系统相关
首页 > 系统相关> > weixueyuan-Nginx日志管理与监控8

weixueyuan-Nginx日志管理与监控8

作者:互联网

https://www.weixueyuan.net/nginx/log/

Nginx访问日志配置

Nginx 的访问日志主要记录用户客户端的请求信息(见下表)。用户的每次请求都会记录在访问日志中,access_log 指令可以设置日志的输出方式及引用的日志格式。

名称访问日志指令
指令 access_log
作用域 http、stream、server、location、if in location、limit except
默认值 logs/access.log combined;
指令值格式 off 或 path[format[buffer=size][gzip[=level]][flush=time][if=condition]];
指令说明 设置访问日志输出方式及引用的日志格式

关于 access_log 指令有以下几点需要说明:

access_log off;

access_log logs/access.log combined;

access_log logs/log.gz combined gzip flush=5m;

map $status $loggable {
    ~^[23]  0;
    default 1;
}

access_log logs/access.log combined if=$loggable;

日志格式指令如下表所示。

名称日志格式指令
指令 log_format
作用域 http、stream
默认值 combined"...";
指令值格式  name[escape=default 或 json 或 none]string...;
指令说明 设置访问日志输出方式及输出日志格式

关于 log_format 指令有以下几点需要说明:

变量名变量说明
$time_iso8601 ISO 8601 时间格式
$time_local 用户请求的时间和时区
$msec 毫秒级别的日志记录时间
$remote_addr 发起与 Nginx 建立连接的网络客户端的 IP,有时会是上层代理服务器的 IP
$http_x_forwarded_for 可以记录客户端 IP,通过代理服务器来记录客户端的 IP
$remote_user 用于记录远程客户端的用户名称
$http_user_agent 用户客户端浏览器标识
$connection 网络连接编号
$connection_requests 当前连接的请求数
$request 用户请求的 URI 及请求方法
$request_method 用户请求方法
$request_uri 用户请求的 URI 及请求方法
$server_protocol 请求协议
$request_time 请求时间
$request_length 请求数据大小
$status 用户请求响应状态码
$bytes_sent 发送到客户端响应数据的大小
$body_bytes_sent 用户请求返回的响应体字节数
$http_referer HTTP 请求头中属性字段 referer

配置样例如下:
# 普通格式日志
log_format  main  '$remote_addr - $connection - $remote_user [$time_local] "$request" - $upstream_addr'
                  '$status  - $body_bytes_sent - $request_time - "$http_referer" '
                  '"$http_user_agent" - "$http_x_forwarded_for" - ';

# JSON格式日志
log_format json '{"@timestamp": "$time_iso8601", '
                '"connection": "$connection", '
                '"remote_addr": "$remote_addr", '
                '"remote_user": "$remote_user", '
                '"request_method": "$request_method", '
                '"request_uri": "$request_uri", '
                '"server_protocol": "$server_protocol", '
                '"status": "$status", '
                '"body_bytes_sent": "$body_bytes_sent", '
                '"http_referer": "$http_referer", '
                '"http_user_agent": "$http_user_agent", '
                '"http_x_forwarded_for": "$http_x_forwarded_for", '
                '"request_time": "$request_time"}';
Nginx TCP/UDP 的访问日志的变量与 HTTP 的访问日志的变量是不同的,TCP/UDP 常见日志变量如下表所示。

变量名变量说明
$time_iso8601 ISO 8601 时间格式
$time_local 用户请求的时间和时区
$connection 网络连接编号
$remote_addr 发起与 Nginx 建立连接的网络客户端的 IP,有时会是上层代理服务器的 IP
$server_addr Nginx 服务器地址
$server_port Nginx 服务器端口
$status 用户请求响应状态码
$upstream_addr 被代理服务器地址
$bytes_received 接收字节数
$bytes_sent 发送字节数
$session_time 连接会话时间
$proxy_protocol_addr 代理协议地址
$proxy_protocol_port 代理协议端口

Nginx 的 TCP/UDP 的日志处理是在连接处理阶段结束时才发生,所以 TCP/UDP 代理的访问日志只在连接关闭时才被记录。访问日志格式配置样例如下:
# 普通格式日志
log_format  tcp  '$remote_addr - $connection - [$time_local] $server_addr: $server_port '
                  '- $status - $upstream_addr - $bytes_received - $bytes_sent - $session_time '
                  '- $proxy_protocol_addr:$proxy_protocol_port ';

# JSON格式日志
log_format json '{"@timestamp": "$time_iso8601", '
                '"connection": "$connection", '
                '"remote_addr": "$remote_addr", '
                '"server_addr": "$server_addr:$server_port" '
                '"status": "$status" '
                '"upstream_addr": "$upstream_addr" '
                '"bytes_received": "$bytes_received" '
                '"bytes_sent": "$bytes_sent" '
                '"session_time": "$session_time" '
                '"proxy_protocol_addr": "$proxy_protocol_addr:$proxy_protocol_port" '}'
打开日志缓存指令见下表。

名称打开日志缓存指令
指令 open_log_file_cache
作用域 http、stream、server、location
默认值 off
指令值格式 off 或 max=N [inactive=time][min_uses=N][valid=time];
指令说明 设置存储日志文件描述符(文件句柄)的缓存

关于 open_log_file_cache 指令有以下几点需要说明:

open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
logs/access.log combined;

Nginx error_log:错误日志配置

Nginx 的错误日志可以帮助用户及时判断 Nginx 配置及运行时出错的原因,错误日志也可以通过 Nginx 内置指令进行配置,但不支持格式定义。配置指令如下表所示。

说明 错误日志指令组成
主指令 error_log
作用域 main、http、mail、stream、server、location
默认值 logs/error.log error;
指令说明 设置错误日志输出方式及输出日志级别

关于 error_log 指令有以下几点需要说明:

error_log syslog:server=192.168.2.109 error;
error_log memory:32m debug;
error_log /dev/null;

# 访问文件不存在时,记入错误日志
log_not_found on;

指令值中第二个参数是输出日志的级别,指定的级别将包含自身及级别值比其小的所有级别日志,日志内容会保存到第一个参数设定的输出位置。

错误日志级别及相关说明如下表所示。

级别级别值级别说明
debug 8 代码中标记为 NGX_LOG_DEBUG 的输出,输出最为详细,配合调试使用
info 7 代码中标记为 NGX_LOG_INFO 的输出,因包括除 debug 级别的所有输出,故同样会消耗大量磁盘 IO 资源
notice 6 代码中标记为 NGX_LOG_NOTICE 的输出
warn  5 代码中标记为 NGX_LOG_WARN 的输出
error 4 代码中标记为 NGX_LOG_ERROR 的输出,实际生产环境中常用的输出级别
crit 3 代码中标记为 NGX_LOG_CRIT 的输出
alert 2 代码中标记为 NGX_LOG_ALERT 的输出
emerg 1 代码中标记为 NGX_LOG_EMERG 的输出

Nginx Logrotate:日志归档

Nginx 日志存储为文件时,同一 access_log 指令设置的日志文件是以单文件形式存储的,在日常使用中为方便维护,通常需要将日志文件按日期进行归档。虽然 Nginx 本身并没有这一功能,但实现日志归档的方法仍有很多,此处推荐使用 Logrotate 实现日志归档管理。

Logrotate 是 CentOS 操作系统内置日志管理工具,该工具可对系统中生成的大量日志文件进行归档管理,其允许对日志文件实行压缩、删除或邮寄等操作。Logrotate 可以按照每天、周、月或达到某一大小的日志文件进行归档操作,Logrotate 基于 anacrontab 实现计划任务,只需在 /etc/logrotate.d 目录下编写相关日志管理配置文件,就可以无须人工干预使用自动化方式完成日志归档操作。

1) Logrotate 安装

yum -y install logrotate

2) Logrotate 文件目录

/etc/logrotate.conf                     # logrotate主配置文件
/usr/sbin/logrotate                     # logrotate二进制文件
/etc/logrotate.d/                       # 自定义logrotate配置文件
/var/lib/logrotate/logrotate.status     # logrotate管理日志执行记录的状态文件

3) Logrotate 命令参数

    -d, --debug                             # 测试归档配置文件
    -f, --force                             # 立即执行归档操作
    -m, --mail=command                      # 指定发送邮件的命令(默认为'/bin/mail')
    -s, --state=statefile                   # 设置logrotate.status文件路径,可用于区分在同
                                                # 一系统下以不同用户身份运行的logrotate任务
    -v, --verbose                           # 显示配置详细信息
    -l, --log=STRING                        # 将Logrotate执行的详情输出到指定的文件

logrotate -v /etc/logrotate.conf                # 显示配置文件详细信息
logrotate -d /etc/logrotate.d/syslog -l /var/log/logrotate.log  # 配置文件,执行测试
logrotate -f /etc/logrotate.d/syslog    # 立即执行当前配置文件

4) Logrotate 配置指令

Logrotate 配置指令如下表所示。

指令指令说明
归档执行周期
hourly 日志归档周期为 1 小时,默认 Logrotate 的最小周期为 1 天,需额外调整该参数才可生效
daily 日志归档周期为 1 天
weekly 日志归档周期为 1 周
monthly 日志归档周期为 1 月,通常为每月的第一天
归档执行条件
include 读取外部参数文件
missingok 如果日志文件不存在,则不显示错误信息
nomissingok 如果日志文件不存在,则显示错误信息。默认配置
size 日志文件可被归档的最小值
minsize 日志文件可被归档的最小值,没到归档周期执行时间,不会执行归档操作
maxsize 日志文件超过设定值时,即使没到归档周期执行时间,也会执行归档操作
ifempty 即使日志文件为空,也执行归档操作
notifempty 如果日志文件为空,则不进行归档。默认设置
tabooext 不对设置扩展名的日志文件执行归档操作
归档文件命名
start count 使用日志文件归档次数作为归档文件扩展名,count 默认值为 1,默认配置
dateext 为归档文件名添加日期,默认追加到扩展名后
dateformat 设置归档文件名中的日期格式,使用“%Y%m%d%H”作为说明符,默认为-%Y%m%d
dateyesterday 使用前一天的日期而非创建归档文件时的日期作为归档文件的文件名中的日期
extension 指定日志的扩展名,并将其设置为归档文件的扩展名,启用压缩时,压缩的扩展名在最后
compressext 启用压缩时,自定义归档文件扩展名,如将“.gz”改为“.ddd”
归档文件保存方式
compress 对归档文件启用压缩,默认为 gzip 压缩
nocompress 不压缩归档文件。默认设置
compresscmd 指定压缩归档文件的命令,默认为 gzip 压缩
uncompresscmd 指定解压归档文件的命令,默认为 gunzip 解压
compressoptions 启用压缩时,设置压缩工具的命令选项
delaycompress 在下一个归档周期再对当前归档文件进行压缩
nodelaycompress 不延迟压缩。默认设置
归档执行方式
copy 为日志文件复制一个副本后再进行归档
nocopy 不复制源日志文件。默认配置
copytruncate 复制日志文件后清空日志文件的内容
nocopytruncate 复制源日志文件后,不清空源文件。默认设置
create mode owner group, create owner group 重命名日志文件,创建与日志文件同名的文件,默认 mode=0644 uid=0 gid=0,与 copy 指令不能同时使用
nocreate 不创建与日志文件同名的文件。默认设置
olddir 设置归档文件保存目录
noolddir 归档文件与源文件在同一目录。默认设置
createolddir mode owner group 如果 olddir 参数指定的目录不存在,则创建目录并指定属组,默认 mode = 0777 uid = 0 gid = 0
nocreateolddir 当 olddir 参数设定目录不存在时,不创建目录。默认设置
prerotate ... endscript 归档执行之前执行脚本,日志文件名为传入的第一个参数
postrotate ... endscript 归档执行之后执行脚本,日志文件名为传入的第一个参数
firstaction ... endscript prerotate 脚本之前,仅当第一个日志文件被开始执行归档操作时才执行脚本,日志文件名为传入的第一个参数
lastaction ... endscript postrotate 脚本之后,仅当最后一个日志文件执行归档操作结束时才执行脚本,日志文件名为传入的第一个参数
preremove ... endscript 删除日志文件之前执行脚本,日志文件名为传入的第一个参数
sharedscripts 当匹配的日志文件为多个时,prerotate 和 postrotate 脚本会在每个日志文件执行归档操作时都执行一次,启用共享模式会让 prerotate 和 postrotate 脚本在全局只运行一次
nosharedscripts 当匹配的日志文件为多个时,prerotate 和 postrotate 脚本会在每个日志文件执行归档操作时都执行一次。默认设置
su user group 指定操作源文件执行归档操作的用户及属组
归档文件清理
mail 设置接收归档文件的邮件地址
nomail 不将归档文件发送到任何邮件地址
mailfirst 将刚生成的归档文件发送到设置的邮箱
maillast 将要超过 maxage 设置时间的归档文件发送到设置的邮箱
mахage 设置过期归档文件的天数
rotate 保留归档文件数,默认为 0
shred 彻底删除
shredcycles count 彻底删除时,覆盖文件的次数,默认为 3
noshred 不彻底删除

关于上表有以下几点需要说明:

5) Logrotate 管理 Nginx 日志

根据 Logrotate 的功能特点,建议选择 create 方式进行日志归档管理,配置样例如下:
vi /etc/logrotate.d/nginx
/usr/local/nginx/logs/*.log {
    daily                                   # 日志归档周期为1天
    size 1                                  # 日志文件最小为1字节时才执行归档
    minsize 1                               # 日志文件最小为1字节时才执行归档
    notifempty                              # 日志文件不为空时才执行归档
    dateext                                 # 归档文件名添加时间字符串
    dateformat -%Y%m%d%H                    # 归档文件名时间字符串格式为-%Y%m%d%H
    dateyesterday                           # 归档文件名时间字符串以归档操作的前一天为时间戳
    extension .log                          # 归档文件名中保留日志的扩展名
    compress                                # 归档文件执行压缩
    delaycompress                           # 在归档执行的下个周期再进行压缩
    create                                  # 以创建新文件方式实现日志归档
    olddir /data/backup/nginx_logs          # 归档文件存储目录
    createolddir                            # 归档文件存储目录不存在时自动创建
    postrotate                              # 归档执行后执行脚本
        /usr/local/nginx/sbin/nginx -s reopen -g "pid /run/nginx.pid;"
                                                # 通知Nginx重新打开日志文件
    endscript
    sharedscripts                           # 启用脚本共享模式
    maxage 7                                # 归档文件最多保留7天
    rotate 7                                # 归档文件最多保留7份
}

Nginx日志分析工具(ELK)配置

Nginx 的访问日志中可以记录用户的 IP、访问方法、访问 URI、响应状态及响应数据大小等 HTTP 请求处理中会涉及的各种信息,通过这些信息可以实现访问用户来源分布、用户请求 URI 排行、响应数据大小及并发连接的分析和统计。

1、ELK 简介

ELK(Elasticsearch、Logstash、Kibana)是开源的实时日志收集分析解决方案。ELK 访问逻辑如下图所示,是由 Elasticsearch、Logstash、Kibana 这三款软件和数据采集客户端(如 Filebeat)等实现日志采集、储存、搜索分析等操作。

ELK 访问逻辑
图:ELK 访问逻辑
1) Elasticsearch 是一款用 Java 语言开发的,基于 Lucene 的开源搜索引擎,它提供了分布式多用户的全文搜索、分析、存储能力。Elasticsearch 的常见关键词如下表所示。

关键词名称关键词说明
cluster 集群 集群由一个主节点和多个从节点组成,主节点是通过内部选举产生的。Elastic-search 集群是一个去中心化的分布式架构,对于外部用户来讲,Elasticsearch 集群是个整体,与其中任何一个节点通信获取内容都是一致的
index 索引 Elasticsearch 是面向文档的数据库,一条数据就是一个文档,文档内容为包含多个 key,value 格式字段数据。Elasticsearch 集群可以包括多个索引,每个索引下包含多个类型,每个类型下包含多个文档。索引相当于关系型数据库中的库,类型相当于关系型数据库中的表
shards 索引分片 Elasticsearch 可以把一个完整的索引分成多个分片,该方式可以把一个大的索引拆分成多个,并分布到不同的节点,实现分布式搜索
replicas 索引副本 Elasticsearch 可以为索引设置多个副本,当集群中某个节点或某个索引的分片损坏或丢失时,可以通过副本进行恢复,同时可以为搜索请求提供负载均衡,以提高查询效率
recovery 数据分配与恢复 Elasticsearch 集群在有节点加入或退出时,会根据节点的数量变化对索引分片进行重新分配,当挂掉的节点重启后也会进行数据分配与恢复
gateway 存储方式 Elasticsearch 存储方式,Elasticsearch 会先把索引存放到内存中,当内存满了时再持久化到 gateway 配置的目标存储中。默认 gateway 配置为本地硬盘,也支持其他分布式文件系统,如 Hadoop 的 HDFS 和 Amazon 的 s3 云存储服务等

2) Logstash 是基于 C/S 架构,对日志进行收集、过滤、转发的日志收集引擎,它可以同时从多个源获取数据,动态地将客户端采集的数据进行分拣、过滤,并转发到不同存储服务器。

Logstash 是以 pipeline 方式处理每条日志信息的,在每个 pipeline 中都有输入(INPUTS)、过滤(FILTERS)、输出(OUTPUTS)3 个处理动作。每个处理动作可由一个或多个插件实现复杂的功能。输入处理是获取日志数据;过滤处理可以对日志进行分拣、修改;输出处理则是将日志数据发送给目标存储服务器。

Logstash 工作原理如下图所示。

Logstash 原理
图:Logstash 原理
3) Kibana 是 Elasticsearch 的 Web 管理工具,它提供了友好的界面化操作方式和统计分析的 Dashboard 工具,让使用者只需简单点击就可完成基本的数据搜索、分析等工作。

4) Filebeat 隶属于 Beats 工具包,是负责文件数据采集的客户端工具。Filebeat 由 pro-spector 和 harvester 两个主要组件组成。prospector 目前只支持 log 文件和 stdin 两个输入类型,是 harvester 的管理进程,负责按照配置参数 paths 的内容查找日志文件,并为每个日志文件分配一个 harvester。

harvester 负责实时读取单个日志文件,harvester 将日志内容发送给底层的 libbeat,libbeat 将日志数据发送给配置文件中指定的输出目标。Filebeat 工作原理如下图所示。

Filebeat 原理
图:Filebeat 原理

2、ELK 安装

ELK 支持多种安装方式,鉴于 Docker 化部署的便捷性,本小节以基于 docker-compose 脚本的 Docker 化来部署 ELK 环境,部署示意如下图所示。

ELK 部署示意
图:ELK 部署示意

1) 初始化系统环境

首先要初始化系统环境并安装 Docker 应用。
# 安装yum工具
yum install -y yum-utils
# 安装Docker官方yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装docker及docker-compose应用
yum install -y docker-ce docker-compose
# 设置docker服务开机自启动
systemctl enable docker
# 启动docker服务
systemctl start docker

# 优化内核参数,设置一个进程拥有VMA(虚拟内存区域)的最大数量为262144
sysctl -w vm.max_map_count=262144

2) 编写 docker-compose 文件

使用 docker-compose 工具进行 ELK 容器运行编排。docker-compose 文件如下:
cat elk.yaml

version: '2'
services:
    elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:7.0.1
        container_name: elasticsearch701
        environment:
            - discovery.type=single-node
            - bootstrap.memory_lock=true
            - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
        ulimits:
            memlock:
                soft: -1
            hard: -1
        hostname: elasticsearch
        restart: always
        ports:
            - "9200:9200"
            - "9300:9300"
    kibana:
        image: docker.elastic.co/kibana/kibana:7.0.1
        container_name: kibana701
        hostname: kibana
        depends_on:
            - elasticsearch
        restart: always
        ports:
            - "5601:5601"
    logstash:
        image: docker.elastic.co/logstash/logstash:7.0.1
        container_name: logstash701
        hostname: logstash
        restart: always
        depends_on:
            - elasticsearch
        ports:
            - "5044:5044"

# 运行ELK容器
docker-compose -felk.yaml up -d
docker-compose 是功能非常强的容器运行编排工具,内部含有很多配置指令可以完成容器的资源配置、运行、服务依赖、网络配置等运行时的编排配置,具体指令说明可参照 docker-compose 的官方文档。

3) 数据持久化

Docker 的镜像(Image)文件存放在一个只读层,而容器(Container)的文件则是存放在可写层,当容器删除或重建时,该容器运行时变更的文件将会丢失,所以需要通过外挂卷的方式将变更的配置和文件保存到主机系统中。ELK 容器有 Elasticsearch、Logstash 和 Kibana 3 个容器,这 3 个容器都需要实现数据持久化。
cd /opt/data/apps
# 创建容器外挂卷目录及数据存储目录
mkdir -p {elasticsearch/data,elasticsearch/config,elasticsearch/modules,elastic-search/plugins,kibana/config,logstash/pipeline,logstash/config}

# 复制容器数据到数据存储目录
docker cp elasticsearch701:/usr/share/elasticsearch/data elasticsearch
docker cp elasticsearch701:/usr/share/elasticsearch/config elasticsearch
docker cp elasticsearch701:/usr/share/elasticsearch/modules elasticsearch
docker cp elasticsearch701:/usr/share/elasticsearch/plugins elasticsearch
docker cp logstash701:/usr/share/logstash/config logstash
docker cp logstash701:/usr/share/logstash/pipeline logstash
docker cp kibana701:/usr/share/kibana/config kibana

# Logstash配置

cat>logstash/pipeline/logstash.conf<<EOF
input {
    beats {
        port => 5044
        codec =>"json"
    }
}
output {
    elasticsearch {
        hosts => ["http://10.10.4.37:9200"]
        index => "logstash-nginx-%{[@metadata][version]}-%{+YYYY.MM.dd}"
    }
}
EOF

# 配置目录权限
chown -R 1000:1000 elasticsearch/*
chown -R 1000:1000 logstash/*

# 配置docker-compose脚本,挂载数据存储目录

cat elk.yaml

version: '2'
services:
    elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:7.0.1
        container_name: elasticsearch701
        environment:
            - discovery.type=single-node
            - bootstrap.memory_lock=true
            - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
        ulimits:
            memlock:
                soft: -1
                hard: -1
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - /etc/timezone:/etc/timezone:ro
            - /opt/data/apps/elasticsearch/modules:/usr/share/elasticsearch/modules
            - /opt/data/apps/elasticsearch/plugins:/usr/share/elasticsearch/plugins
            - /opt/data/apps/elasticsearch/data:/usr/share/elasticsearch/data
            - /opt/data/apps/elasticsearch/config:/usr/share/elasticsearch/config
        hostname: elasticsearch
        restart: always
        ports:
            - "9200:9200"
            - "9300:9300"
    kibana:
        image: docker.elastic.co/kibana/kibana:7.0.1
        container_name: kibana701
        hostname: kibana
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - /etc/timezone:/etc/timezone:ro
            - /opt/data/apps/kibana/config:/usr/share/kibana/config
        depends_on:
            - elasticsearch
        restart: always
        ports:
            - "5601:5601"
    logstash:
        image: docker.elastic.co/logstash/logstash:7.0.1
        container_name: logstash701
        hostname: logstash
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - /etc/timezone:/etc/timezone:ro
            - /opt/data/apps/logstash/pipeline:/usr/share/logstash/pipeline
            - /opt/data/apps/logstash/config:/usr/share/logstash/config
        restart: always
        depends_on:
            - elasticsearch
        ports:
            - "5044:5044"

# 运行ELK容器

docker-compose -f elk.yaml up -d

4) Nginx 配置

在运行 Nginx 的主机上把 Nginx 日志定义为 json 格式,编辑 nginx.conf 文件并在 http 指令域添加如下指令:
log_format json '{"@timestamp": "$time_iso8601", '
                '"connection": "$connection", '
                '"remote_addr": "$remote_addr", '
                '"remote_user": "$remote_user", '
                '"request_method": "$request_method", '
                '"request_uri": "$request_uri", '
                '"server_protocol": "$server_protocol", '
                '"status": "$status", '
                '"body_bytes_sent": "$body_bytes_sent", '
                '"http_referer": "$http_referer", '
                '"http_user_agent": "$http_user_agent", '
                '"http_x_forwarded_for": "$http_x_forwarded_for", '
                '"request_time": "$request_time"}';

5) Filebeat 安装

在 Nginx 服务器安装 Filebeat 进行 Nginx 日志采集。
# 安装Filebeat
rpm -ivh https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.0.1 -x86_64.rpm

# 设置输出数据到Logstash及Logstash地址
sed -i "s/#output.logstash:/output.logstash:/g" /etc/filebeat/filebeat.yml
sed -i "s/#hosts: \[\"localhost:5044\"\]/  hosts: \[\"10\.10\.4\.37:5044\"\]/g" /etc/filebeat/filebeat.yml

# 关闭直接输出数据到Elasticsearch
sed -i "s/output.elasticsearch/#output.elasticsearch/g" /etc/filebeat/filebeat.yml
sed -i "s/hosts: \[\"localhost:9200\"\]/#hosts: \[\"localhost:9200\"\]/g" /etc/filebeat/filebeat.yml

# 安装Filebeat Nginx模块
filebeat modules enable nginx

# 配置Filebeat Nginx模块
cat >/etc/filebeat/modules.d/nginx.yml<<EOF
- module: nginx
    access:
        enabled: true
        var.paths: ["/usr/local/nginx/logs/*access.log"]
    error:
        enabled: true
        var.paths: ["/usr/local/nginx/logs/*error.log"]
EOF

# 检查配置
filebeat test config
filebeat test output

# 启动Filebeat
systemctl restart filebeat

# 设置为自启动
systemctl enable filebeat

6) Kibana 展示

在浏览器中打开 http://10.10.4.37:5601,在右侧菜单栏中选择 management → index_patterns → Create index pattern,然后输入 logstash-nginx-*,接着点击Next Step添加Nginx日志索引。在左侧菜单栏中点击Discover选择logstash-nginx-就可以实时查看Nginx输出的访问或错误日志了。

Nginx监控工具(Prometheus)配置

Nginx 的 ngx_http_stub_status_module 模块及第三方的主机状态监控模块都提供了自身状态数据的统计和输出功能,但作为监控管理,仍需要进一步实现对各种状态数据的收集、存储、统计展示、阈值报警等工作。为实现监控管理的完整性,需要使用更专业的监控工具来实现后续的工作。

1、Prometheus简介

Prometheus 是由 SoundCloud 开源的监控告警解决方案,其在 GitHub 上的 Star 数已经超过 3.1 万,已成为很多大公司首选的监控解决方案。Prometheus 由 Prometheus Server、PushGateway、Alertmanager、Exporter 等 4 个组件共同组成。

其中,Exporter 可以由用户自行开发,只需输出符合 Prometheus 的规范数据即可;Prometheus Server 提供了 api 接口并支持自定义的 PromQL 查询语言对外实现监控数据查询输出,结合 Grafana 强大的图形模板功能,可以非常直观地以监控数据统计图表的形式进行展示。Prometheus 结构如下图所示。

Prometheus结构
图:Prometheus 结构
关于上图有以下几点需要说明。

2、Prometheus部署

Prometheus 支持多种方式部署,鉴于 Docker 化部署的便捷性,此处选择基于 docker-compose 脚本部署 Docker 化的 Prometheus 环境,部署示意如下图所示。

Prometheus 部署
图:Prometheus 部署
在服务器 10.10.4.38 上部署 Prometheus 的基础服务和 Grafana 服务;在服务器 10.10.4.39 上部署 Prometheus 的推送网关服务和 Prometheus 的告警服务。

1) 安装Prometheus和Grafana

在服务器 10.10.4.38 上初始化 Prometheus 和 Grafana 的 docker-compose 脚本。
cat>prometheus.yaml<<EOF
version: '3.5'
services:
    prometheus:
        hostname: prometheus
        container_name: prometheus
        restart: always
        image: prom/prometheus
        ports:
            - "9090:9090"
        stop_grace_period: 1m
    grafana:
        hostname: grafana
        container_name: grafana
        restart: always
        image: grafana/grafana
        ports:
            - "3000:3000"
        stop_grace_period: 1m
EOF

# 启动镜像
docker-compose -f prometheus.yaml up -d

2) 配置Prometheus

配置 Prometheus 并持久化 Prometheus 及 Grafana 数据。
cd /opt/data/apps
mkdir -p {prometheus,grafana}

# 复制配置文件
docker cp prometheus:/etc/prometheus prometheus/prometheus

# 复制监控数据文件
docker cp prometheus:/prometheus prometheus/prometheus_data

# 配置Alertmanager服务器地址
sed -i "s/# - alertmanager:9093/ - 10.10.4.39:9093/g" prometheus/prometheus/prometheus.yml

# 配置告警规则文件目录
sed -i "/rule_files:/a\  - /etc/prometheus/*.rules" prometheus/prometheus/prometheus.yml

# 配置PushGateway地址
cat>>prometheus/prometheus/prometheus.yml<<EOF

    - job_name: pushgateway                 # 监控job名称,全局唯一
      static_configs:
        - targets: ['10.10.4.39:9091']      # 被监控主机的IP及Exporter的端口
          labels:
            instance: pushgateway           # 被监控主机的标识,多为主机名或docker实例名称
EOF

# 设置目录权限
chown -R 65534:65534 prometheus/*

# 复制Grafana配置文件
docker cp grafana:/etc/grafana grafana/config
# 复制Grafana数据文件
docker cp grafana:/var/lib/grafana grafana/data

# 设置目录权限
chown -R 472:472 grafana/*

# 修改docker-compose脚本
cat>prometheus.yaml<<EOF
version: '3.5'
services:
    prometheus:
        hostname: prometheus
        container_name: prometheus
        restart: always
        image: prom/prometheus
        ports:
            - "9090:9090"
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - /opt/data/apps/prometheus/prometheus:/etc/prometheus
            - /opt/data/apps/prometheus/prometheus_data:/prometheus
        stop_grace_period: 1m
    grafana:
        hostname: grafana
        container_name: grafana
        restart: always
        image: grafana/grafana
        ports:
            - "3000:3000"
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - /opt/data/apps/grafana/config:/etc/grafana
            - /opt/data/apps/grafana/data:/var/lib/grafana
        stop_grace_period: 1m
EOF

# 重建并运行镜像
docker-compose -f prometheus.yaml up -d
通过浏览器访问 http://10.10.4.38:9090/targets,就可以看到 Prometheus 和 PushGateway 这两个 Endpoint。然后通过浏览器访问 Grafana Web 管理页面 http://10.10.4.38:3000,初始用户名和密码都是 admin。

3) 安装Alertmanager和PushGateway

在服务器 10.10.4.39 上初始化 Alertmanager 和 PushGateway 的 docker-compose 脚本。
cat>prometheus.yaml<<EOF
version: '3.5'
services:
    alertmanager:
        hostname: alertmanager
        container_name: alertmanager
        restart: always
        image: prom/alertmanager
        ports:
            - "9093:9093"
        stop_grace_period: 1m
    pushgateway:
        hostname: pushgateway
        container_name: pushgateway
        restart: always
        image: prom/pushgateway
        ports:
            - "9091:9091"
        stop_grace_period: 1m
EOF

# 运行镜像
docker-compose -f prometheus.yaml up -d

4) 配置Alertmanager

配置 Alertmanager 并持久化 Alertmanager 及 PushGateway 数据。
cd /opt/data/apps
mkdir -p prometheus

# 复制Alertmanager配置文件
docker cp alertmanager:/etc/alertmanager prometheus/alertmanager
# 复制Alertmanager数据文件
docker cp alertmanager:/alertmanager prometheus/alertmanager_data

# 配置目录权限
chown -R 65534:65534 prometheus/alertmanager
chown -R 65534:65534 prometheus/alertmanager_data

# 配置prometheus.yaml
cat>prometheus.yaml<<EOF
version: '3.5'
services:
    alertmanager:
        hostname: alertmanager
        container_name: alertmanager
        restart: always
        image: prom/alertmanager
        ports:
            - "9093:9093"
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - /opt/data/apps/prometheus/alertmanager:/etc/alertmanager
            - /opt/data/apps/prometheus/alertmanager_data:/alertmanager
        stop_grace_period: 1m
    pushgateway:
        hostname: pushgateway
        container_name: pushgateway
        restart: always
        image: prom/pushgateway
        ports:
            - "9091:9091"
        volumes:
            - /etc/localtime:/etc/localtime:ro
EOF

# 重建并运行镜像
docker-compose -f prometheus.yaml up -d
通过浏览器访问 http://10.10.4.39:9093,可以查看 Alertmanager 的告警信息及配置;通过浏览器访问 http://10.10.4.39:9091,可以查看 PushGateway 的相关信息。

3、监控HTTP主机状态

Prometheus 针对被监控主机,是通过轮询 Exporter 接口的形式获取监控数据的,nginx-module-vts 模块虽然也提供 Prometheus 数据格式输出,但数据并不详细,推荐使用 nginx-vts-exporter 实现 Prometheus 数据输出。nginx-vts-exporter 是由Go语言开发的,不仅提供了针对信息的监控数据,还提供了配套的 Grafana 模板。

1) 在Nginx服务器上安装nginx-vts-exporter

# 获取nginx-vts-exporter二进制文件
wget https://github.com/hnlq715/nginx-vts-exporter/releases/download/v0.10.3/nginx-vts-exporter-0.10.3.linux-amd64.tar.gz
tar zxmf nginx-vts-exporter-0.10.3.linux-amd64.tar.gz
cp nginx-vts-exporter-0.10.3.linux-amd64/nginx-vts-exporter /usr/local/nginx/sbin/

# 运行测试
nginx-vts-exporter -nginx.scrape_timeout 10 -nginx.scrape_uri http://127.0.0.1: 8080/vts/format/json

curl http://127.0.0.1:9913/metrics

2) 将nginx-vts-exporter配置为进程服务

# 安装supervisor
yum install supervisor

# 配置nginx-vts-exporter服务管理配置
cat>/etc/supervisord.d/nginx-vts-exporter.ini<<EOF
[program:nginx-vts-exporter]
;配置进程运行命令
command=/usr/local/nginx/sbin/nginx-vts-exporter -nginx.scrape_timeout 10 -nginx.scrape_uri http://127.0.0.1:8080/vts/format/json
directory=/usr/local/nginx/sbin     ;进程运行目录
startsecs=5                         ;启动5秒后没有异常退出表示进程正常启动,默认为1秒
autostart=true                      ;在supervisord启动的时候也自动启动
autorestart=true                    ;程序退出后自动重启
EOF

# 启动supervisord并配置为开机运行
systemctl start supervisord
systemctl enable supervisord

# nginx-vts-exporter进程服务管理
# 查看nginx-vts-exporter进程服务状态
supervisorctl status nginx-vts-exporter

# 重启nginx-vts-exporter进程服务
supervisorctl restart nginx-vts-exporter

# 启动nginx-vts-exporter进程服务
supervisorctl start nginx-vts-exporter

# 停止nginx-vts-exporter进程服务
supervisorctl stop nginx-vts-exporter

# 访问测试
curl http://10.10.4.8:9913/metrics

3) 在Prometheus上配置监控job

cd /opt/data/apps
cat>>prometheus/prometheus/prometheus.yml<<EOF
    # nginx-vts-exporter job
    - job_name: nginx_exporter
        static_configs:
        - targets: ['10.10.4.8:9913']
            labels:
                instance: nginx-1
EOF

docker restart prometheus

4) 导入Grafana模板实现图表化展示

登录 Grafana 后,在左侧菜单点击 Configuration→Add data source,选择 Prometheus 图标后进入数据源配置页面,配置如下图所示。

Grafana 数据源配置
图:Grafana 数据源配置
在左侧菜单点击Create→Import,在标题为Grafana.com Dashboard的输入框输入模板ID 2949后,点击任意位置进入模板导入页,如下图所示。

Grafana模板导入
图:Grafana模板导入

4、监控TCP/UDP主机状态

TCP/UDP 主机状态模块 nginx-module-sts 虽然也提供了 Prometheus 格式数据输出,但仍然不够详细,同时也没有可用的开源 Exporter。为实现 Nginx TCP/UDP 主机状态数据的采集,可以按照 Prometheus 的数据规范编写一个 Exporter。

1) Prometheus的数据类型

2) Exporter数据输出格式

Exporter 输出的数据是以 Metric 行为单位的文本数据,数据输出格式规范如下。

类型声明与注释行间的文本为 Metric 数据,每行结构如下图所示。

Metric 数据行结构
图:Metric 数据行结构

3) 编写Exporter脚本

Python 下的 prometheus_client 模块可以实现 Prometheus Exporter 的快速开发,因 Prome-theus 是采用拉取方式获取监控数据的,所以还需要用 flask 实现 Web 框架和访问路由功能。脚本代码如下:
import prometheus_client
from prometheus_client import Counter,Gauge
import requests
import sys
import json
import time
from flask import Response, Flask

# 初始化监控项
nginx_info = Gauge("nginx_info", "nginx_info nginx info",['hostName','nginxVersion'])
nginx_server_info = Gauge("nginx_server_info", "nginx_server_info nginx server info",['host','port','protocol'])
nginx_server_connections = Gauge("nginx_server_connections", "nginx connections", ['status'])
nginx_server_bytes = Counter("nginx_server_bytes","request/response bytes", ['direction','host'])
nginx_upstream_responses = Counter("nginx_upstream_requests","requests counter", ['backend','code','upstream'])

app = Flask(__name__)

@app.route("/metrics")
def requests_metrics():
    metrics=""
    url = "http://127.0.0.1:8080/sts/format/json"
    res = requests.get(url)
    all_data = json.loads(json.dumps(res.json()))

    # server_info
    nginx_info.labels(hostName=all_data["hostName"],nginxVersion=all_data["nginx-Version"]).set(time.time())
    metrics+=prometheus_client.generate_latest(nginx_info)

    # connections
    connections=["accepted","active","handled","reading","requests","waiting", "writing"]
    for con in connections:
        nginx_server_connections.labels(status=con).set(all_data["connections"][con])
    metrics+=prometheus_client.generate_latest(nginx_server_connections)

    # streamServerZones
    for k,streamServer in all_data["streamServerZones"].items():
        nginx_server_bytes.labels(direction="in",host=k).inc(streamServer["inBytes"])
        nginx_server_bytes.labels(direction="out",host=k).inc(streamServer["outBytes"])
        nginx_server_info.labels(host=k,port=streamServer["port"],protocol=stream-Server["protocol"]).set(1)

    metrics+=prometheus_client.generate_latest(nginx_server_bytes)
    metrics+=prometheus_client.generate_latest(nginx_server_info)

    # streamUpstreamZones
    status_code=["1xx","2xx","3xx","4xx","5xx"]
    for ups,stream in all_data["streamUpstreamZones"].items():
        for v in stream:
            for code in status_code:
                nginx_upstream_responses.labels(backend=v["server"],code=code,up-stream=ups).inc(v["responses"][code])

    metrics+=prometheus_client.generate_latest(nginx_upstream_responses)

    return Response(metrics,mimetype="text/plain")

@app.route('/')
def index():
    html='''<html>
            <head><title>Nginx sts Exporter</title></head>
            <body>
            <h1>Nginx sts Exporter</h1>
            <p><a href="/metrics">Metrics</a></p>
            </body>
            </html>'''
    return html

if __name__ == "__main__":
    app.run(
        host="0.0.0.0",
        port= 9912,
        debug=True
        )
在此处只选了几个监控项做样例,感兴趣的读者可继续补充完整。

4) Exporter脚本部署

将 Exporter 脚本保存为 /usr/local/nginx/sbin/nginx-sts-exporter.py。

# 配置运行环境
yum install python2-pip
pip install prometheus_client requests flask

# 运行Exporter
python /usr/local/nginx/sbin/nginx-sts-exporter.py

# 测试
curl http://127.0.0.1:9912/metrics

5) 在 Prometheus 上配置监控 job

具体配置样例如下:
cd /opt/data/apps
cat>>prometheus/prometheus/prometheus.yml<<EOF
    # nginx-vts-exporter && nginx-sts-exporter job
    - job_name: nginx_exporter_8
        static_configs:
        - targets: ['10.10.4.8:9913','10.10.4.8:9912']
          labels:
            instance: nginx-8
EOF

# 重启Prometheus,使配置生效
docker restart prometheus

5、Prometheus监控告警

Prometheus 监控告警是通过 Alertmanager 组件实现的。Alertmanager 提供标准的 RESTful api 接口接收警报信息,其将告警信息按照规则重定向给接收者,接收者可以是邮箱、webhook 和微信等。Alertmanager 会对已发送的告警进行智能记录并做延时、去重等处理,从而有效避免告警风暴的产生。

1) Prometheus监控告警处理流程如下:

2) 告警规则格式

ALERT <alert name>            # 告警标识符,可以不唯一
  IF <expression>             # 触发告警阈值规则
  [ FOR <duration> ]          # 触发告警通知的持续时间
  [ LABELS <label set> ]      # 分组标签,用以Alertmanager进行分拣路由
  [ ANNOTATIONS <label set> ] # 告警描述信息

3) Prometheus Server配置告警规则格式

cat>prometheus/prometheus/nginx.rules<<EOF
groups:
- name: NginxAlert # 规则组名称
  rules:
    - alert: ResponseTimeAlert      # 规则的名称
      # 告警阈值计算规则为响应时间大于1000ms并持续10s的发送告警
      expr: (nginx_upstream_responseMsec > 1000)
      for: 10s                      # 持续时间为10s
      labels:                       # 定义告警路由标签
            severity: critical
            service: nginx
        annotations:                # 告警信息
            summary: “Nginx响应大于1000ms”
            description: “Nginx {{ $labels.instance }}后端集群{{ $labels.upstream }} 中{{ $labels.backend }}的响应时间大于1000ms。当前值为:{{ $value }} ms”
EOF

# 重启Prometheus
docker restart prometheus
其中,$labels 是 Metric 行数据的 labels 内容。labels 的内容可用对象数据类型方法引用;$value 是 Metric 行的 value;$labels 是多条时,会自动遍历内容,每条记录生成一个 annotations 信息。

4) Alertmanager配置

cd /opt/data/apps

# 配置Alertmanager
cat>prometheus/alertmanager/alertmanager.yml<<EOF
# 全局配置,配置smtp信息
global:
    resolve_timeout: 5m                             # 处理超时时间,默认为5min
    smtp_smarthost: 'smtp.exmail.qq.com:465'        # 邮箱smtp服务器代理,请替换自己的smtp
                                                        # 服务器地址
    smtp_from: 'monitor@nginxbar.org'               # 发送告警信息的邮箱地址,请替换自己的
                                                        # 邮箱地址
    smtp_auth_username: 'monitor@nginxbar.org'      # 邮箱账号,请替换自己的邮箱账号
    smtp_auth_password: '12345678'                  # 邮箱密码,请替换自己的邮箱密码
    smtp_require_tls: false

# 定义发送邮件的模板信息
templates:
    - 'template/*.tmpl'

# 定义发送告警邮件的路由信息,这个路由不仅可以接收所有的告警,还可以配置多个路由
route:
    group_by: ['alertname']                 # 告警信息分组依据,按照同类alertname
                                                        # 进行分组
    group_wait: 10s                                 # 最初等待10s发送告警通知
    group_interval: 60s                             # 在发送新告警前的等待时间
    repeat_interval: 1h                             # 发送重复告警的等待周期为1小时,避免产
                                                        # 生邮件风暴
    receiver: 'email'                       # 全局默认告警接收者的名称,与receivers
                                                        # 的name对应
    routes:
    - match:                                # 匹配labels存在如下标签的告警信息
            severity: critical
            service: nginx
        receiver: nginx_email                       #Nginx服务器警报接收者的名称

# 定义默认警报接收者信息
receivers:
    - name: 'email'                                 # 路由中对应的receiver名称
      email_configs:                                # 告警接收者邮箱配置
        - to: 'xiaodong.wang@freemud.com'           # 告警接收者的邮箱配置

    - name: 'nginx_email'                           # 路由中对应的receiver名称
      email_configs:                                # 告警接收者邮箱配置
        - to: 'xiaodong.wang@freemud.com'           # 告警接收者的邮箱配置

EOF

# 重启alertmanager
docker restart alertmanager
Nginx 监控项的阈值触发设置的告警规则时,Prometheus 就会自动发送告警到目标邮箱。

 

标签:文件,weixueyuan,nginx,Prometheus,Nginx,prometheus,归档,日志
来源: https://www.cnblogs.com/hanease/p/16194773.html