← 返回首页

# 监控服务器搭建文档(Prometheus + Zabbix + Grafana 源码安装)

编写日期:2026-07-06 | 最近更新:2026-07-22(按第 13 章踩坑记录回填正文流程;重写第 14 章:外网地址探测 + Alertmanager 完整安装流程)
操作系统:CentOS 7.9(x86_64)
部署原则:所有组件统一安装到 /data 目录下;数据库(MySQL)与 Docker 数据目录均落在 /data。
Prometheus / Grafana / Zabbix 采用源码/二进制方式部署,数据库使用 Docker 部署。


⚠️ CentOS 7.9 特别说明(务必先读)

CentOS 7 已于 2024-06-30 EOL(停止维护),官方 mirror 已下线,直接 yum install 会报 Could not resolve host: mirror.centos.org。另外 Zabbix 6.4 已 EOL 下架,本文改用 6.0.47 LTS(前端要 PHP 7.4+,CentOS 7 自带 5.4 过旧)。关键处理点:

坑 说明 解决方案(文档已含)
yum 源失效 官方 mirror 下线 切换到 vault.centos.org 源(3.1)
glibc 2.17 CentOS 7 内核/glibc 较旧 Prometheus/Grafana 用官方静态二进制,可正常运行;Grafana 建议用 10.x/11.x LTS 早期版,个别最新版可能要求更高 glibc
gcc 4.8.5 编译 Zabbix 6.4 偏旧 建议用 devtoolset-9(SCL)提供 gcc 9,避免编译报错(8.1)
PHP 5.4 Zabbix 6.4 前端要 PHP 7.4+ 用 Remi 源装 PHP 7.4(8.6)
MySQL 8.0 无本地安装,走 Docker 不受宿主机版本影响 ✅

目录

  1. 整体架构与端口规划
  2. 目录规划(/data 布局)
  3. 2.1 挂载数据盘到 /data(第一步,先做)
  4. 系统环境准备
  5. 安装 Docker(数据目录落在 /data)
  6. Docker 部署数据库(MySQL for Zabbix)
  7. 源码安装 Prometheus
  8. 源码安装 Grafana
  9. 源码安装 Zabbix
  10. 组件集成
  11. 被监控主机接入(安装 Zabbix Agent)
  12. 启动顺序与验证
  13. 常见问题排查
  14. 实战部署踩坑记录(本次真实部署问题汇总)
  15. New API 主备集群(Docker)Prometheus 监控与钉钉告警

1. 整体架构与端口规划

                       ┌─────────────────────────────────────────┐
                       │              监控服务器 (Linux)           │
                       │                                           │
   被监控主机 ──node_exporter──►  Prometheus (9090) ──┐            │
   被监控主机 ──zabbix-agent───►  Zabbix Server (10051)│            │
                       │                              ▼            │
                       │                          Grafana (3000)   │
                       │            ┌───────────────┴──────────┐   │
                       │            │  Docker: MySQL (3306)     │   │
                       │            │  → Zabbix / Grafana 数据  │   │
                       │            └──────────────────────────┘   │
                       └─────────────────────────────────────────┘
组件 端口 部署方式 说明
Prometheus 9090 二进制源码 指标采集与存储
Grafana 3000 二进制源码 可视化展示
Zabbix Server 10051 源码编译 传统监控 Server
Zabbix Web 8080 源码 + PHP Zabbix 前端(Nginx/Apache)
Zabbix Agent 10050 源码编译 本机被监控代理
MySQL 3306 Docker Zabbix / Grafana 后端数据库
node_exporter 9100 二进制 主机指标导出(可选)
mysqld-exporter 9104 Docker MySQL 指标导出(Prometheus 抓取)

2. 目录规划(/data 布局)

所有内容统一放在 /data,结构如下:

/data
├── docker/                     # Docker 根目录(data-root)
│   └── ...                     # 镜像、容器、volume
├── db/                         # 数据库持久化数据
│   ├── mysql/                  # MySQL 数据文件
│   └── mysql-conf/             # MySQL 自定义配置(my.cnf)
├── prometheus/
│   ├── prometheus-2.53.0/      # 解压后的程序目录
│   ├── data/                   # TSDB 数据
│   ├── conf/                   # prometheus.yml 等配置
│   └── mysqld-exporter/        # mysqld-exporter 的 docker-compose
├── grafana/
│   ├── grafana-11.1.0/         # 程序目录
│   ├── data/                   # Grafana 数据
│   ├── logs/                   # 日志
│   └── conf/                   # 自定义配置
├── zabbix/
│   ├── zabbix-6.0.47/          # 源码目录(6.4 已 EOL,用 6.0 LTS)
│   ├── server/                 # 安装前缀 (sbin/bin/etc)
│   └── web/                    # 前端 PHP 文件
├── src/                        # 各类下载的源码包/二进制包临时存放
├── blackbox-exporter/          # Prometheus HTTP 黑盒探测配置
├── alertmanager/               # Alertmanager 配置与持久化数据
└── dingtalk/                   # 钉钉 Webhook 适配器配置

创建目录:

sudo mkdir -p /data/{docker,db/mysql,db/mysql-conf,src}
sudo mkdir -p /data/prometheus/{data,conf,mysqld-exporter}
sudo mkdir -p /data/grafana/{data,logs,conf}
sudo mkdir -p /data/zabbix/{server,web}
sudo mkdir -p /data/{blackbox-exporter,alertmanager,dingtalk}/conf

⚠️ 上面的 mkdir 请在数据盘已挂载到 /data 之后执行,见下一节 §2.1。

2.1 挂载数据盘到 /data(第一步,先做)

由于所有组件、数据库、Docker 数据都落在 /data,务必先把独立数据盘挂载到 /data 并配置开机自动挂载,否则重启后数据盘不挂载会导致数据"消失"或服务起不来。

(1)识别数据盘

# 查看所有磁盘,确认数据盘设备名(如 /dev/sdb、/dev/vdb、/dev/nvme1n1)
lsblk
fdisk -l

示例:系统盘为 /dev/sda,新加的数据盘为 /dev/sdb(无分区、无挂载点)。下方以 /dev/sdb 为例,请按实际替换。

(2)分区(单分区占满整盘)

单盘 ≤2TB 用 fdisk(MBR) 即可;磁盘 >2TB 必须用 GPT(parted),见下方备选。

# 方式 A:fdisk(≤2TB)
sudo fdisk /dev/sdb <<'EOF'
n
p
1


w
EOF
# 生成 /dev/sdb1

# 方式 B:parted(>2TB,GPT)
# sudo parted -s /dev/sdb mklabel gpt
# sudo parted -s /dev/sdb mkpart primary xfs 0% 100%

(3)格式化(CentOS 7.9 默认文件系统 xfs)

sudo mkfs.xfs -f /dev/sdb1
# 如偏好 ext4: sudo mkfs.ext4 /dev/sdb1

(4)挂载并写入 /etc/fstab(开机自动挂载)

# 先创建挂载点(若不存在)
sudo mkdir -p /data

# 用 UUID 挂载(比设备名更稳妥,避免盘符漂移)
UUID=$(sudo blkid -s UUID -o value /dev/sdb1)
echo "数据盘 UUID = ${UUID}"

# 写入 fstab(xfs 示例)
echo "UUID=${UUID}  /data  xfs  defaults,noatime  0 0" | sudo tee -a /etc/fstab

# 挂载全部 fstab 条目并验证
sudo mount -a
df -hT /data          # 应看到 /dev/sdb1 挂载在 /data,类型 xfs

(5)验证

lsblk                 # /data 下应挂着 sdb1
df -hT | grep /data   # 确认容量与文件系统正确

✅ 确认 df -hT /data 显示的是数据盘容量(而非系统盘)后,再回到上面执行 mkdir 建子目录、继续 §3 及后续安装。
⚠️ 若 mount -a 报错,先不要重启(fstab 写错会导致无法正常启动),核对 UUID 与文件系统类型后再试。


3. 系统环境准备

以下命令以 root 或 sudo 执行,均为 CentOS 7.9 命令。

3.1 切换 YUM 源到 vault(必做)

CentOS 7 EOL 后官方镜像下线,先把 yum 源指向归档站 vault.centos.org:

# 备份原有仓库
sudo mkdir -p /etc/yum.repos.d/bak
sudo mv /etc/yum.repos.d/CentOS-*.repo /etc/yum.repos.d/bak/ 2>/dev/null

# 写入 vault 源
sudo tee /etc/yum.repos.d/CentOS-Vault.repo >/dev/null <<'EOF'
[base]
name=CentOS-7.9 Base - vault
baseurl=https://vault.centos.org/7.9.2009/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[updates]
name=CentOS-7.9 Updates - vault
baseurl=https://vault.centos.org/7.9.2009/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[extras]
name=CentOS-7.9 Extras - vault
baseurl=https://vault.centos.org/7.9.2009/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
EOF

# 安装 EPEL(同样走归档/阿里镜像)
sudo yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm 2>/dev/null || \
sudo yum install -y epel-release

sudo yum clean all && sudo yum makecache

如服务器在国内,可把 vault.centos.org 换成 https://mirrors.aliyun.com/centos-vault/7.9.2009/ 提速。

3.2 基础工具

sudo yum install -y wget curl vim tar gcc gcc-c++ make git \
  net-tools lsof pcre-devel

3.3 关闭 SELinux(测试环境建议关闭,生产按需)

sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

3.4 防火墙放行端口

for p in 3000 9090 9100 10050 10051 3306 8080; do
  sudo firewall-cmd --permanent --add-port=${p}/tcp
done
sudo firewall-cmd --reload

3.5 创建运行用户(非 root 运行组件,更安全)

sudo useradd -M -s /sbin/nologin prometheus
sudo useradd -M -s /sbin/nologin grafana
sudo useradd -M -s /sbin/nologin zabbix

4. 安装 Docker(/data)

数据库用 Docker 部署,Docker 的数据目录(镜像/容器/卷)要落在 /data/docker。

4.1 安装 Docker 引擎

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 使用阿里云 Docker 源(CentOS 7 官方源亦可,但国内建议阿里)
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

CentOS 7.9 内核 3.10 满足 Docker 运行要求;docker-compose-plugin 提供 docker compose v2 子命令。

4.2 将 Docker 数据目录指向 /data/docker

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
  "data-root": "/data/docker",
  "log-driver": "json-file",
  "log-opts": { "max-size": "100m", "max-file": "3" },
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me",
    "https://dockerproxy.net",
    "https://docker.m.daocloud.io"
  ]
}
EOF

4.3 启动并验证

sudo systemctl enable --now docker
docker info | grep "Docker Root Dir"      # 应显示 /data/docker
docker info | grep -A5 "Registry Mirrors"  # 确认镜像加速生效(拉镜像超时必查,见 §13.1)
docker version

5. Docker 部署数据库(MySQL for Zabbix)

数据持久化到 /data/db/mysql。这里用 MySQL 8.0(Zabbix 6.4 支持),Grafana 也可复用同一实例(另建库)。

5.1 启动 MySQL 容器

docker run -d \
  --name monitor-mysql \
  --restart=always \
  -p 3306:3306 \
  -v /data/db/mysql:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD='ChangeMe_Root@2026' \
  -e TZ=Asia/Shanghai \
  mysql:8.0 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_bin \
  --default-authentication-plugin=mysql_native_password \
  --log_bin_trust_function_creators=1

说明:Zabbix 要求 utf8mb4_bin 排序规则,且导入 schema 时需要 log_bin_trust_function_creators=1。

5.2 创建 Zabbix / Grafana 数据库与账号

docker exec -i monitor-mysql mysql -uroot -p'ChangeMe_Root@2026' <<'SQL'
-- Zabbix
CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE USER 'zabbix'@'%' IDENTIFIED BY 'Zabbix_Pass@2026';
GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'%';

-- Grafana(可选,Grafana 也可用自带 SQLite)
CREATE DATABASE grafana CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'grafana'@'%' IDENTIFIED BY 'Grafana_Pass@2026';
GRANT ALL PRIVILEGES ON grafana.* TO 'grafana'@'%';

FLUSH PRIVILEGES;
SQL

6. 源码安装 Prometheus

Prometheus 官方提供预编译二进制(Go 静态编译),生产推荐用官方二进制包;若需从源码编译,见 6.4。

6.1 下载与解压到 /data

cd /data/src
VER=2.53.0
wget https://github.com/prometheus/prometheus/releases/download/v${VER}/prometheus-${VER}.linux-amd64.tar.gz
tar -zxf prometheus-${VER}.linux-amd64.tar.gz -C /data/prometheus/
mv /data/prometheus/prometheus-${VER}.linux-amd64 /data/prometheus/prometheus-${VER}

6.2 配置文件

cat > /data/prometheus/conf/prometheus.yml <<'EOF'
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # 主机监控(在被监控机部署 node_exporter:9100)
  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']
EOF

sudo chown -R prometheus:prometheus /data/prometheus

6.3 systemd 托管

sudo tee /etc/systemd/system/prometheus.service >/dev/null <<EOF
[Unit]
Description=Prometheus
After=network.target

[Service]
User=prometheus
Group=prometheus
ExecStart=/data/prometheus/prometheus-2.53.0/prometheus \\
  --config.file=/data/prometheus/conf/prometheus.yml \\
  --storage.tsdb.path=/data/prometheus/data \\
  --web.listen-address=0.0.0.0:9090 \\
  --web.enable-lifecycle
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now prometheus

访问:http://<服务器IP>:9090

6.4(可选)从源码编译

# 需要 Go 1.21+
cd /data/src
git clone https://github.com/prometheus/prometheus.git
cd prometheus
git checkout v2.53.0
make build          # 生成 prometheus / promtool 二进制
cp prometheus promtool /data/prometheus/prometheus-2.53.0/

6.5(可选)node_exporter 主机指标

cd /data/src
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.1/node_exporter-1.8.1.linux-amd64.tar.gz
tar -zxf node_exporter-1.8.1.linux-amd64.tar.gz -C /data/prometheus/
# 用 systemd 托管,监听 :9100

systemd 服务文件(监听 :9100):

sudo tee /etc/systemd/system/node_exporter.service >/dev/null <<'EOF'
[Unit]
Description=Node Exporter
After=network.target

[Service]
ExecStart=/data/prometheus/node_exporter-1.8.1.linux-amd64/node_exporter \
  --collector.systemd \
  --collector.processes \
  --web.listen-address=:9100
Restart=always

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
curl -s http://localhost:9100/metrics | head -5    # 验证

Grafana 中文仪表盘导入见 §9.3.4(推荐 ID 8919)。


7. 源码安装 Grafana

Grafana 官方提供独立二进制包(standalone),解压即用,是"源码/二进制"部署到 /data 的推荐方式。
CentOS 7.9 兼容性:Grafana 为 Go 静态编译,依赖极少,10.x / 11.x 在 glibc 2.17 上均可正常运行。本文用 11.1.0;若遇到极个别版本报 glibc 版本过低,可回退到 10.4.x LTS。

7.1 下载与解压到 /data

cd /data/src
VER=11.1.0
wget https://dl.grafana.com/oss/release/grafana-${VER}.linux-amd64.tar.gz
tar -zxf grafana-${VER}.linux-amd64.tar.gz -C /data/grafana/
mv /data/grafana/grafana-v${VER} /data/grafana/grafana-${VER}

7.2 自定义配置(数据/日志/DB 落到 /data)

cat > /data/grafana/conf/custom.ini <<'EOF'
[paths]
data = /data/grafana/data
logs = /data/grafana/logs
plugins = /data/grafana/data/plugins

[server]
http_addr = 0.0.0.0
http_port = 3000

# 使用 Docker MySQL 作为后端(可选,不配则默认 SQLite)
[database]
type = mysql
host = 127.0.0.1:3306
name = grafana
user = grafana
password = Grafana_Pass@2026
EOF

sudo chown -R grafana:grafana /data/grafana

7.3 systemd 托管

sudo tee /etc/systemd/system/grafana.service >/dev/null <<EOF
[Unit]
Description=Grafana
After=network.target docker.service

[Service]
User=grafana
Group=grafana
WorkingDirectory=/data/grafana/grafana-11.1.0
ExecStart=/data/grafana/grafana-11.1.0/bin/grafana server \\
  --homepath=/data/grafana/grafana-11.1.0 \\
  --config=/data/grafana/conf/custom.ini
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now grafana

访问:http://<服务器IP>:3000,默认账号 admin / admin(首次登录强制改密)。


8. 源码安装 Zabbix

Zabbix Server 需要从源码 ./configure && make 编译。

8.1 安装编译依赖

CentOS 7.9 自带 gcc 4.8.5,编译 Zabbix 6.4 建议使用 SCL 提供的 gcc 9:

# 1) 安装编译依赖库
sudo yum install -y gcc make automake pkgconfig \
  mysql-devel libxml2-devel net-snmp-devel libcurl-devel \
  pcre2-devel openssl-devel libevent-devel zlib-devel

# 2) 安装 devtoolset-9(gcc 9),编译时启用
sudo yum install -y centos-release-scl
# SCL 源同样 EOL,需切 vault
sudo sed -i 's|^mirrorlist=|#mirrorlist=|g; s|^# *baseurl=http://mirror.centos.org|baseurl=https://vault.centos.org|g' \
  /etc/yum.repos.d/CentOS-SCLo-scl*.repo
sudo yum install -y devtoolset-9-gcc devtoolset-9-gcc-c++
# 临时启用 gcc9(仅当前 shell 生效,编译 Zabbix 前执行)
source /opt/rh/devtoolset-9/enable
gcc --version    # 确认 9.x

若本机没有 MySQL 客户端库,mysql-devel 提供 mysql_config 供 --with-mysql 链接。
CentOS 7 的 pcre2-devel 在 base 源即可安装;Zabbix 6.4 需要 PCRE2。

8.2 下载源码到 /data 并编译

cd /data/src
# ⚠️ Zabbix 6.4 已 EOL 下架(cdn 会 404),CentOS 7.9 请用 6.0 LTS 最新版
VER=6.0.47
wget https://cdn.zabbix.com/zabbix/sources/stable/6.0/zabbix-${VER}.tar.gz
tar -zxf zabbix-${VER}.tar.gz -C /data/zabbix/
cd /data/zabbix/zabbix-${VER}

# ⚠️ CentOS 7.9:编译前先启用 gcc9,否则可能编译报错
source /opt/rh/devtoolset-9/enable

./configure \
  --prefix=/data/zabbix/server \
  --enable-server \
  --enable-agent \
  --with-mysql \
  --with-net-snmp \
  --with-libcurl \
  --with-libxml2 \
  --with-openssl

make -j$(nproc)
make install

编译产物在 /data/zabbix/server/(sbin/zabbix_server、sbin/zabbix_agentd、etc/)。

💡 VER 只是当前 shell 的临时变量,换终端 / 新开会话会丢失(见 §13.3)。下载、解压、编译请在同一次会话中连续执行;会话中断后先重新 VER=6.0.47 再继续。

8.3 导入数据库 schema(导入到 Docker MySQL)

⚠️ 导入前必须确认 MySQL 已开启 log_bin_trust_function_creators=1(容器启用了 binlog 时,导入触发器/存储过程会报 ERROR 1419 SUPER privilege)。用 root 动态打开:
bash docker exec -i monitor-mysql mysql -uroot -p'ChangeMe_Root@2026' \ -e "SET GLOBAL log_bin_trust_function_creators=1;"

cd /data/zabbix/zabbix-6.0.47/database/mysql
ls    # 先确认文件名:6.0 源码包是 schema.sql / images.sql / data.sql 三个文件

# 依次导入(顺序不能错)——一条 cat 管道也可以
cat schema.sql images.sql data.sql | \
  docker exec -i monitor-mysql mysql -uzabbix -p'Zabbix_Pass@2026' zabbix

# 导入完成后可关闭 log_bin_trust_function_creators(可选)
docker exec -i monitor-mysql mysql -uroot -p'ChangeMe_Root@2026' \
  -e "SET GLOBAL log_bin_trust_function_creators=0;"

验证导入成功:
bash docker exec -it monitor-mysql mysql -uzabbix -p'Zabbix_Pass@2026' zabbix \ -e "SELECT * FROM dbversion; SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='zabbix';"
dbversion 有一行、表数 170+ 即成功。
若导入中途报错后需重来,先删库重建再导,避免"表已存在":
DROP DATABASE zabbix; CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

8.4 配置 Zabbix Server

cat > /data/zabbix/server/etc/zabbix_server.conf <<'EOF'
LogFile=/data/zabbix/server/zabbix_server.log
PidFile=/data/zabbix/server/zabbix_server.pid
DBHost=127.0.0.1
DBName=zabbix
DBUser=zabbix
DBPassword=Zabbix_Pass@2026
DBPort=3306
ListenPort=10051
Timeout=30
EOF

sudo chown -R zabbix:zabbix /data/zabbix

8.5 systemd 托管 Zabbix Server / Agent

# Server
sudo tee /etc/systemd/system/zabbix-server.service >/dev/null <<EOF
[Unit]
Description=Zabbix Server
After=network.target docker.service

[Service]
Type=forking
User=zabbix
Group=zabbix
ExecStart=/data/zabbix/server/sbin/zabbix_server -c /data/zabbix/server/etc/zabbix_server.conf
PIDFile=/data/zabbix/server/zabbix_server.pid
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

# Agent(本机被监控)
sudo tee /etc/systemd/system/zabbix-agent.service >/dev/null <<EOF
[Unit]
Description=Zabbix Agent
After=network.target

[Service]
Type=forking
User=zabbix
Group=zabbix
ExecStart=/data/zabbix/server/sbin/zabbix_agentd -c /data/zabbix/server/etc/zabbix_agentd.conf
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now zabbix-server zabbix-agent

8.6 部署 Zabbix Web 前端(PHP)

Zabbix 6.4 前端要求 PHP 7.4+,而 CentOS 7.9 自带 PHP 5.4,必须用 Remi 源 安装 PHP 7.4,配合 Nginx + PHP-FPM。

# 1) 安装 Remi 源并启用 PHP 7.4
sudo yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm
sudo yum install -y yum-utils
sudo yum-config-manager --enable remi-php74

# 2) 安装 Nginx + PHP 7.4 及 Zabbix 前端所需扩展
sudo yum install -y nginx \
  php php-fpm php-mysqlnd php-gd php-bcmath \
  php-mbstring php-xml php-ldap php-json php-gettext

php -v    # 确认 7.4.x

# 3) 拷贝前端文件到 /data
# ⚠️ 必须拷贝 ui/ 目录"里面"的文件,不能多套一层 ui/,否则 nginx 报 403(见 §13.4)
cp -r /data/zabbix/zabbix-6.0.47/ui/* /data/zabbix/web/
ls -l /data/zabbix/web/index.php      # 确认入口文件直接在 web/ 下
sudo chown -R nginx:nginx /data/zabbix/web
sudo chmod 755 /data /data/zabbix /data/zabbix/web

Remi 源在 CentOS 7 上仍可用(PHP 7.4 归档包保留)。若 remi-php74 启用失败,可改用 remi-php80(Zabbix 6.4 同样支持 PHP 8.0)。

Nginx 站点配置(/etc/nginx/conf.d/zabbix.conf):

server {
    listen 8080;
    server_name _;
    root /data/zabbix/web;
    index index.php;

    location / {
        try_files $uri $uri/ =404;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;   # 或 unix:/run/php-fpm/www.sock
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

PHP 需调整(/etc/php.ini):

max_execution_time = 300
memory_limit = 256M
post_max_size = 32M
upload_max_filesize = 16M
max_input_time = 300
date.timezone = Asia/Shanghai

启动并按向导安装:

sudo systemctl enable --now php-fpm nginx
# ⚠️ 每次修改 php.ini 后必须 restart 才生效(向导预检查失败的最常见原因,见 §13.5)
sudo systemctl restart php-fpm

浏览器访问 http://<服务器IP>:8080,按向导填写 DB(127.0.0.1 / zabbix / 密码),完成安装。默认后台账号 Admin / zabbix。

⚠️ 向导最后一步若报「无法创建配置文件」,是 php-fpm 运行用户对 web/conf/ 无写权限(见 §13.8):
bash sudo mkdir -p /data/zabbix/web/conf sudo chown -R nginx:nginx /data/zabbix/web/conf # php-fpm 运行用户,默认 nginx
点「完成」后收回权限:sudo chmod 644 /data/zabbix/web/conf/zabbix.conf.php。也可以点「下载配置文件」手动放入该目录。

8.7 通过已有 nginx 主备集群对外提供访问(两种方案)

线上通常已有 nginx 主备(keepalived + VIP)做统一入口。Zabbix 前端接入有两种方案:

方案 前端文件位置 特点 适用
A. 反向代理 监控服务器 :8080 主备 nginx 只做 proxy_pass,不解析 PHP,维护简单 推荐
B. 前端直部署 主备两台 nginx 本机 前端 + php-fpm 跑在主备两台,仅 DB / Server 回连监控机 本次实战采用

方案 A:反向代理

Zabbix 前端已在监控服务器 8080 端口跑起来(§8.6)。用已有的一套 nginx 主备服务器(keepalived + VIP)做反向代理,用户通过 VIP 访问,nginx 把请求 proxy_pass 转发到后端 8080。这一层只做代理和高可用,不解析 PHP。

                用户访问 http://VIP
                         │
                ┌────────┴────────┐   keepalived VIP 漂移
                ▼                 ▼
    ┌───────────────────┐ ┌───────────────────┐
    │ nginx 主 (MASTER) │ │ nginx 备 (BACKUP) │   ← 纯反向代理,两台配置相同
    │   proxy_pass ↓    │ │   proxy_pass ↓    │
    └─────────┬─────────┘ └─────────┬─────────┘
              └──────────┬──────────┘
                         ▼  proxy_pass
        监控服务器 Zabbix 前端 http://<监控服务器IP>:8080

(1)反向代理配置(主、备两台内容完全一致)

放到各自 nginx 的站点目录(yum 版 /etc/nginx/conf.d/zabbix-proxy.conf,编译版放主配置 http{} 的 include 目录):

upstream zabbix_backend {
    server <监控服务器IP>:8080;      # 后端 Zabbix 前端(如 172.16.1.30:8080)
    keepalive 16;
}

server {
    listen 80;
    server_name zabbix.example.com;   # 换成你的域名;无域名可用 _ 直接走 VIP

    client_max_body_size 32m;         # Zabbix 配置导入/上传需要,别漏

    location / {
        proxy_pass http://zabbix_backend;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;   # 前端识别 http/https 靠它
        proxy_connect_timeout 10s;
        proxy_read_timeout    300s;    # 与 PHP max_execution_time 对齐
        proxy_send_timeout    300s;
    }
}

⚠️ 主备两台都要放这份配置并各自 reload:
bash nginx -t && nginx -s reload # 编译版:/usr/local/nginx/sbin/nginx -t && ... -s reload

(2)后端放行 8080 给主备两台

监控服务器防火墙 / 云安全组放行 8080 给主、备 nginx 的 IP(含 VIP):

for ip in <主nginx_IP> <备nginx_IP> <VIP>; do
  firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=${ip}/32 port port=8080 protocol=tcp accept"
done
firewall-cmd --reload

(3)HTTPS(可选)

若代理层做 SSL 终结,把 listen 80 改成 listen 443 ssl; 并加证书,后端仍用 http 的 8080;同时 X-Forwarded-Proto $scheme 保留,让 Zabbix 前端生成正确的 https 链接。可再加一个 listen 80 的 server 做 301 跳转到 https。

(4)验证

# 在主/备 nginx 机分别测到后端连通
nc -zv <监控服务器IP> 8080
# 浏览器访问 http://VIP (或域名),应正常打开 Zabbix 登录页

说明:反向代理不涉及 Zabbix 的 zabbix.conf.php,所以主备切换对前端会话的影响与 §13.9 相同(默认切换后需重新登录一次)。

方案 B:前端直接部署在 nginx 主备集群(本次实战采用)

本次实战前端未装在监控服务器,而是放在已有业务的 nginx 主备集群上。要点(来自 §13.9 实战记录):

  1. php-fpm 必须与 nginx 同机(从本地磁盘读 PHP 文件),所以主备两台都要部署 ui/* + php-fpm,配置一致(按 §8.6 在两台各执行一遍)。
  2. fastcgi_pass 指向 nginx 本机的 php-fpm(127.0.0.1:9000),不是监控服务器。
  3. 安装向导里 Database host / Zabbix server host 填监控服务器内网 IP(如 172.16.1.30),不是 localhost。
  4. 监控服务器防火墙 / 云安全组放行 3306、10051 给主、备两台 IP(含 VIP):
    bash for ip in <主nginx_IP> <备nginx_IP> <VIP>; do sudo firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=${ip}/32 port port=3306 protocol=tcp accept" sudo firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=${ip}/32 port port=10051 protocol=tcp accept" done sudo firewall-cmd --reload
  5. 生成的 zabbix.conf.php 手动同步到另一台:scp /data/zabbix/web/conf/zabbix.conf.php root@<备机IP>:/data/zabbix/web/conf/,否则切到备机会重新弹安装向导。
  6. 会话默认存 PHP 本地,主备切换后需重新登录一次(数据不丢);要无感切换需共享 session(DB/Redis),非强需求不建议一开始就上。
  7. 编译版 nginx 配置在 /usr/local/nginx/conf/,改动前先备份(主备机上可能有其他线上业务),nginx -t 通过再 reload。

9. 组件集成

9.1 Grafana 接入 Prometheus 数据源

  1. 登录 Grafana → Connections → Data sources → Add data source → Prometheus
  2. URL 填 http://localhost:9090 → Save & Test
  3. 导入 Dashboard:Node Exporter Full(ID 1860)等

9.2 Grafana 接入 Zabbix 数据源

Grafana 只是展示层,通过 Zabbix API 读数据(不直连数据库),所以升级 Grafana 不影响 Zabbix / Prometheus 本身,它们照常运行。

(1)安装 Zabbix 插件(在监控服务器 VM-1-30)

# 以 grafana 用户身份装,避免生成 root 属主文件导致权限错误(见 §13.11)
sudo -u grafana /data/grafana/grafana-11.6.0/bin/grafana cli \
  --pluginsDir /data/grafana/data/plugins \
  plugins install alexanderzobnin-zabbix-app
systemctl restart grafana

路径里的版本目录换成实际的(ls /data/grafana/)。
无外网时离线装:下载 alexanderzobnin-zabbix-app.zip 解压到 /data/grafana/data/plugins/,然后 chown -R grafana:grafana /data/grafana/data/plugins 再重启。

(2)⚠️ 版本兼容性(关键,务必先确认)

Zabbix 插件对 Grafana 版本有硬性要求,不匹配会导致前端白屏报 Minified React error #130(见 §13.12)。安装后先核对:

grep -i grafanaDependency /data/grafana/data/plugins/alexanderzobnin-zabbix-app/plugin.json
/data/grafana/grafana-*/bin/grafana server -v

例如插件 6.4.1 要求 grafanaDependency >= 11.6.0。若你的 Grafana 低于该版本,二选一:
- 升级 Grafana(推荐):见 §13.12 的升级步骤(CentOS 7.9 建议升到刚好满足的 11.6.x,不要直接上 13.x,glibc 2.17 会报 GLIBC not found)。
- 降插件版本:grafana cli plugins install alexanderzobnin-zabbix-app <兼容版本>。

(3)在 Zabbix 建只读 API 账号(供 Grafana 用)

不要用 Admin 直接接。Zabbix Web 里:
1. 用户 → 用户群组 → 创建用户群组(如 grafana-ro),对要展示的主机组授 读(Read) 权限。
2. 用户 → 用户 → 创建用户:用户名 grafana、设密码、群组选 grafana-ro、角色选 User role。

(4)Grafana 添加数据源

  1. ⚙ Plugins 搜 Zabbix → Enable 启用。
  2. Connections → Data sources → Add data source → Zabbix。
  3. 填写:
  4. URL:http://<Zabbix前端IP或VIP>/api_jsonrpc.php(走前端 8080 则 http://<前端IP>:8080/api_jsonrpc.php)
  5. Zabbix API details:Username grafana / 对应密码
  6. Trends:开启(大时间范围查询更快)
  7. Save & test → 显示 Zabbix API version: 6.0.x 即成功。

⚠️ 监控服务器(Grafana)要能访问 Zabbix 前端地址;不通则在前端/代理放行端口给监控服务器 IP。

(5)出图(推荐用随附的定制模板)

本文档目录随附两个已按 Zabbix 6.0 Linux by Zabbix agent 模板调好、全中文的 Grafana 仪表盘 JSON,导入即用:

文件 用途
grafana-zabbix-linux-dashboard.json 单台深度:切 Host 看一台的全部细节(概览仪表 + CPU各态/负载/内存/磁盘/网络/磁盘IO/Swap/中断/错误丢包 + 磁盘·内存横条)
grafana-zabbix-all-servers.json 全局总览:一屏看所有服务器,每台一行(repeat by host,行内 CPU/内存仪表 + 磁盘横条 + 内存使用横条 + CPU各态/负载/网络/内存/Swap/进程)

导入步骤:
1. Grafana → Dashboards → New → Import
2. 上传 JSON 或粘贴内容 → Load
3. 数据源选 DS_ZABBIX(你的 Zabbix 数据源)→ Import
4. 顶部 Group 选主机组、Host 选主机(总览页 Host 选 All)
5. 改过 JSON 重新导入时勾选 Overwrite 覆盖

也可手动自建:New Dashboard → Add panel → 数据源选 Zabbix → 依次选 Group / Host / Item。

💡 Item 名匹配技巧:grafana-zabbix 按 item 名(非 key)模糊匹配,用不带前缀的正则(如 /CPU .* time/、/: Space utilization/)即可,不管 item 是否带 Linux: 前缀都能命中。

数据显示 N/A / No data 的排查顺序(本次实战验证,见 §13.13):
1. 顶部变量没选:Group 和 Host 是级联的——必须先选 Group,Host 下拉才有值,不选就全 N/A。
2. 数据源/权限:数据源 Save&test 是否 Zabbix API version 6.0.x;grafana 只读账号是否在用户群组里对该主机组授了 读 权限(在"用户"页改无效,必须在"用户群组"里,见 §13.13)。
3. Zabbix 端有无数据:监测→最新数据有值?可用性 ZBX 图标绿?/data/zabbix/server/bin/zabbix_get -s <IP> -k system.cpu.load 能取到值?
4. 社区模板 item 名不匹配:从 grafana.com 导入的老仪表盘(如葡语版)item 名对不上你的模板,全 N/A——改用随附模板或用 Explore(Item 填 /.*/)确认真实 item 名后重选。

9.3 Prometheus 监控 MySQL(mysqld-exporter)

§5 部署的 MySQL 容器自身也需要被监控(QPS、连接数、InnoDB 缓冲池、慢查询等),通过 mysqld-exporter 把 MySQL 内部指标转成 Prometheus 格式。

MySQL (3306) ──采集──► mysqld-exporter (9104) ──scrape──► Prometheus (9090) ──► Grafana (3000)
   Docker                  Docker                          二进制             二进制

9.3.1 创建 MySQL 监控账号

mysqld-exporter 用一个最小权限账号读 MySQL 内部表,不要用 root:

docker exec -i monitor-mysql mysql -uroot -p'ChangeMe_Root@2026' <<'SQL'
CREATE USER 'monitor'@'%' IDENTIFIED BY 'Monitor_Pass@2026'
  WITH MAX_USER_CONNECTIONS 5;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'monitor'@'%';
GRANT SELECT ON performance_schema.* TO 'monitor'@'%';
FLUSH PRIVILEGES;
SELECT User, Host FROM mysql.user WHERE User = 'monitor';
SQL

只授 PROCESS / REPLICATION CLIENT / SELECT,限 5 个并发连接,最小权限原则。

9.3.2 Docker Compose 部署 mysqld-exporter

在 /data/prometheus/mysqld-exporter/ 下创建 docker-compose.yml:

services:
  mysqld-exporter:
    image: prom/mysqld-exporter:v0.16.0
    container_name: mysqld-exporter
    restart: unless-stopped
    ports:
      - "9104:9104"
    environment:
      # DSN 格式:用户:密码@tcp(主机:端口)/
      # 同 Docker 网络用容器名 monitor-mysql;不同网络改 host.docker.internal 或宿主 IP
      DATA_SOURCE_NAME: "monitor:Monitor_Pass@2026@tcp(monitor-mysql:3306)/"
    command:
      - "--collect.info_schema.tables"
      - "--collect.info_schema.innodb_metrics"
      - "--collect.info_schema.processlist"
      - "--collect.info_schema.tables.databases=*"
      - "--collect.global_status"
      - "--collect.global_variables"
      - "--collect.binlog_size"
      - "--collect.perf_schema.eventsstatements"
      - "--collect.perf_schema.eventswaits"
      - "--collect.perf_schema.file_events"
      - "--collect.perf_schema.file_instances"
      - "--collect.perf_schema.indexiowaits"
      - "--collect.perf_schema.tableiowaits"
      - "--collect.perf_schema.tablelocks"

启动并验证:

cd /data/prometheus/mysqld-exporter
docker compose up -d
docker compose logs -f mysqld-exporter        # 看到 "Listening on :9104" 即成功

# 验证 mysql_up=1 表示 exporter 已连上 MySQL
curl -s http://localhost:9104/metrics | grep "^mysql_up"

⚠️ DATA_SOURCE_NAME 里的 monitor-mysql 是 MySQL 容器名,两个容器要在同一个 Docker 网络才能用容器名互访。若不在同网络:
- 方案 A:在 docker-compose 里加 networks: 让两个容器加入同一自定义网络
- 方案 B:改用宿主机内网 IP(如 172.16.1.30:3306)
- 方案 C:用 host.docker.internal(Linux 需配 extra_hosts: ["host.docker.internal:host-gateway"])

9.3.3 接入 Prometheus 抓取

编辑 /data/prometheus/conf/prometheus.yml,在 scrape_configs 下追加:

  - job_name: 'mysql'
    scrape_interval: 15s
    static_configs:
      - targets: ['localhost:9104']

reload Prometheus(§6.3 启动参数带 --web.enable-lifecycle 才能用此接口):

curl -X POST http://localhost:9090/-/reload

打开 http://<服务器IP>:9090/targets,确认 mysql 这个 job 状态是 UP。

9.3.4 Grafana 导入中文仪表盘

MySQL 监控(必装):

Dashboard ID 名称 说明
17320 Mysqld Exporter Dashboard CN StarsL.cn 出品,全中文,专为 mysqld-exporter 设计

导入步骤:Grafana → Dashboards → New → Import → 输入 17320 → Load → 数据源选 Prometheus → Import。

打开后顶部下拉选 MySQL 实例(默认 localhost:9104),即可看到:
- QPS / TPS
- 用户连接数
- InnoDB 缓冲池命中率与内存使用
- 慢查询数
- 表占用空间 Top 10
- Processlist 列表

主机监控(推荐补一个,独立的中文仪表盘):

Dashboard ID 名称 说明
8919 Node Exporter for Prometheus Dashboard StarsL.cn 出品,全中文,主机 CPU/内存/磁盘/网络

⚠️ Node Exporter 中文版 ID 是 8919,不是 11074(11074 是同作者的英文版 EN)。导入 8919 后顶部 $node 变量选 172.16.1.30:9100(你的 node_exporter 实例)即可。

若某个面板提示 "Plugin not found"(饼图),装一下:docker exec -it grafana grafana-cli plugins install grafana-piechart-panel && systemctl restart grafana(Grafana 用 Docker 时把 grafana 换成对应容器名)。

17320 仪表盘部分面板 No data 的排查:
1. exporter 采集项没开全:对照 §9.3.2 的 command: 列表,缺哪个补哪个,重启容器
2. $node_host 变量配错:17320 里 CPU 使用率面板用了 node_cpu_seconds_total,但变量默认从 mysql_up 拉 instance → 改 Settings → Variables → node_host,把 Metric 改成 node_uname_info,Label filters 清空
3. MariaDB 专属 metric:个别面板用了 MariaDB 才有的指标(如 userstats),MySQL 拉不到属正常,忽略即可

9.3.5 MySQL 配置优化(my.cnf)

挂载自定义 my.cnf 给 MySQL 容器,开启 performance_schema、慢查询日志、InnoDB 调优。

/data/db/mysql-conf/my.cnf:

[mysqld]

# ===== 基础 =====
character-set-server    = utf8mb4
collation-server        = utf8mb4_bin
default-storage-engine  = InnoDB

# ===== 连接数 =====
max_connections         = 500                 # 看业务量调整
max_connect_errors      = 10000
wait_timeout            = 600                 # 10 分钟空闲断开
interactive_timeout     = 600

# ===== InnoDB 核心(innodb_buffer_pool_size 按物理内存 ~70% 调)=====
innodb_buffer_pool_size         = 2G
innodb_buffer_pool_instances    = 8
innodb_redo_log_capacity        = 1G          # MySQL 8.0.30+ 替代 innodb_log_file_size
innodb_log_buffer_size          = 64M
innodb_flush_log_at_trx_commit  = 2           # 2=每秒刷盘(性能), 1=每次提交刷(安全)
innodb_flush_method             = O_DIRECT    # 绕过 OS 缓存,Linux 必开
innodb_io_capacity              = 2000        # SSD 设 2000+,HDD 设 200
innodb_io_capacity_max          = 4000
innodb_read_io_threads          = 8
innodb_write_io_threads         = 8
innodb_file_per_table           = 1

# ===== 临时表/排序缓冲 =====
tmp_table_size          = 64M
max_heap_table_size     = 64M
sort_buffer_size        = 4M
join_buffer_size        = 4M

# ===== Binlog =====
log_bin                         = mysql-bin
binlog_format                   = ROW
binlog_expire_logs_seconds      = 604800      # 7 天自动清理
max_binlog_size                 = 512M
sync_binlog                     = 0           # 0=系统决定(性能), 1=每次刷(安全)
log_bin_trust_function_creators = 1

# ===== 慢查询(日志放数据卷,不要放 /var/log/mysql,否则容器起不来,见 §13.14)=====
slow_query_log                  = 1
slow_query_log_file             = /var/lib/mysql/slow.log
long_query_time                 = 2
log_queries_not_using_indexes   = 1
log_slow_admin_statements       = 1

# ===== Performance Schema(mysqld-exporter 的 perf_schema 采集依赖这个)=====
performance_schema              = ON

# ===== 其他 =====
skip_name_resolve               = 1           # 禁止 DNS 反向解析,加速连接
explicit_defaults_for_timestamp = 1
# ⚠️ lower_case_table_names 不能在已有数据上改!保持默认 0,见 §13.15
sql_mode                        = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION

[client]
default-character-set   = utf8mb4

[mysql]
default-character-set   = utf8mb4

把 §5.1 的 docker run 迁移到 docker-compose 管理(推荐),新建 /data/db/mysql-conf/docker-compose.yml:

services:
  mysql:
    image: mysql:8.0
    container_name: monitor-mysql
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "ChangeMe_Root@2026"
      TZ: "Asia/Shanghai"
    volumes:
      - /data/db/mysql:/var/lib/mysql
      - /data/db/mysql-conf/my.cnf:/etc/mysql/conf.d/my.cnf:ro    # 自定义配置
    command:
      - "--character-set-server=utf8mb4"
      - "--collation-server=utf8mb4_bin"
      - "--log_bin_trust_function_creators=1"

无痛替换原容器(bind mount 数据不会丢):

cd /data/db/mysql-conf
docker stop monitor-mysql && docker rm monitor-mysql
docker compose up -d
docker logs -f monitor-mysql        # 看到 "ready for connections" 即成功

⚠️ innodb_buffer_pool_size 按物理内存调整:8G 内存设 6G,16G 设 12G,32G 设 24G。CentOS 7.9 + 4G 内存机器保守设 2G。

9.3.6 日志查看方式

# MySQL 错误日志(走 stderr,docker logs 直接看)
docker logs monitor-mysql

# 慢查询日志(写在数据卷里,MySQL 自动创建文件)
tail -f /data/db/mysql/slow.log

# mysqld-exporter 日志
docker logs mysqld-exporter

10. 被监控主机接入(安装 Zabbix Agent)

要监控一台 Linux 主机,需在目标主机装 agent 并指向 Zabbix Server,再在 Web 添加主机。

① 目标主机安装 agent(CentOS 7 示例)

rpm -Uvh https://repo.zabbix.com/zabbix/6.0/rhel/7/x86_64/zabbix-release-latest-6.0.el7.noarch.rpm
yum clean all && yum install -y zabbix-agent

无外网时,拷贝监控服务器编译好的 /data/zabbix/server/sbin/zabbix_agentd + 配置过去用。

② 配置 /etc/zabbix/zabbix_agentd.conf

Server=<监控服务器IP>          # 被动模式:允许该 server 采集
ServerActive=<监控服务器IP>    # 主动模式:主动上报
Hostname=web-node-01           # 本机唯一名,与 Web 添加的主机名一致
systemctl enable --now zabbix-agent
# 放行 10050 给监控服务器
firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=<监控服务器IP>/32 port port=10050 protocol=tcp accept"
firewall-cmd --reload

云服务器安全组同样放行 10050。

③ 监控服务器侧验证连通

/data/zabbix/server/bin/zabbix_get -s <被监控主机IP> -k system.cpu.load   # 返回数值即通

④ Zabbix Web 添加主机
1. 数据采集 → 主机 → 创建主机
2. 主机名称=web-node-01;模板选 Linux by Zabbix agent(被动,推荐);主机群组选/建 Linux servers;接口加 Agent,IP=被监控主机 IP,端口 10050
3. 添加后约 1~2 分钟,可用性 ZBX 图标转绿,监测→最新数据出现指标即成功

⑤ 推荐模板与阈值宏
- 首选 Linux by Zabbix agent(被动);agent 在 NAT 后用 Linux by Zabbix agent active(主动)
- 常用阈值宏(主机→宏 里覆盖):{$MEMORY.UTIL.MAX}(内存%默认90)、{$VFS.FS.PUSED.MAX.WARN/CRIT}(磁盘%默认80/90)、{$LOAD_AVG_PER_CPU.MAX.WARN}(每CPU负载默认1.5)


11. 启动顺序与验证

11.1 推荐启动顺序

Docker (MySQL) → Zabbix Server → Zabbix Agent → Prometheus → Grafana → Nginx/PHP

11.2 验证清单

# Docker & MySQL
docker ps | grep monitor-mysql
docker exec -it monitor-mysql mysql -uzabbix -p'Zabbix_Pass@2026' -e "SHOW DATABASES;"

# 服务状态
systemctl status prometheus grafana zabbix-server zabbix-agent nginx php-fpm

# 端口监听
ss -tlnp | egrep '9090|3000|10051|10050|3306|8080'
检查项 访问地址 预期
Prometheus http://IP:9090/targets targets UP
Grafana http://IP:3000 登录页
Zabbix Web http://IP:8080 登录页;登录后顶部无 "Zabbix server is not running" 红字(有则 server 未启动,见 §13.10)
MySQL docker exec 进容器查库 库存在

12. 常见问题排查

现象 排查方向
df -hT /data 显示的是系统盘 / 数据没落到数据盘 数据盘未挂载或挂载到了别处,重新执行 §2.1 的挂载步骤,确认在 mkdir 子目录之前已挂好
重启后 /data 空了、服务起不来 fstab 未配置或 UUID 写错,数据盘没自动挂载;lsblk 核对后修正 /etc/fstab
mount -a 报错 fstab 条目写错(UUID/文件系统类型),先别重启,核对后再试,避免开机进救援模式
yum install 报 Could not resolve mirror.centos.org CentOS 7 EOL,未切 vault 源,见 3.1
centos-release-scl 装完 SCL 源仍 404 SCL 源也 EOL,需按 8.1 的 sed 命令把 baseurl 改到 vault.centos.org
PHP 版本仍是 5.4 / Zabbix 前端校验不过 未启用 Remi 的 remi-php74,见 8.6
Zabbix make 报 C 语法/头文件错误 未 source /opt/rh/devtoolset-9/enable 启用 gcc9
Grafana 启动报 GLIBC_2.xx not found 该 Grafana 版本要求更高 glibc,回退到 10.4.x LTS
docker info 的 Root Dir 不是 /data/docker 检查 /etc/docker/daemon.json 后 systemctl restart docker;若已有旧数据需迁移 /var/lib/docker
Zabbix schema 导入报 function creators 确认容器启动参数带 --log_bin_trust_function_creators=1
Zabbix Server 起不来,日志报连不上 DB 检查 zabbix_server.conf 的 DBHost=127.0.0.1、端口、密码;确认 MySQL 容器已 -p 3306:3306
./configure 报缺 mysql 安装 mysql-devel / libmysqlclient-dev,或指定 --with-mysql=/usr/bin/mysql_config
Grafana 无法连 MySQL 确认 grafana 库/账号已建,collation 用 utf8mb4_unicode_ci
端口访问不通 检查防火墙(firewalld/ufw)、SELinux、云安全组
Prometheus targets DOWN 被监控端 node_exporter/agent 是否启动、端口是否放行

13. 实战部署踩坑记录(本次真实部署问题汇总)

本章按部署顺序记录本次在 CentOS 7.9(腾讯云 VM)实际踩到的问题、报错原文与解决办法,供复现和排错参考。

13.1 Docker 拉镜像超时

  • 报错:docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled ... (Client.Timeout exceeded)
  • 原因:国内服务器直连 Docker Hub 超时。
  • 解决:配置 /etc/docker/daemon.json 的 registry-mirrors(多源并列,见 §4.2),systemctl restart docker 后 docker info | grep -A5 "Registry Mirrors" 确认生效,再 docker pull mysql:8.0。
  • 注意:公共加速器时效性强(如中科大 ustc 已停),一次配多个;实在不行给 Docker 单独配代理。

13.2 Zabbix 6.4 源码包 404 下载失败

  • 报错:wget ... zabbix-6.4.15.tar.gz → ERROR 404: Not Found;随后 tar 报 Cannot open: No such file or directory。
  • 原因:Zabbix 6.4 已 EOL,官方 stable 目录整个下架,现仅保留 6.0、7.0、7.4 分支。
  • 解决:改用 6.0 LTS 最新版 6.0.47(对 CentOS 7.9 + PHP 7.4 最友好):
    bash VER=6.0.47 wget https://cdn.zabbix.com/zabbix/sources/stable/6.0/zabbix-${VER}.tar.gz

13.3 ${VER} 变量丢失导致 cd 失败

  • 现象:cd /data/zabbix/zabbix-${VER} 报 No such file or directory,路径里 ${VER} 未展开或为空。
  • 原因:VER=... 是当前 shell 的临时变量,换终端 / 新开会话就没了;或上一步 wget 失败根本没解压出目录。
  • 解决:wget、tar、cd 保持在同一次会话连续执行;换窗口后先重新 VER=6.0.47。

13.4 前端 nginx 报 403(directory index forbidden)

  • 报错(nginx error.log):directory index of "/data/zabbix/web/" is forbidden
  • 原因:nginx 配置生效、root 正确,但目录下没有 index.php → 退化成列目录被拒。根因是前端文件没拷对(目录空,或多套了一层 ui/)。
  • 解决:
    bash ls -l /data/zabbix/web/index.php # 确认入口文件在不在 # 若文件在 web/ui/ 下(多一层),拉平: cp -r /data/zabbix/web/ui/* /data/zabbix/web/ && rm -rf /data/zabbix/web/ui
  • 附:编译版 nginx(/usr/local/nginx)用 nginx -T | grep "listen 8080" 确认配置真的加载了;文件属主改成 php-fpm 运行用户,/data /data/zabbix /data/zabbix/web 每层 755。

13.5 安装向导预检查 PHP 项失败

  • 现象:预检查页 max_input_time 当前 60、要求 300、失败(其余 PHP 项同理)。
  • 解决:改 php.ini(php -i | grep "Loaded Configuration File" 定位实际文件),按 §8.6 的表调好 max_execution_time / max_input_time / post_max_size / upload_max_filesize / memory_limit / date.timezone,然后 systemctl restart php-fpm(不重启不生效),刷新页面重试。

13.6 配置数据库连接:未找到表 dbversion

  • 报错(向导):无法确定当前 Zabbix 数据库版本:未找到表 "dbversion"。
  • 理解:这是能连上库、但库是空的(schema 没导入)——网络/账号/密码其实都是通的。
  • 解决:回监控服务器执行 §8.3 导入 schema,导入成功后向导「下一步」即过。

13.7 schema 导入报 ERROR 1419(SUPER privilege)

  • 报错:ERROR 1419 (HY000) at line 2124: You do not have the SUPER privilege and binary logging is enabled ...
  • 原因:MySQL 开了 binlog,导入触发器/存储过程需要 log_bin_trust_function_creators=1,容器创建时漏了该参数。
  • 解决(注意已导入半截,要删库重建再导):
    bash # 1) root 打开开关(动态生效) docker exec -i monitor-mysql mysql -uroot -p'ChangeMe_Root@2026' \ -e "SET GLOBAL log_bin_trust_function_creators=1;" # 2) 删库重建 docker exec -i monitor-mysql mysql -uroot -p'ChangeMe_Root@2026' \ -e "DROP DATABASE zabbix; CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;" # 3) 重新导入 schema→images→data cd /data/zabbix/zabbix-6.0.47/database/mysql cat schema.sql images.sql data.sql | \ docker exec -i monitor-mysql mysql -uzabbix -p'Zabbix_Pass@2026' zabbix
  • 根治:docker run 时带 --log_bin_trust_function_creators=1(§5.1)。

13.8 安装向导最后一步:无法创建配置文件

  • 报错(向导):无法创建配置文件,提示手动保存为 /data/zabbix/web/conf/zabbix.conf.php。
  • 原因:php-fpm 用户对 web/conf/ 目录无写权限。
  • 解决(二选一):
  • A:mkdir -p /data/zabbix/web/conf && chown -R <php-fpm用户> /data/zabbix/web/conf && chmod 755 ... 后点「完成」;装完 chmod 644 conf/zabbix.conf.php 收回权限。
  • B:点「下载配置文件」,scp 到 /data/zabbix/web/conf/ 再点「完成」。

13.9 前端部署在远程 nginx 主备集群的要点

本次前端未装在监控服务器,而是放在已有业务的 nginx 主备集群上,要点:

  1. php-fpm 必须与 nginx 同机(从本地磁盘读 PHP 文件),所以主备两台都要部署 ui/* + php-fpm,配置一致。
  2. fastcgi_pass 指向 nginx 本机的 php-fpm(127.0.0.1:9000),不是监控服务器。
  3. 向导里 Database host / Zabbix server host 填监控服务器内网 IP(如 172.16.1.30),不是 localhost。
  4. 监控服务器防火墙 / 云安全组要放行 3306、10051 给主、备两台 IP(含 VIP)。
  5. 生成的 zabbix.conf.php 手动同步到另一台:scp .../conf/zabbix.conf.php root@<备机>:/data/zabbix/web/conf/,否则切到备机会重新弹安装向导。
  6. 会话默认存 php 本地,主备切换后需重新登录一次(数据不丢);要无感切换需共享 session(DB/Redis),非强需求不建议一开始就上。
  7. 编译版 nginx 配置在 /usr/local/nginx/conf/,改动前先备份(这台有 one.ixiaozu.cn 等线上业务),nginx -t 通过再 reload。

13.10 登录后提示 "Zabbix server is not running"

  • 现象:前端能登录(Admin / zabbix),但顶部红字告警 server 未运行。
  • 原因:前端只是 Web,后端 zabbix_server 进程还没启动。
  • 解决:在监控服务器按 §8.4 配好 zabbix_server.conf、§8.5 systemctl enable --now zabbix-server,红字即消失。

13.11 Grafana 装插件报 permission denied

  • 报错:Failed to install plugin ... open /data/grafana/data/plugins: permission denied(Web 装插件 status=500)。
  • 原因:Grafana 以 grafana 用户运行,但 /data/grafana 目录属主是 root(用 root 建的目录),写不进去。
  • 解决:
    bash chown -R grafana:grafana /data/grafana chmod 755 /data /data/grafana systemctl restart grafana
    之后重装。用 CLI 装时也要 sudo -u grafana,否则又生成 root 属主文件;离线解压装完同样要 chown -R grafana:grafana。

13.12 Grafana 页面白屏 / Minified React error #130(插件与版本不兼容)

  • 报错:打开 Zabbix 插件页 An unexpected error happened + Minified React error #130,堆栈含 alexanderzobnin-zabbix-datasource/module.js。
  • 原因:Zabbix 插件版本与 Grafana 版本不兼容。查插件要求:
    bash grep -i grafanaDependency /data/grafana/data/plugins/alexanderzobnin-zabbix-app/plugin.json # 例:">=11.6.0-0",而当前 Grafana 11.1.0 < 11.6.0 → 崩溃
  • 解决(升级 Grafana,推荐;CentOS 7.9 升到刚好满足的 11.6.x,勿直接上 13.x):
    ```bash
    # 0) 备份(降级不可逆)
    cp -a /data/grafana/data /data/grafana/data.bak.$(date +%F)
    docker exec monitor-mysql mysqldump -uroot -p'ChangeMe_Root@2026' grafana \
    > /data/src/grafana-db-$(date +%F).sql # 若用 MySQL 后端

# 1) 下载并解压 11.6.0
cd /data/src
VER=11.6.0
wget https://dl.grafana.com/oss/release/grafana-${VER}.linux-amd64.tar.gz
tar -zxf grafana-${VER}.linux-amd64.tar.gz -C /data/grafana/
mv /data/grafana/grafana-v${VER} /data/grafana/grafana-${VER} 2>/dev/null
chown -R grafana:grafana /data/grafana/grafana-${VER}

# 2) systemd 指向新目录并重启
sed -i 's/grafana-11.1.0/grafana-11.6.0/g' /etc/systemd/system/grafana.service
systemctl daemon-reload && systemctl restart grafana

# 3) 验证(重点看 glibc)
systemctl status grafana --no-pager | head -8
journalctl -u grafana -n 40 --no-pager | grep -iE "GLIBC|error|version"
`` - **若报GLIBC_2.xx not found**:说明该 Grafana 版本在 CentOS 7 跑不了,回滚(把 sed 改回grafana-11.1.0)并改走「降插件版本」:grafana cli plugins install alexanderzobnin-zabbix-app <兼容旧版>。 - **注意**:升级 Grafana 只换自身二进制,/data/grafana/data(仪表盘/插件/配置)保留;**不影响 Zabbix、Prometheus**(Grafana 只是通过数据源读它们的数据)。改完记得**强刷浏览器**清缓存。 - **本次实测**:CentOS 7.9 升级到 **Grafana 11.6.0 正常运行,无 GLIBC 报错**,插件页恢复正常。启动日志里的Adding GroupVersion ... to ResourceManager是 11.x 新架构的正常输出;升级后浏览器旧会话会出现401 token needs to be rotated`,强刷/重新登录即可,非故障。

13.13 Grafana 仪表盘全是 N/A / No data

按数据流 agent → Server → MySQL → API → Grafana 从上游往下逐层排查:

  1. 只读账号权限没生效(最隐蔽):现象是数据源 Save&test 成功,但仪表盘 Host 下拉空、全 N/A。原因是给用户配主机权限的位置错了——Zabbix 提示「权限只能被指派给用户群组」,必须在 用户 → 用户群组 → 该群组 → 主机权限 里对主机组授 读(Read),在"用户"页配无效。
  2. 顶部变量级联没选:Group 和 Host 是级联的,先选 Group,Host 才有值;不选 Host 全 N/A。总览页 Host 要选 All。
  3. 社区仪表盘 item 名不匹配:从 grafana.com 导入的老仪表盘(如葡语 Uso de CPU 那种)panel 写死的 item 名和 Zabbix 6.0 Linux by Zabbix agent 模板(Linux: CPU idle time 等)对不上,全 N/A。用本文档随附的定制模板,或用 Explore(Item 填 /.*/)确认真实 item 名后在 panel 里重选。
  4. 验证数据链路:Grafana 左侧 Explore → 数据源 Zabbix → Group/Host 选好 → Item /.*/,能列出几十个 item 并出数据,即证明链路 100% 正常,问题必在仪表盘(变量或 item 名)。
  5. 时间范围:Last 5 minutes 有时擦边,拉到 Last 1 hour。

13.14 MySQL 容器死循环重启(my.cnf 日志目录权限)

  • 现象:docker logs monitor-mysql 反复打印 Entrypoint script for MySQL Server 8.0.46 started. + Switching to dedicated user 'mysql',每 30 秒一次,无任何错误信息
  • 原因:my.cnf 里把 log_error 指向了 /var/log/mysql/error.log,但容器内该目录不存在或非 root 用户无写权限。MySQL 切换到 mysql 用户后写日志失败,直接退出,restart: always 又拉起,形成死循环
  • 解决:从 my.cnf 删除 log_error 配置项,让 MySQL 错误日志走 stderr(docker logs 直接看);慢查询日志放 /var/lib/mysql/slow.log(数据卷里,一定有写权限,MySQL 自动创建文件)
  • 延伸:如果非要把日志挂到宿主机,需提前 mkdir -p /data/db/mysql-log && chown 999:999 /data/db/mysql-log(mysql 用户 uid=999),并在 docker-compose 里加 - /data/db/mysql-log:/var/log/mysql。CentOS 7 若 SELinux 是 Enforcing 还需 chcon -Rt svirt_sandbox_file_t /data/db/mysql-log,否则即使属主对了也写不进去

13.15 MySQL 启动报 Different lower_case_table_names settings

  • 报错:[ERROR] [MY-011087] Different lower_case_table_names settings for server ('1') and data dictionary ('0'). + Data Dictionary initialization failed
  • 原因:my.cnf 里设了 lower_case_table_names = 1,但原有数据是用默认值 0 初始化的。MySQL 8.0 不允许在已有数据上改这个值(5.7 可以,8.0 改了数据字典机制)
  • 解决:从 my.cnf 删除(或注释掉)lower_case_table_names 配置项,保持默认 0
  • 延伸:如果业务强需求 lower_case_table_names = 1(如表名大小写不敏感),只能在首次初始化时设——即清空 /data/db/mysql 重新建库,所有数据丢失,仅适用于全新部署

13.16 MySQL 启动 warning:innodb_log_file_size / default_authentication_plugin 已弃用

  • 现象:MySQL 8.0.30+ 启动日志打印 warning,但不影响启动
  • 解决:用新参数替代
  • innodb_log_file_size = 512M → innodb_redo_log_capacity = 1G(8.0.30 起用单一参数替代 innodb_log_file_size × innodb_log_files_in_group)
  • default_authentication_plugin = mysql_native_password → authentication_policy = mysql_native_password
  • 注意:binlog_format 同样已弃用(MySQL 8.0 默认 ROW),保留不报错但可以删

13.17 Grafana 17320 仪表盘 CPU 使用率面板 No data

  • 现象:导入 17320 后大部分面板有数据,唯独 "CPU 使用率" 面板空白
  • 原因:该面板查询用了 node_cpu_seconds_total(来自 node_exporter),但仪表板的 $node_host 变量默认从 mysql_up metric 拉 instance,自然拉不到 node_exporter 的实例
  • 解决:Settings → Variables → 编辑 node_host:
  • Type: Query
  • Data source: Prometheus
  • Query type: Label values
  • Label: instance
  • Metric: node_uname_info(不是 mysql_up)
  • Label filters: 清空(删掉 vendor/account/group/name 这些 MySQL 专属标签)
  • Regex: /(.*:.*)/(保留默认)
  • 简化方案:单台机器直接用 Constant 类型,Value 填 172.16.1.30(你的 node_exporter IP)
  • 更优方案:导入独立的 Node Exporter 中文仪表盘 ID 8919,分两个仪表盘:17320 看 MySQL,8919 看主机资源,互不干扰

13.18 Node Exporter 中文仪表盘 ID 易混淆

  • 现象:导入 11074 后发现全是英文,不是预期的中文版
  • 原因:StarsL.cn 同作者出品了两个版本,名字相似容易搞错:
  • 11074 = Node Exporter Dashboard EN 20201010(英文版)❌
  • 8919 = Node Exporter for Prometheus Dashboard(中文版)✅
  • 解决:删掉 11074,重新导入 8919
  • 延伸:StarsL.cn 系列配套中文仪表盘(风格统一,推荐都用):
  • MySQL → 17320
  • 主机 → 8919
  • Redis → 17507

14. New API 主备集群(Docker)Prometheus 监控与钉钉告警

现状与前提
- New API 已通过 Docker 部署为主备集群(主、备两台节点,容器名 new-api),对外统一通过外网地址(域名 / 外网 VIP,本文以 https://newapi.example.com 为例)访问。
- 监控服务器上尚未安装 Alertmanager,本章包含它从零安装的完整流程(§14.4)。
- 本章只新增监控与告警,不改动任何已有 New API、MySQL、Redis、nginx 配置。

本章新增组件(除 cAdvisor / node_exporter 装在 New API 节点上,其余都装在监控服务器):

组件 部署方式 作用
blackbox_exporter Docker 经外网地址探测 /api/status(可用性 / 时延)
Alertmanager Docker(§14.4 新装) 告警分组、路由、静默、恢复通知
prometheus-webhook-dingtalk Docker(§14.4 新装) 把告警转成钉钉群机器人消息
cAdvisor + node_exporter(可选) Docker / 二进制 容器与主机资源指标
用户 ──► https://newapi.example.com ──► nginx 主备入口 ──► New API 主/备节点(Docker)

监控服务器 Prometheus
  ├── blackbox_exporter ──外网探测──► https://newapi.example.com/api/status  (统一入口链路)
  │                                ──► 主节点外网地址 /api/status            (定位单点故障)
  │                                ──► 备节点外网地址 /api/status
  ├── cAdvisor(可选)      ──► 两台节点 :8080    容器 CPU / 内存
  └── node_exporter(可选) ──► 两台节点 :9100    主机 CPU / 内存 / 磁盘

告警链路:Prometheus ──告警规则──► Alertmanager ──webhook──► 钉钉适配器 ──► 钉钉群机器人
展示链路:Grafana ──► Prometheus

为什么用黑盒探测而不是应用内部指标:不依赖 New API 版本内部的指标名,应用升级不会导致监控失效;探测走外网地址,覆盖 DNS → nginx 主备 → 后端容器的完整真实访问链路,与用户实际体验一致。

14.1 部署 blackbox_exporter(黑盒探测,监控服务器)

blackbox_exporter 部署在监控服务器,由它经外网向 New API 的 /api/status 发起探测。先确认监控服务器能访问外网目标:

curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' https://newapi.example.com/api/status
# 期望输出:200 0.xxxs

(1)创建探测模块配置

sudo mkdir -p /data/blackbox-exporter/conf
sudo tee /data/blackbox-exporter/conf/blackbox.yml >/dev/null <<'EOF'
modules:
  newapi_status:
    prober: http
    timeout: 10s
    http:
      method: GET
      valid_status_codes: [200]
      fail_if_body_not_matches_regexp:
        - '"success"[[:space:]]*:[[:space:]]*true'
EOF

sudo docker run -d \
  --name blackbox-exporter \
  --restart unless-stopped \
  --network host \
  -v /data/blackbox-exporter/conf/blackbox.yml:/config/blackbox.yml:ro \
  quay.io/prometheus/blackbox-exporter:latest \
  --config.file=/config/blackbox.yml

容器用 --network host,监听 9115。探测走外网,要求宿主机 DNS 与外网出口正常;quay.io 拉取慢可先配镜像加速(§4.2)。

验证(应返回 probe_success 1):

curl -s 'http://127.0.0.1:9115/probe?target=https://newapi.example.com/api/status&module=newapi_status' | grep probe_success

14.2(可选)在两台 New API 节点部署 cAdvisor + node_exporter

(1)cAdvisor(容器指标)

docker run -d \
  --name cadvisor \
  --restart unless-stopped \
  --privileged \
  --network host \
  -v /:/rootfs:ro \
  -v /var/run:/var/run:rw \
  -v /sys:/sys:ro \
  -v /var/lib/docker:/var/lib/docker:ro \
  swr.cn-north-4.myhuaweicloud.com/ddn-k8s/gcr.io/cadvisor/cadvisor:v0.49.1

(2)node_exporter(主机指标)

两台节点按 §6.5 安装并启动 node_exporter(监听 9100)。

⚠️ 这两类采集是 Prometheus 直连节点 IP:端口。若监控服务器与 New API 节点之间只能走外网,需改用节点外网 IP,并在安全组 / 防火墙仅对监控服务器出口 IP 放行 8080(cAdvisor)和 9100(node_exporter)。若网络策略不允许,可整节跳过:可用性告警不受影响,只是少了容器 / 主机资源面板。

14.3 Prometheus 增加采集任务与告警规则

在 /data/prometheus/conf/prometheus.yml 顶部已有配置后补充以下内容。请把占位符替换为实际的外网地址:

  • https://newapi.example.com → New API 统一入口域名(用户实际访问地址)
  • <主节点外网地址> / <备节点外网地址> → 两台节点各自的外网访问地址(外网 IP 或域名,含端口)

alerting 指向的 127.0.0.1:9093(Alertmanager)将在 §14.4 安装,先配上即可,装完自动生效。

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['127.0.0.1:9093']

rule_files:
  - /data/prometheus/conf/rules/newapi-alerts.yml

scrape_configs:
  # ……保留原有 prometheus、node 等 job ……

  # 分别探测主、备 New API 节点;可定位是哪台异常
  - job_name: blackbox-newapi-node
    metrics_path: /probe
    params:
      module: [newapi_status]
    static_configs:
      - targets:
          - http://<主节点外网地址>/api/status     # 如 http://1.2.3.4:3000/api/status
          - http://<备节点外网地址>/api/status     # 如 http://5.6.7.8:3000/api/status
        labels:
          service: newapi
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9115

  # 探测用户实际访问的 nginx VIP/域名,验证完整入口链路
  - job_name: blackbox-newapi-vip
    metrics_path: /probe
    params:
      module: [newapi_status]
    static_configs:
      - targets: ['https://newapi.example.com/api/status']
        labels:
          service: newapi
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9115

  # 以下两个 job 仅当按 §14.2 部署了 cAdvisor / node_exporter 时才配置
  - job_name: cadvisor-newapi
    static_configs:
      - targets: ['<主节点IP>:8080', '<备节点IP>:8080']

  - job_name: node-newapi
    static_configs:
      - targets: ['<主节点IP>:9100', '<备节点IP>:9100']

创建规则目录与告警规则文件:

sudo mkdir -p /data/prometheus/conf/rules
sudo tee /data/prometheus/conf/rules/newapi-alerts.yml >/dev/null <<'EOF'
groups:
  - name: newapi-alerts
    rules:
      - alert: NewApiNodeDown
        expr: probe_success{job="blackbox-newapi-node"} == 0
        for: 2m
        labels:
          severity: critical
          service: newapi
        annotations:
          summary: "New API 节点不可用"
          description: "{{ $labels.instance }} 的 /api/status 连续 2 分钟探测失败。"

      - alert: NewApiAllNodesDown
        expr: sum(probe_success{job="blackbox-newapi-node"}) < 1
        for: 1m
        labels:
          severity: critical
          service: newapi
        annotations:
          summary: "New API 主备节点全部不可用"
          description: "主、备节点均未通过 /api/status 健康检查。"

      - alert: NewApiVipDown
        expr: probe_success{job="blackbox-newapi-vip"} == 0
        for: 2m
        labels:
          severity: critical
          service: newapi
        annotations:
          summary: "New API 统一访问入口不可用"
          description: "{{ $labels.instance }} 连续 2 分钟探测失败,请检查 nginx VIP、DNS、证书和后端。"

      - alert: NewApiHighLatency
        expr: probe_duration_seconds{job=~"blackbox-newapi-node|blackbox-newapi-vip"} > 3
        for: 5m
        labels:
          severity: warning
          service: newapi
        annotations:
          summary: "New API 健康检查响应慢"
          description: "{{ $labels.instance }} 响应时长 {{ $value | printf \"%.2f\" }} 秒,持续超过 3 秒。"

      - alert: NewApiCadvisorDown
        expr: up{job="cadvisor-newapi"} == 0
        for: 3m
        labels:
          severity: warning
          service: newapi
        annotations:
          summary: "New API 节点 cAdvisor 不可达"
          description: "{{ $labels.instance }}:8080 无法采集 Docker 容器指标。"

      - alert: NewApiHostCpuHigh
        expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{job="node-newapi",mode="idle"}[5m])) * 100) > 90
        for: 10m
        labels:
          severity: warning
          service: newapi
        annotations:
          summary: "New API 节点 CPU 使用率过高"
          description: "{{ $labels.instance }} CPU 使用率持续 10 分钟高于 90%。"

      - alert: NewApiHostMemoryHigh
        expr: (1 - node_memory_MemAvailable_bytes{job="node-newapi"} / node_memory_MemTotal_bytes{job="node-newapi"}) * 100 > 90
        for: 10m
        labels:
          severity: warning
          service: newapi
        annotations:
          summary: "New API 节点内存使用率过高"
          description: "{{ $labels.instance }} 内存使用率持续 10 分钟高于 90%。"
EOF

sudo -u prometheus /data/prometheus/prometheus-2.53.0/promtool check config /data/prometheus/conf/prometheus.yml
sudo systemctl reload prometheus

prometheus.yml 只能保留一个顶层 scrape_configs、alerting 和 rule_files。若已有同名顶层项,将本节相应内容合并进去,不要重复创建。

在 Prometheus 的 Status → Targets 中确认 blackbox-newapi-node、blackbox-newapi-vip(以及可选的 cadvisor-newapi、node-newapi)均为 UP。

14.4 安装 Alertmanager 与钉钉告警适配器(本次新装)

监控服务器上尚未安装 Alertmanager,本节是从零安装的完整流程。告警链路由两个容器组成:

  • Alertmanager:接收 Prometheus 推送的告警,负责分组、去重、路由、恢复通知;
  • prometheus-webhook-dingtalk:Alertmanager 通过通用 Webhook 调用它,它再按钉钉机器人协议(支持加签 secret)把消息发到群里。参考:Prometheus 官方 Webhook 集成说明、适配器项目。

14.4.1 创建钉钉自定义机器人

在目标钉钉群:群设置 → 智能群助手 → 添加机器人 → 自定义机器人。

  • 安全设置建议选加签,复制 Webhook URL 与 SEC... 密钥;若公司策略要求,也可同时设置关键字 Prometheus。
  • 不要把 URL 或 SEC 密钥提交到 Git、截图或公开文档。

14.4.2 创建目录与配置文件

在监控服务器执行:

sudo mkdir -p /data/alertmanager/{conf,data}
sudo mkdir -p /data/dingtalk/conf

创建 /data/dingtalk/conf/config.yml:

targets:
  newapi:
    url: https://oapi.dingtalk.com/robot/send?access_token=<钉钉机器人Token>
    secret: SEC<钉钉机器人加签密钥>

创建 /data/alertmanager/conf/alertmanager.yml:

global:
  resolve_timeout: 5m

route:
  receiver: dingtalk-newapi
  group_by: [alertname, service, instance]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h

receivers:
  - name: dingtalk-newapi
    webhook_configs:
      - url: http://dingtalk-webhook:8060/dingtalk/newapi/send
        send_resolved: true

14.4.3 编写 docker-compose.yml(Alertmanager + 钉钉适配器)

创建 /data/alertmanager/docker-compose.yml:

services:
  alertmanager:
    image: quay.io/prometheus/alertmanager:latest
    container_name: alertmanager
    restart: unless-stopped
    ports:
      - "127.0.0.1:9093:9093"
    volumes:
      - /data/alertmanager/conf/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
      - /data/alertmanager/data:/alertmanager
    command:
      - --config.file=/etc/alertmanager/alertmanager.yml
      - --storage.path=/alertmanager
      - --web.enable-lifecycle
    depends_on:
      - dingtalk-webhook

  dingtalk-webhook:
    image: timonwong/prometheus-webhook-dingtalk:v2.1.0
    container_name: dingtalk-webhook
    restart: unless-stopped
    volumes:
      - /data/dingtalk/conf/config.yml:/etc/prometheus-webhook-dingtalk/config.yml:ro
    command:
      - --config.file=/etc/prometheus-webhook-dingtalk/config.yml
      - --web.enable-ui

14.4.4 启动、校验并接入 Prometheus

cd /data/alertmanager
docker compose up -d
docker ps --filter name=alertmanager --filter name=dingtalk-webhook

# 配置校验(应输出 SUCCESS)
docker exec alertmanager amtool check-config /etc/alertmanager/alertmanager.yml

# 确认 prometheus.yml 已含 alerting 配置(§14.3 已加),并重载生效
grep -A3 '^alerting' /data/prometheus/conf/prometheus.yml
curl -X POST http://localhost:9090/-/reload

# Prometheus 侧确认告警链路:
#   http://<监控服务器IP>:9090/alerts                 查看规则状态
#   http://<监控服务器IP>:9090/api/v1/alertmanagers   应能看到 127.0.0.1:9093
# Alertmanager 自身 Web UI(仅监听本机,需 SSH 转发或在服务器本地访问):
#   http://127.0.0.1:9093

14.4.5 告警链路测试(验证钉钉通知)

临时停止主节点 new-api 容器,等待 2 分钟,钉钉群应收到 NewApiNodeDown;若同时停掉备节点,1 分钟后应收到 NewApiAllNodesDown。随后恢复容器,应收到恢复通知。

# 在对应 New API 节点执行,测试完成立即恢复
docker stop new-api
docker start new-api

14.5 Grafana 展示与常用 PromQL

Grafana 添加(或复用)Prometheus 数据源后,新建 New API 主备集群监控 仪表盘。推荐面板:

面板 PromQL
主备节点可用性 probe_success{job="blackbox-newapi-node"}
VIP/域名可用性 probe_success{job="blackbox-newapi-vip"}
健康检查响应时延 probe_duration_seconds{job=~"blackbox-newapi-node|blackbox-newapi-vip"}
New API 容器 CPU sum by (instance) (rate(container_cpu_usage_seconds_total{job="cadvisor-newapi",name=~".*new-api.*"}[5m])) * 100
New API 容器内存 sum by (instance) (container_memory_working_set_bytes{job="cadvisor-newapi",name=~".*new-api.*"})
节点 CPU 使用率 100 - avg by (instance) (rate(node_cpu_seconds_total{job="node-newapi",mode="idle"}[5m])) * 100
节点内存使用率 (1 - node_memory_MemAvailable_bytes{job="node-newapi"} / node_memory_MemTotal_bytes{job="node-newapi"}) * 100

14.6 运维检查清单

# 两节点:确认容器健康、查看日志
docker ps --filter name=new-api
docker logs --tail=100 new-api
curl -s http://127.0.0.1:3000/api/status

# Prometheus 服务器:确认黑盒探测自身可用
curl -G 'http://127.0.0.1:9115/probe' \
  --data-urlencode 'target=https://newapi.example.com/api/status' \
  --data-urlencode 'module=newapi_status'

# 配置变更后验证并热加载 Prometheus
sudo -u prometheus /data/prometheus/prometheus-2.53.0/promtool check config /data/prometheus/conf/prometheus.yml
sudo systemctl reload prometheus

附:版本对照(本文所用)

组件 版本
操作系统 CentOS 7.9.2009 (x86_64)
Docker CE 最新稳定
MySQL 8.0
Prometheus 2.53.0
node_exporter 1.8.1
mysqld-exporter v0.16.0
blackbox_exporter 官方稳定版(生产固定镜像标签)
cAdvisor 官方稳定版(生产固定镜像标签)
Alertmanager 官方稳定版(生产固定镜像标签)
钉钉适配器 prometheus-webhook-dingtalk v2.1.0
New API calciumion/new-api(生产固定镜像标签)
Grafana 11.6.0(需 ≥ 插件 grafanaDependency;CentOS 7.9 勿上 13.x)
Zabbix 6.0.47 LTS(6.4 已 EOL 下架)
gcc(编译用) 9(devtoolset-9)
PHP(前端用) 7.4(Remi 源)

⚠️ 文档中所有密码(ChangeMe_Root@2026、Zabbix_Pass@2026、Grafana_Pass@2026、Monitor_Pass@2026)为示例,上线前务必替换为强密码,并妥善保管。