1. 方案选型:为什么是 Docker + Zabbix
这两年代维的项目多了之后,我对监控系统的要求就三个:部署快、升级稳、恢复容易。以前手工装 Zabbix 的日子我是真不想再回去了,PHP 依赖、Apache 配置、MySQL 初始化、前端文件权限,一套下来少说俩小时,中间任何一个环节报错,排查起来都让人头皮发麻。后来全面切到 Docker 部署之后,同样的环境我从零到能用,十分钟以内搞定,这个差距是非常直观的。
Zabbix 本身是企业级监控里非常成熟的方案,能监控服务器、容器、网络设备、数据库,甚至连 Windows 上的 GPU 状态都能通过 agent 采集。它最大的优势是生态完整,模板库非常丰富,常见的 Linux、Windows、MySQL、Redis、NGINX 都有现成模板,导入就能用,不需要像 Prometheus 那样从 exporter 开始一项项配。但要发挥它的能力,前提是你得先有一个跑得起来的 Server。如果你卡在安装这一步,后面所有监控需求都无从谈起。
所以我在这篇文章里只聚焦一件事:用 Docker Compose 把 Zabbix Server、Zabbix Web、MySQL 数据库和 Agent 一次性编排起来,实现一套开箱即用的企业级监控告警平台。你会得到什么:一个干净的 Web 界面,一套能自动发现主机、采集指标、触发告警的完整链路,以及后续加机器、改告警都只用改配置文件的运维体验。
这套方案适合谁?适合刚接触 Zabbix 想快速上手的人,适合公司内部需要一套正经监控但又不想养一个专职运维的团队,也适合已经在用 Zabbix 但还在裸机部署、每次升级都心惊胆战的老手。Docker 在这里不是炫技,而是把 Zabbix 部署从“搬砖”变成“填空”。
1.1 容器化部署对比传统安装的差异
传统安装 Zabbix 最麻烦的点在于依赖关系。Zabbix Server 要连数据库,Zabbix Web 要跑 PHP,PHP 又要装一堆扩展,甚至不同版本对 PHP 版本还有要求。我在 CentOS 7 上装 Zabbix 6.0 的时候就碰到过系统自带的 PHP 5.4 完全不兼容,只能额外装 Software Collections 的 PHP 7.2,这还只是其中一环。如果是在一台已经跑着其他业务的机器上来装,还要担心会不会把系统已有的 PHP 或者 MySQL 版本搞坏。
用容器化部署,相当于把 Zabbix Server、Web、数据库各自关进了一个“打包好的集装箱”里。每个容器只包含它运行所必需的环境,互相不干扰。升级的时候拉一个新镜像重新起容器就行,回滚也简单到离谱——把镜像 tag 指回旧版本。数据放在宿主机挂载的卷里,不会因为容器重建就丢。
容器化带来的另一个好处是环境一致性。你在自己电脑上测试通过的编排文件,拿到生产环境基本是同样效果。我实际遇到过因为服务器系统版本不同导致编译安装失败的场景,但同样的 docker-compose.yml 在 Ubuntu、Debian、CentOS 上跑出来的结果几乎没有差别,这就是容器化的价值。
1.2 从零到可用的三种部署路径对比
网上关于 Zabbix Docker 部署的教程不算少,但方案各异,我整理下来主要分三类,选择的时候可以参考自己的实际场景。
第一种是直接用 docker run 一条条命令起容器。这种方式适合只做功能验证、临时测试的场景。缺点很明显:参数太长容易写错,容器之间的依赖关系要靠手工控制启动顺序,一不小心数据库还没就绪 Server 就起来了,然后报一大堆连接错误。
第二种是使用 Docker Compose 编排,这也是我在文章里推荐的方式。所有服务写在一个 YAML 文件里,依赖关系、网络、数据卷都声明式管理。一条 docker compose up -d 就把整套平台拉起来,后续扩容也只需要改配置再执行一次。生产环境用这个方式足够。
第三种是使用 Zabbix 官方提供的容器化部署脚本或者 Kubernetes Helm Chart。这适合已经上了容器编排平台、有专门运维工具链的团队。如果你平时管着几十上百台机器,K8s 方式更合适;但如果你只需要一两套监控环境,引入 K8s 反而是过度设计。
我的建议:除非你只是为了看一眼界面,否则不要用 docker run 一个个敲。Compose 文件写一次可以重复用,而且它本身就是你的“部署文档”,换机器的时候拷贝过去就能跑,这才是 Docker 方案最值钱的地方。
2. 环境准备与编排文件解析
动手之前先把环境确认好,这一步能避免后面大量踩坑。我用的是 Docker Engine 20.10 以上的版本,Docker Compose V2 插件式版本。检查方法很简单,终端里执行 docker --version 和 docker compose version,能看到正常输出就说明环境没问题。
资源方面,Zabbix 的消耗和监控规模直接挂钩。我自己的经验:一台 2 核 4G 内存的机器,跑这套方案同时监控二三十台主机完全没压力。如果监控的目标上百,或者采集频率调得很高,建议至少 4 核 8G。硬盘主要留给数据库,历史数据会持续增长,我给 MySQL 的 volume 预留了 50G,一般中小团队用几个月没问题,后续也可以单独对历史数据做保留周期控制。
操作系统不用太纠结,Ubuntu 22.04、Debian 12、CentOS 7.9 我都验证过。需要注意的是 CentOS 7 的 Docker 版本可能偏旧,建议先升级 docker-ce 到最新版本再继续。Windows 上用 Docker Desktop 也能跑通,但文件挂载和网络模式有些差异,生产环境我还是推荐 Linux。
2.1 镜像选型:zabbix-server-mysql 还是 zabbix-server-pgsql
Zabbix 官方镜像分了好几个版本,最大的分叉在于后端数据库。zabbix-server-mysql 和 zabbix-server-pgsql 分别对应 MySQL 和 PostgreSQL,另外还有支持 TimescaleDB 的版本。选哪个?如果完全没有历史包袱,我建议直接上 PostgreSQL,它在处理时间序列数据方面表现更好,特别是历史数据和趋势数据量大的时候。但如果你公司已经有 MySQL 运维体系,或者你本人对 MySQL 更熟,那选 MySQL 版本也完全没问题,功能上没有差别。
这里要强调一点:Zabbix 6.0 之后官方对 TimescaleDB 的支持越来越完善,如果你的监控指标数量很多、历史数据保留时间又长,TimescaleDB 版本值得尝试。它能自动按时间分块压缩数据,查询性能比裸 PostgreSQL 明显好。代价是运维复杂度稍高一些。对于中小型场景,默认 PostgreSQL 或 MySQL 版本已经足够。
镜像 tag 建议用具体的版本号,比如 zabbix/zabbix-server-mysql:6.0.31-ubuntu,而不是用 latest。latest 会跟着官方滚动更新,哪天你重新拉镜像发现版本变了,Zabbix 前端和 Server 版本不一致,就会出现各种奇怪问题。固定版本号是生产环境的基本素养,升级是你主动决定的事,而不是意外。
2.2 docker-compose.yml 逐段图解
我直接把我现在用的这套编排文件贴出来,版本是 Zabbix 6.0,数据库用的 MySQL 8.0。你可以直接复制使用,再根据实际环境调整密码和端口。
version: '3.8' services: mysql-server: image: mysql:8.0 container_name: zabbix-mysql command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_bin - --default-authentication-plugin=mysql_native_password environment: MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pwd MYSQL_ROOT_PASSWORD: root_pwd volumes: - ./data/mysql:/var/lib/mysql restart: always healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot_pwd"] interval: 10s timeout: 5s retries: 5 zabbix-server: image: zabbix/zabbix-server-mysql:6.0.31-ubuntu container_name: zabbix-server environment: DB_SERVER_HOST: mysql-server DB_SERVER_PORT: 3306 MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pwd ZBX_STARTPOLLERS: 10 ZBX_STARTPREPROCESSORS: 5 ZBX_CACHESIZE: 256M ZBX_HISTORYCACHESIZE: 128M ZBX_TRENDCACHESIZE: 128M ports: - "10051:10051" depends_on: mysql-server: condition: service_healthy restart: always volumes: - ./data/alertscripts:/usr/lib/zabbix/alertscripts - ./data/externalscripts:/usr/lib/zabbix/externalscripts zabbix-web: image: zabbix/zabbix-web-nginx-mysql:6.0.31-ubuntu container_name: zabbix-web environment: ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_PORT: 10051 DB_SERVER_HOST: mysql-server MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pwd PHP_TZ: Asia/Shanghai ports: - "80:8080" depends_on: zabbix-server: condition: service_started mysql-server: condition: service_healthy restart: always这个文件里我重点解释几个关键点,因为它们是你后面排查问题的重点。
MySQL 的 command 参数里,utf8mb4 字符集是必须的,否则 Zabbix 前端如果配置了中文,保存中文类型的资产信息时可能出乱码。default-authentication-plugin 设置成 mysql_native_password 是为了兼容 Zabbix 6.0 的数据库连接方式,MySQL 8.0 默认的 caching_sha2_password 在一些老版本驱动下会认证失败,这个坑我不止一次见过。
healthcheck 这一段值得单独说。Zabbix Server 启动必须先等 MySQL 完全就绪,否则连接数据库失败后容器可能会陷入重启循环。没有 healthcheck 的 depends_on 只是控制启动顺序,不保证依赖服务可用。我用 mysqladmin ping 做健康检查,Compose 只有确认数据库健康后才会启动 zabbix-server,这套机制可以省掉你 90% 的“容器起不来”问题。
web 服务映射的端口,我把容器的 8080 映射到宿主机 80,这样直接用 IP 访问就能打开前端,不用带端口号。如果你宿主机 80 已经被占用,改成 8080:8080 也行,只是访问的时候要带上端口。
2.3 数据卷与可维护性设计
编排文件里我特意把 MySQL 数据挂载到宿主机 ./data/mysql 目录下,这是整套方案里绝对不能省的一步。如果数据库容器因为升级、崩溃、或者机房断电被删掉了,只要这个目录还在,你的历史监控数据、主机配置、告警规则就都还在。我见过有人为了省事不挂数据卷,结果容器重建之后整个监控平台从零开始,那种痛我不希望你再体会一次。
alertscripts 和 externalscripts 这两个挂载目录是给自定义脚本用的。企业监控后期总会遇到一些特殊需求,比如调用第三方接口发告警、写自定义脚本来采集专有指标。官方容器镜像里自带目录,但容器重建后文件会被清空。挂在宿主机上,脚本和容器生命周期解耦,维护起来才顺手。
关于备份,我的习惯是直接备份 ./data 整个目录,同时每周用 mysqldump 导出一份逻辑备份。逻辑备份的好处是可以恢复到任意版本的 Zabbix,目录备份虽然快但依赖 MySQL 版本兼容。两种都做,总没坏处。
3. 初始化部署:从空目录到有监控大屏
编排文件准备好之后,部署流程其实就剩下三步:建目录、起服务、初始化前端。我习惯在 /opt/zabbix 下面操作,路径选择看个人习惯,但建议不要放在 /tmp,重启可能被系统清理掉。
mkdir -p /opt/zabbix/data/mysql cd /opt/zabbix # 将上面的 docker-compose.yml 保存为 docker-compose.yml docker compose up -d第一次执行 docker compose up -d 的时候,Docker 会去拉取三个镜像:mysql:8.0、zabbix-server-mysql、zabbix-web-nginx-mysql。镜像体积都不小,尤其 Zabbix 的镜像几百 MB 很正常,网络状况不好时会拉比较久。国内服务器如果镜像拉取特别慢,可以给 Docker daemon 配置 registry-mirrors,用你所在网络环境下能访问的加速地址,配置完重启 Docker 再拉,速度会好很多。
镜像拉完,容器会按照依赖关系依次启动。MySQL 先起来做初始化,Zabbix Server 等数据库健康后开始建表、写入种子数据,这个过程通常会持续一到三分钟,取决于机器性能和数据库磁盘速度。第一次启动别急着访问前端,你先执行 docker logs -f zabbix-server 观察日志,看到类似 “server started” 或者不再有数据库连接报错,再继续下一步。
3.1 前端初始化和首次登录
浏览器打开 http://你的服务器IP,会进入 Zabbix 安装欢迎页。这个页面问你要数据库连接信息,按编排文件里的参数填就行:数据库主机填 mysql-server,数据库端口 3306,数据库名 zabbix,用户 zabbix,密码对应 MYSQL_PASSWORD。注意数据库主机要填 compose 里的服务名 mysql-server,不能填 localhost 或 127.0.0.1,因为 Web 容器和 MySQL 不在同一个网络命名空间里,localhost 指向的是 Web 容器自己。
填完数据库信息之后,Zabbix 会检查前置环境是否满足要求。容器化版本基本不会在这一步报错,因为官方已经在镜像里把所有 PHP 扩展件都配好了。跟着向导走完,前端提示你保存配置文件。官方镜像会自动把配置文件写入容器,不需要像裸机安装那样手工下载 zabbix.conf.php 再上传。最后一步是登录,默认账号 Admin,密码 zabbix。登录之后第一件事,去 Administration -> Users 里改密码,这个默认密码相当于把监控平台的钥匙挂在大门口,必须第一时间换掉。
到这里基础平台就算落成了。Zabbix 默认会带一个叫 Zabbix server 的本机监控,已经有一些内置监控项在跑数据。你会在 Dashboard 上看到系统负载、CPU 使用率这些曲线在慢慢出现,这就说明 Server、数据库、Web 三个组件协同工作正常,可以开始接被监控主机了。
3.2 调整时区、语言和基本外观
进入前端第一眼你可能Notice到时间不对或者界面是英文。时间是时区问题,虽然我在编排文件里设置了 PHP_TZ: Asia/Shanghai,但如果你是直接在旧版本镜像上改配置,或者镜像版本对时区处理方式有差异,可能仍然需要到 Administration -> General -> Time zone 里手动设置为 Asia/Shanghai。时区设置不正确,不仅前端显示的时间不对,告警邮件的发送时间、历史数据的落库时间也会跟着偏,排查问题的时候非常误导人。
中文界面的设置入口在 Administration -> Users -> Users,点击 Admin 用户,Language 选择 Chinese (zh_CN),保存后刷新页面就生效了。这里要注意,只有管理员账号能改全局语言,其他用户登录后默认还是跟随浏览器语言。个别时候中文字体没有完全加载,界面上会出现方块字,那是因为镜像缺少中文字体包,去 Zabbix Web 容器里装一下 fonts-noto-cjk 就可以了,命令是 docker exec -it zabbix-web bash -c "apt-get update && apt-get install -y fonts-noto-cjk",装完重启 web 容器。
至于大屏展示,Zabbix 6.0 之后自带多个 Dashboard 模板,例如 Problems、Hosts 概览这些,基本能满足日常监控展示需求。如果公司领导层需要投屏看大屏,建议单独分配一个只读用户,锁定到某个 Dashboard,避免有人在监控大屏上误操作了配置。
4. 接入第一台被监控主机与扩展监控方向
平台跑通之后,最有成就感的一步就是看到第一台主机的数据出现在界面上。Zabbix 监控主机最常用的方式是装 Agent,让 Agent 主动把数据上报给 Server,或者 Server 定时来拉取。Zabbix 6.0 推荐用 Zabbix Agent 2,它比经典 Agent 多了很多内置插件,采集 Redis、MySQL、Docker 这些目标时不需要额外写脚本,直接用官方插件就能出数据。
被监控主机上执行一条命令就能把 Agent 2 容器拉起来:
docker run -d --name zabbix-agent2 \ --network host \ -e ZBX_SERVER_HOST=192.168.1.100 \ -e ZBX_HOSTNAME=web-server-01 \ -e ZBX_SERVER_ACTIVE=192.168.1.100 \ -e ZBX_SERVER_PORT=10051 \ -e ZBX_HOSTNAME=web-server-01 \ -e ZBX_METADATA=linux \ -e ZBX_TIMEOUT=10 \ -e ZBX_ALLOWUNSUPPORTEDDBMODELS=1 \ -e ZBX_PASSIVE_ALLOW=true \ -e ZBX_ACTIVE_ALLOW=true \ zabbix/zabbix-agent2:6.0.31-ubuntu这里 --network host 直接使用了宿主机网络,Agent 和 Server 通信不需要经过端口映射和 NAT,速度和稳定性都更可靠。ZBX_SERVER_HOST 填你的 Zabbix Server 地址,如果是同一台机器就填内网 IP,不要填 localhost。ZBX_SERVER_ACTIVE 是让 Agent 主动连接 Server 进行主动检查的地址,配合 Zabbix 前端里的主动模式使用。两个都填上,被动检查和主动检查就都覆盖了。
然后回到 Zabbix 前端,在 Configuration -> Hosts -> Create host 里添加主机。主机名称写 web-server-01,这个名称必须和 Agent 容器里的 ZBX_HOSTNAME 保持一致,否则 Server 无法把收到的数据和这个主机关联起来。可见名称可以单独设置,用来展示更方便看的名字。然后点 Templates 选择模板,Linux 系统选 “Linux by Zabbix agent”,Windows 系统选 “Windows by Zabbix agent”,这些都是官方自带的,里面预置了 CPU、内存、磁盘、网络等几十个监控项和对应的触发器,等于装上模板之后告警规则也一起配好了。最后填上被监控机的 IP 和端口 10050,点 Add 完成添加。
等一两分钟,去 Monitoring -> Hosts 或 Latest Data 页面查看,如果能看到绿色的 ZBX 图标和不断变化的数据,说明 Agent 已经接入成功。如果一直是灰色或者没有数据,不要马上怀疑配置有问题,先检查宿主机防火墙有没有放通 10050 端口,这一条我排过的故障里占了一半。
4.1 用 SNMP 监控交换机与网络设备
Agent 只能装在能安装软件的机器上,交换机、路由器、防火墙这些网络设备没法装 Agent,这时候就用 SNMP 协议。Zabbix 对 SNMP 的支持非常成熟,官方模板库里有 Cisco、Huawei、H3C 等主流厂商的设备模板,添加方式和 Agent 类似,只是 Type 选择 SNMP,填上设备的 SNMP community string,默认一般是 public,生产环境建议改成私有字符串并限制管理网段访问。
配置完 SNMP 接口后,模板换成对应的网络设备模板,比如 “Cisco IOS by SNMP”。这些模板里已经定义好了接口流量、CPU 使用率、内存使用率等关键指标的 OID 和图形,不需要你手动去找 OID,这是 Zabbix 比自建监控方案强很多的地方。有一点要注意:SNMP v2c 的 community 在网络上明文传输,不要在公网环境直接暴露,用防火墙或 ACL 控制管理地址的访问权限。
4.2 Windows 主机和 GPU 监控的落地
Windows 主机接入同样用 Agent。在目标 Windows 机器上安装 Zabbix Agent 2 的 MSI 包,安装时把 Server 地址填正确,装完服务会自动注册并启动。前端添加主机时选 “Windows by Zabbix agent” 模板,基本不需要额外配置,CPU、内存、磁盘性能计数器就都能采集到。
不少做 AI 或者图形渲染的团队会关注 Windows 主机的 GPU 占用率。Zabbix Agent 2 从 6.0 开始内置了 NVIDIA GPU 插件,前提是 Windows 上装了 NVIDIA 驱动。在模板里搜索 Nvidia,找到对应的 GPU 监控模板添加到主机上,就能看到 GPU 利用率、显存占用、温度这些指标。这个功能实测下来效果不错,以前要人工登录服务器看显卡状态,现在直接在大屏上就能看到所有 GPU 服务器的负载情况,对资源调度很有帮助。
4.3 容器化环境自身的监控
用 Docker 跑 Zabbix,自然还要关注 Docker 本身的状态。Zabbix Agent 2 内置了 Docker 插件,配置好 Agent 的 docker socket 权限后,它可以直接读取本机的容器信息。在 Agent 2 容器的启动命令里加上 -v /var/run/docker.sock:/var/run/docker.sock,然后在前端把 Docker 模板加到 Zabbix Server 这台主机上,就能监控到每个容器的 CPU、内存、网络、状态变化。我在部署完平台后第一时间就把这个配置加上,等于整个监控系统拥有了自监控能力,系统挂没挂自己心里有数。
5. 企业告警配置:让平台真正“会说话”
很多团队把 Zabbix 部署起来、看到数据曲线在跑,就觉得完事了。其实监控平台的真正价值在告警。没有告警,你只会在系统已经宕机之后通过用户投诉才发现异常;有了合理的告警,你才能在故障发酵之前介入处理。Zabbix 的告警体系由三部分组成:监控项采集数据、触发器判断异常、动作发出通知。三者串联起来才是完整链路。
触发器是判断“这件事是否异常”的规则,它的核心就是表达式。比如监控 CPU 使用率是否过高,我会建一个触发器,表达式写成这样:
last(/Linux by Zabbix agent/system.cpu.util[,idle]) < 15这个表达式的意思是:当前 CPU 空闲时间占比小于 15%,即 CPU 使用率超过 85% 时触发告警。注意 Zabbix 的监控项名称和 key 过滤规则,在写表达式时使用的是模板和监控项 key,不是随便写个名字就行。官方模板自带的触发器已经覆盖了绝大多数常见场景,我建议新手不要急着自定义,先用默认模板里的规则跑起来,熟悉了之后再做精细化调整。
告警的中枢是动作。Configuration -> Actions -> Trigger actions 里创建一个动作,指定触发条件(就是选择哪些触发器),然后配置操作:给哪个用户或用户组发邮件、发什么内容、要不要执行远程命令。Zabbix 的操作步骤机制很实用,它可以设置第 1 步发送给一线值班人员,如果 10 分钟内问题没恢复,第 2 步升级给主管,第 3 步再通知到技术总监。这种分级通知机制,能避免告警轰炸,又能确保问题不被忽略。
5.1 邮件告警的两种主流方式
邮件告警是 Zabbix 最经典的通知方式。老版本的 Zabbix 通常用脚本来发邮件,运维人员需要自己在服务器上写 Python 或 Perl 脚本调用 SMTP 发送。Zabbix 5.0 之后,官方在 Media types 里原生支持了 SMTP 类型,直接配置 SMTP 服务器地址、端口、认证信息就能发邮件,不再依赖脚本,大幅度降低了配置门槛。
我推荐优先用原生的 SMTP 媒介类型。配置路径是 Administration -> Media types -> Email,填入你的 SMTP 服务器地址和端口,比如企业邮箱一般用 465 端口 SSL 加密,再填上邮箱账号和授权码。这地方需要说明的是,很多邮箱服务商要求用客户端授权码而不是登录密码,用密码会报认证失败,折腾半天最后发现是这个原因,非常不值。
邮件内容模板建议自定义一下。默认模板只提示有异常发生,信息不完整。常见的做法是在主题里加上主机名和问题状态,内容里写清楚监控项当前的数值。Zabbix 支持大量宏变量,比如 {HOST.NAME} 表示主机名,{ITEM.LASTVALUE} 表示当前值,{TRIGGER.NAME} 是触发器名称,{EVENT.DATE} 和 {EVENT.TIME} 是事件发生时间。把这些拼进模板里,收到的告警邮件才能让你一眼判断该不该马上处理。
5.2 对接钉钉、企业微信、飞书
国内现在用得更多的其实是 Im 类的告警接收方式,钉钉群机器人、企业微信应用消息、飞书机器人。Zabbix 内置了 Webhook 媒介类型,可以直接对接这些平台。配置的通用流程是:先在钉钉或飞书群里添加一个自定义机器人,拿到 Webhook 地址,然后在 Zabbix 的 Media types 里选择对应的 Webhook 模板,把地址填进去,再给用户添加该媒介即可。
这里有一个容易踩的坑:钉钉机器人对 Webhook 地址有安全设置,如果是加签方式,你不仅要把 Webhook 地址填进去,还需要在 Zabbix 的 Webhook 参数里填加签的密钥。飞书机器人对自定义关键词和签名校验也有严格限制。配置完务必先点 Test 按钮验证一下,等收到测试消息再应用到正式告警里,不要配完就直接等下一次故障。
5.3 告警风暴治理的实践经验
告警配置完成之后紧接着的场景就是告警风暴,我第一次在生产环境配完告警,当天晚上手机被消息叮到没电。原因很简单:同一个故障会触发多个监控项的多个触发器同时报警,每台主机、每个监控项都发一遍通知,问题就变成了五十条消息。解决告警风暴,我最常用的手段有三个。
第一个是触发器依赖。Zabbix 允许你配置触发器之间的依赖关系。比如服务器宕机后,不但 Ping 触发器会报警,它的 CPU、内存、磁盘监控也会跟着失去数据而报警。这时候你把 Ping 触发器设置为管理型触发器,其他触发器依赖它,主故障触发后,被依赖的触发器就会自动降级为显示“已依赖”而不发通知。配置位置在触发器的高级选项里。
第二个是维护窗口。Zabbix 的 Maintenance 功能可以设置在指定时间段内暂停告警。比如每周日凌晨做数据库备份,备份期间服务器负载可能飙高,这时候不关告警就只能天天收到假警。建一个维护周期,设定时间段和要覆盖的主机,到时间自动生效,不用手动干预。
第三个是控制恢复通知。不是所有问题恢复都要第一时间发消息,有些波动性的问题恢复之后就恢复了,发一条恢复通知价值不大。我通常只对核心业务主机开启恢复通知,非核心主机靠 Dashboard 观察即可,这样能大幅减少无效消息数量。
6. 高频问题排查实录:从报错到稳定运行
这部分我把我实际遇到的、也经常在网上看到别人问的问题整理成一个速查表,遇到对应现象直接对照着排查,能省很多时间。先说结论:绝大多数 Zabbix 容器化部署问题,最后都集中在数据库连接、时间同步、端口通信这三件事上。
6.1 “Zabbix server is not running” 的完整排查路径
前端页面顶部常常会显示黄色横幅:Zabbix server is not running: the information displayed may not be current. 这个提示一出,很多人就慌了,但其实原因并不复杂。这句话表示 Zabbix Web 连接不到 Zabbix Server 的 API,或者 Server 进程没有正常运行。按下面顺序排查,基本都能找到原因。
第一步看容器状态,docker ps 检查 zabbix-server 容器是不是已经退出了。如果容器一直在自动重启,用 docker logs -f zabbix-server 看日志,最常见的报错是数据库连接失败。这里的问题通常有两个:一是数据库还没就绪就启动 Server,没有配置健康检查就会出现这种情况,解决方式就是我在编排文件里写的 depends_on 加 healthcheck;二是数据库密码填错,认真核对 compose 文件里的 MYSQL_PASSWORD 和 Server 环境变量是否一致。
第二步检查 Server 容器和 Web 容器之间的网络。容器只要在同一个 compose 文件里定义,会自动加入同一个默认网络,互相用服务名访问是没问题的。但如果你单独用 docker run 起的容器,没有加入同一个自定义网络,服务名解析就会失败。面对这种情况,一条简单的验证命令是 docker exec -it zabbix-web ping zabbix-server,能通则网络没问题。
第三步经常被忽略:宿主机的时区和容器时区不一致。Zabbix Server 对时间非常敏感,Server 和数据库时间偏差过大,前端就可能误判服务状态。验证方法是 docker exec zabbix-server date,看输出是否为当前时间,不对就在 Server 环境变量里加上 ZBX_TIMESYNC 并确保宿主机 ntp 时间同步正常。
6.2 Access denied for user 的数据库权限问题
前文提到过一个常见的访问报错:Access denied for user 'replace_user'@'localhost'。这个报错通常在前端安装向导填完数据库信息后出现。问题指向非常明确:Zabbix Web 容器连接数据库时认证失败。对应的解决方案是,确认 compose 文件里设置的 MYSQL_USER 和 MYSQL_PASSWORD 与你在前端向导里填写的内容一致,同时确认 MySQL 容器创建的用户名与数据库名没有混淆。Zabbix 6.0 搭配 MySQL 8.0 时,注意认证插件是否为 mysql_native_password,我在编排文件里已经加了 default-authentication-plugin 配置,如果你是自己单独拉的 MySQL 容器,很可能就要处理这一步。
还有一种不容易排查的情况:数据库容器是之前用旧配置创建的,环境变量改动后不会自动更新数据库里的用户。即使你改了 MYSQL_PASSWORD,MySQL 容器里已有的用户密码还是旧值。解决方式是删除数据卷重新初始化,或者手动进入容器执行 ALTER USER 语句。删除数据卷前记得确认没有重要监控数据,这个操作不可逆。
6.3 添加主机后没有监控数据的处理思路
前端已经添加了主机,状态显示为灰色,Latest Data 里一条数据都没有。这种情况的排查顺序我建议这样走。先确认被监控机上 agent 进程是否在运行,docker ps 看 agent2 容器状态。然后看网络连通性,在被监控机执行 telnet 你的ZabbixServerIP 10050,看端口是否通。如果端口不通,检查两台机器的防火墙、安全组。如果端口通但还没数据,进 Zabbix Server 容器里用 zabbix_get 命令做主动测试:
docker exec -it zabbix-server zabbix_get -s 192.168.1.101 -k system.cpu.load这条命令返回数值的话,说明 Server 能拿到 Agent 的数据,问题就出在前端配置上。最常见的坑是主机名称和 Agent 配置中的 Hostname 不一致。Zabbix 是严格按照主机名来匹配数据的,只要差一个字符,数据就进不来。把 Agent 容器里的 ZBX_HOSTNAME 和前端添加的主机名保持一致,问题立刻解决。
另一个需要留意的点是,Zabbix 的 Agent 有主动模式和被动模式之分。如果 Server 配置的是被动检查(Server 去拉数据), Agent 那侧必须允许被动模式,即 ZBX_PASSIVE_ALLOW=true;如果配置的是主动检查(Agent 上报数据),则 Agent 要能连上 Server 的 10051 端口,并且 ZBX_SERVER_ACTIVE 配置正确。不少用户两种模式混着配,导致数据时有时无,排查起来也很费劲。
6.4 镜像拉取与容器重启的相关问题
部署初期遇到最多的就是镜像拉取慢或者超时,这在中国大陆的服务器上尤为常见。解决办法是在 Docker daemon 配置 registry-mirrors 加速。修改 /etc/docker/daemon.json 加入镜像加速地址,改完执行 systemctl restart docker 再重新拉取。不同网络环境对不同加速地址的效果差异很大,建议多试几个,选能拉动的那个配置下来长期使用。需要注意的是,修改 daemon 配置并重启 Docker 会导致所有容器重启一次,生产环境操作前先评估影响。
容器启停方面,我遇到过 restart: always 策略导致的一个特殊现象:当宿主机因内存不足触发 OOM,MySQL 容器被内核杀掉,Docker 检测到异常退出会自动拉起容器,但 Zabbix Server 连接池里还有旧的连接,需要等超时才能恢复,这段时间前端表现为数据延迟。解决方式是给 MySQL 容器加内存限制,比如 mem_limit: 2g,同时给 Docker 加大系统 swap 空间,避免物理内存耗尽时内核直接开杀。
最后分享一些实操体会
这套 Docker Compose 部署 Zabbix 的方案,我在多个环境里重复搭建过不下十次,从单机测试到生产监控环境都验证过。整个过程里最大的体会是,不要把 Docker 当作银弹,它解决的是部署和环境一致性问题,但 Zabbix 本身的监控体系建设、告警阈值调优、数据保留策略这些运维基本功,还是得按部就班地做。容器让你快速跑起来,但跑得好不好,取决于你对监控对象理解得够不够深。
如果你是企业里第一个推动监控体系建设的人,我的建议是先别贪多,把这一套平台搭起来,先接上一台生产主机验证链路,再逐步推广。一开始就把所有模板和触发器都加进去,很容易被噪声告警淹没,反而失去对监控系统的信任。宁可先少监控几个指标,也要保证每条告警都是准确且有价值的。
最后再分享一个小技巧:把 docker-compose.yml 和自定义的告警脚本一起放进 Git 仓库管理。这样你每次改动都有记录,出了问题可以快速回滚,新同事加入时 pull 一下代码就能在本地复现整套环境。我把这套文件放在公司的 GitLab 里,后来还基于它写了一个简单的部署脚本,新环境初始化只需要执行一条命令,省下的时间足够我去研究更多监控对象了。