Nginx 教程

Nginx 教程 Nginx 简介 Nginx 源码架构分析 Nginx 编译安装 Nginx(Tengine) 编译安装 Nginx(OpenResty) 编译安装 Nginx 配置简述 Nginx Docker 容器化配置

Nginx 核心配置指令

Nginx 核心配置指令 Nginx 配置文件 Nginx 进程配置指令 Nginx 端口监听:listen Nginx 主机名server_name Nginx 处理HTTP请求 Nginx 路由匹配规则:localhost Nginx 重定向配置:rewrite Nginx 根目录配置:root Nginx 访问路径别名:alias Nginx 文件判断:try_files Nginx 零复制:sendfile Nginx 日志记录配置

Nginx HTTP模块

Nginx 镜像模块 Nginx 请求头控制模块 Nginx IP访问控制模块 Nginx 用户cookie模块 Nginx 并发连接数限制模块 Nginx 首页处理模块 Nginx 请求频率限制模块 Nginx 页面缓存时间配置 Nginx gzip压缩及相关配置

Nginx Web服务

Nginx 静态资源服务器搭建 Nginx 文件下载服务器搭建 Nginx 伪动态SSI服务器 Nginx HTTPS服务器搭建 Nginx FastCGI模块配置简述 Nginx PHP服务器环境搭建 Nginx 基于FastCGI负载均衡 Nginx CGI网关接口 Nginx uWSGI模块配置 Nginx Python项目部署 Nginx 伪流媒体服务器搭建 Nginx HTTP2模块配置简述 Nginx WebDAV模块配置简述

Nginx 代理服务器

Nginx HTTP代理服务器 Nginx stream模块简述 Nginx TCP/UDP代理简述 Nginx 基于SSL的TCP代理服务器 Nginx gRPC代理服务器

Nginx 缓存

Nginx Web缓存配置 Nginx 代理缓存配置 Nginx Memcached 缓存模块 Nginx 反向代理缓存服务器配置 Nginx 客户端缓存控制

Nginx 负载均衡

Nginx 负载均衡模块 Nginx 负载均衡策略 Nginx 长连接负载均衡 Nginx upstream容错机制 Nginx upstream动态更新 Nginx TCP/UDP负载均衡

Nginx 日志管理监控

Nginx 日志分析简述 Nginx 访问日志配置 Nginx 错误日志配置 Nginx 日志归档配置 Nginx 日志分析工具 ELK Nginx 监控工具 Prometheus

Nginx 集群

LVS(Linux虚拟服务器)简介 Keepalived 配置简述 Nginx 集群负载搭建 Nginx 集群配置管理规划 Nginx 配置归档工具GitLab Nginx 配置修改工具Ansible Jenkins 安装与配置简述 Nginx 集群配置管理实例

Nginx 在 k8s 的应用

Kubernetes(k8s)系统简述 Kubernetes(k8s)集群部署 Kubernetes(k8s)网络通信 Nginx Ingress 简介 Nginx Ingress 安装部署 Nginx Ingress 配置映射 Nginx Ingress 注解


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 结构

关于上图有以下几点需要说明。
  • Prometheus Server:Prometheus 的基础服务,其从配置文件中 job 配置的 tagrets 目标服务器拉取监控数据,拉取数据周期由配置参数 scrape_interval 设置,同时开放 api 接口提供监控数据的对外查询和聚合分析功能;
  • PushGateway:Prometheus 的推送网关服务。Prometheus 默认都是从被监控服务器上拉取监控数据的,但由于网络原因无法直接访问目标服务器时,可在被监控服务器上通过脚本或工具采集监控数据,然后推送给推送网关服务(PushGateway),Prometheus 的基础服务则实时地从推送网关服务提供的端口 9091 拉取监控数据,完成监控操作;
  • Alertmanager:Prometheus 的告警服务,其对外开放端口 9093 接收 Prometheus Server 发送的告警信息,并按照告警规则将告警信息发送给接收目标;
  • Exporter:监控数据采集接口服务,该服务可由用户按照 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的数据类型

  • 计数类型(Counter):计数类型用于累加值,一直增加或一直减少,重启进程后,会被重置。如记录请求次数、错误发生次数等;
  • 计量类型(Gauge):计量类型用于常规数值,用以表示瞬间状态的数值,可大可小,重启进程后,会被重置,如硬盘空间、内存使用等;
  • 直方图(Histogram):直方图可以理解为柱状图,常用于表示一段时间内数据的采样,能够对其指定区间及总数进行统计;
  • 合计统计(Summary):合计统计和直方图相似,常用于表示一段时间内数据采样的结果。Histogram需要通过_bucket计算quantile(按百分比划分跟踪的结果),而Summary直接存储了quantile的值。

2) Exporter数据输出格式

Exporter 输出的数据是以 Metric 行为单位的文本数据,数据输出格式规范如下。
  • Exporter 输出数据的 Content-Type 必须是text类型(text/plain);
  • Exporter 输出内容以行为单位,空行将被忽略,文本内容最后一行为空行;
  • 每个输出监控数据的行被称为Metric行,每一行文本的最后不能有空格,否则会不被识别;
  • 以"# HELP"开头的行为注释行,表示帮助信息;
  • 以"# TYPE"开头的行为类型声明行,用以声明至下一个注释行间 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监控告警处理流程如下:

  • Prometheus Server 根据配置参数 evaluation_interval 的时间间隔按照告警规则进行计算;
  • 当不满足 expr 设定计算规则的阈值时,该告警规则被置为 inactive 状态;
  • 当满足 expr 设定计算规则的阈值并小于 for 设定的持续时间时,该告警规则被置为 pending 状态;
  • 当满足 expr 设定计算规则的阈值并大于 for 设定的持续时间时,该告警规则被置为 firing 状态,并发送告警信息给 Alertmanager 处理;
  • Alertmanager 接收到告警信息后,根据 labels 进行路由分拣,告警信息会根据 group_by 配置进行分组,如果分组不存在,则新建分组;
  • 新创建的分组将等待 group_wait 指定的时间(等待时如收到同一分组的告警信息,将其进行合并),然后发送通知;
  • 已有分组时将等待 group_interval 指定的时间,当上次发送通知到现在的间隔大于 repeat_interval 或者分组有更新时会发送通知。

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 就会自动发送告警到目标邮箱。