说实话,第一次接到“把公司几百台服务器、数据库、中间件全部纳入监控,并且要有告警推送”这个需求时,我心里是发怵的。以前在公司内部用传统方式装过 Zabbix,踩了一路的坑:PHP 版本不兼容、MySQL 初始化报错、前端页面白屏……每一处都是时间黑洞。后来我换成 Docker 这条路线,用容器把 Zabbix Server、Web 前端、数据库、Agent 全部编排起来,从一张空白的服务器到把监控面板跑起来,前后不到二十分钟。这篇文章就是把我在这条路上踩过的坑、总结出来的套路,完完整整地分享出来。
Zabbix 是目前业界使用最广泛的企业级开源监控平台之一,它可以监控服务器 CPU、内存、磁盘、网络流量等基础指标,也可以监控数据库、中间件、业务进程,甚至可以通过 SNMP 协议接管交换机、路由器这些网络设备。Docker 部署的好处在于环境隔离、启动快、备份迁移方便,你不用再为装一个监控软件搞坏系统的 PHP 环境而头疼。这篇文章适合两类人看:一是刚接触 Zabbix、被传统安装方式劝退过的运维新手,二是想快速上一套可用监控方案的开发者或者小团队负责人。文章不会浮在概念上,每一步都会给出可复制的配置和操作命令。
1. 方案选型:为什么用 Docker 跑 Zabbix
1.1 传统安装方式到底坑在哪里
很多人在接触 Docker 之前,对 Zabbix 的第一印象就是“依赖地狱”。它本身是 C 语言写的服务端,前端是 PHP,后端数据存储用的是 MySQL 或 PostgreSQL,还要依赖一系列 PHP 扩展、字体库、SNMP 工具、JDBC 驱动等等。在 CentOS 7 上按传统方式安装,先要配 EPEL 源、装 httpd、装 PHP 5.4,再手动改 php.ini 里的时区和内存限制,最后还要处理 SELinux 权限问题。我一个同事曾经因为 PHP 版本和 Zabbix 前端要求的版本不一致,整整调了两天。
这不是说传统安装方式就不可行,生产环境里确实有很多老牌团队还在用 RPM 包或源码编译的方式跑 Zabbix,稳定性和性能也都不差。但它对系统环境的“侵入性”太高了。装一个软件,可能要动系统自带的 PHP、MySQL,甚至会影响其他业务程序。而 Docker 的思路正好相反,每个组件装在各自的容器里,互相隔离,版本由镜像锁定,宿主机只需要一个 Docker 环境就够了。
1.2 容器化部署的三大核心优势
Docker 部署 Zabbix 的优势,我总结下来有三点最值得说。
第一是可移植性。你在测试环境用 docker-compose 拉起来一套 Zabbix,想把同样的环境迁到生产服务器,只需要把 docker-compose.yml 文件和挂载的数据目录一起带过去,然后一条命令就能恢复。不再需要重新编译、重新配环境变量,这对需要频繁在开发、测试、生产环境之间切换的团队来说,是实打实的效率提升。
第二是故障恢复速度。传统安装的 Zabbix Server 如果挂了,你得从头排查系统日志、PHP 日志、数据库日志。容器化之后,最粗暴的方式就是重建容器,所有的软件配置都在镜像和编排文件里定义好了,几分钟就能恢复到可用状态。数据库数据放到持久化卷里,不随容器销毁而丢失。
第三是对新手友好。网络上关于 Zabbix 的教程铺天盖地,但大量教程还停留在 3.x、4.x 时代,用的还是 CentOS 6,步骤繁琐不说,很多命令在现在的新版本发行版上根本跑不通。而 Docker 官方镜像的维护节奏和文档都比较新,只要你 Docker 环境是正常的,用镜像启动 Zabbix 几乎不会遇到编译层面的问题。
1.3 监控组件逻辑:Server、Agent、Web 和数据库怎么协作
在正式写编排文件之前,有必要把 Zabbix 的几个核心组件搞清楚。我在面试运维岗位时经常问这个问题,很多看似用过 Zabbix 的人其实并不清楚它整体的数据流。
Zabbix Server 是监控大脑,负责接收数据、执行触发器判断、发送告警通知;Zabbix Agent 部署在被监控的主机上,负责采集 CPU、内存、磁盘等指标并汇报给 Server;Zabbix Web 是前端界面,完成配置、查看图形、管理用户等操作;MySQL(或 PostgreSQL)存储所有配置和监控数据。此外还有 Zabbix Proxy,适合大规模分布式场景,可以理解为区域代理,由它统一向被监控主机采集数据再回传总部,不过我们今天的基础方案不需要 Proxy。
数据流大致就是 Agent 采集数据发给 Server,Server 写入数据库,Web 前端从数据库读出来展示成图表和面板,同时 Server 根据触发器规则判断是否触发告警并走媒介发送通知。理解了这条链路,后面排错时就有方向了:页面数据不刷新先查 Server 日志,Server 收不到数据先查 Agent,告警没收到先查触发器和媒介配置。
2. 核心组件与关键配置:从编排文件说起
2.1 镜像选型和版本锁定
Docker 部署 Zabbix,最省心的方式是用官方镜像。整个方案涉及四个镜像:zabbix/zabbix-server-mysql、zabbix/zabbix-web-nginx-mysql、mysql(或 percona),以及被监控端用的 zabbix/zabbix-agent2。
镜像标签一定要锁定版本,不建议直接用 latest。我在生产环境刚起步时图省事用了 latest,结果某天官方发了新版本,镜像拉下来后数据库 schema 自动升级了,而前端容器还是旧版本,界面直接报版本不兼容。从那以后我所有镜像都显式指定版本号,比如 zabbix-server-mysql:alpine-6.4-latest 这种格式看起来长,其实比 latest 稳妥得多。版本选择的思路是:如果你的监控规模不大,6.4 LTS 和 7.0 LTS 都是不错的选择,注意 Server、Web 和 Agent 的版本尽量保持一致,避免协议不兼容。
Agent2 是 Zabbix 新一代 Agent,内置了对很多常见协议的采集支持,配置方式和老 Agent 基本一致,强烈建议直接使用 Agent2,不要再用旧版 agent。
2.2 环境变量是编排的灵魂
Zabbix 官方镜像最方便的地方在于:对 MySQL 的连接信息、系统初始化、Web 界面配置都可以通过环境变量注入,不需要进容器手改配置文件。这是无数人第一次部署时最迷糊的地方,我把核心变量整理出来解释。
先看数据库相关。DB_SERVER_HOST 是数据库主机地址,在 compose 编排中直接写成数据库容器的服务名,比如 mysql-server,compose 内部网络会自动做 DNS 解析。MYSQL_USER、MYSQL_PASSWORD、MYSQL_DATABASE 这三个变量会被 Zabbix Server 和 Web 容器用来连接数据库,同时也会被 mysql 容器初始化脚本用于创建用户和库。如果你用的是外部已有数据库,则只需要告诉 Zabbix 连接信息,不需要让 mysql 容器去初始化。
再看 Zabbix Server 自己的变量。ZBX_CACHESIZE 控制缓存大小,默认是 8M,我监控大概一百台主机时改成了 128M;ZBX_HISTORYCACHESIZE 是历史数据缓存,默认 16M,监控项特别多可以适当调到 64M 以上。还有 ZBX_STARTPOLLERS,轮询器进程数,默认 5,监控项数量和主机数量上来之后可以加大。这些参数在传统部署中都需要改 conf 文件,容器化之后通过环境变量注入,改完重启容器即可,非常方便。
Web 容器方面最关键的变量是 PHP_TZ,必须设置成 Asia/Shanghai,不然前端显示的时间跟服务器本地时间差八个小时,监控和告警的时间错乱会让人抓狂。ZBX_SERVER_NAME 是界面左上角显示的名称,想叫什么叫什么,纯展示用。
2.3 数据持久化:容器可以死,数据不能丢
容器是无状态的,这句话是容器使用的基本常识,但 Zabbix 偏偏是有状态的。MySQL 里存了监控历史数据、主机配置、触发器规则,一旦容器销毁而数据没做持久化,损失相当惨重。
在 docker-compose 里,我通常给 MySQL 挂载一个命名卷,类似 mysql-data:/var/lib/mysql,这样即使容器被删除重建,数据也还在。对于 Zabbix Server,重点持久化的是告警脚本目录、外部脚本目录和 SNMP Trap 相关文件,如果你只做最基础的监控,Server 端的卷可以不挂那么多,但 MySQL 的持久化绝对不能省略。
还有一点容易被忽略:备份。容器化不是免死金牌,持久化卷里的数据依然可能因为磁盘故障或者误操作丢失。我在实际运维中养成了一个习惯,每天凌晨用 mysqldump 把 Zabbix 的数据库导出到另一个存储位置,这样即使整个宿主机挂了,也能在新机器上快速重建一套空白 Zabbix,再用备份恢复,十分钟找回全量监控配置。等这套方案跑顺之后,可以把备份脚本固化成一个计划任务,或者用 cron 容器定期执行业务逻辑。
3. 实操部署:从零到上线一套完整监控
3.1 环境要求与 Docker 准备
在开始之前,先确认宿主机的基本条件。Zabbix Server 加 MySQL 这套组合,内存建议至少 4GB,低于 2GB 会非常吃力,尤其是数据库缓存调大之后。CPU 双核起步,监控规模不大时没必要追求高配置。磁盘方面要注意监控数据是持续写入的,建议给数据库挂载独立磁盘,纯机械盘也能跑,SSD 体验更好。
Docker 环境的安装这里不展开细讲,需要注意两点。一是 Docker Engine 版本别太老,新版 Zabbix 镜像对旧版本 Docker 的兼容性不好,建议 Docker 20.10 以上。二是 Docker Compose 插件的使用方式,新版 Docker 推荐 docker compose 子命令(中间没有横杠),旧版需要单独安装 docker-compose。这两类命令的下拉参数略有差异,在流程中先确认一下。
如果宿主机上已经有 Docker 环境,可以顺手验证一下版本:docker --version 和 docker compose version。网络正常的情况下,接下来只需要准备好 docker-compose.yml 就可以开始拉镜像了。
3.2 编写 docker-compose.yml 的完整模板
下面这套编排文件是我的基准模板,已经在好几台服务器上验证过,可以直接拿来用。注意把密码部分替换成自己的强密码。
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_ROOT_PASSWORD=zabbix_root_pwd - MYSQL_DATABASE=zabbix - MYSQL_USER=zabbix - MYSQL_PASSWORD=zabbix_pwd volumes: - mysql-data:/var/lib/mysql networks: - zabbix-net restart: unless-stopped zabbix-server: image: zabbix/zabbix-server-mysql:alpine-6.4-latest container_name: zabbix-server environment: - DB_SERVER_HOST=mysql-server - MYSQL_DATABASE=zabbix - MYSQL_USER=zabbix - MYSQL_PASSWORD=zabbix_pwd - ZBX_CACHESIZE=128M - ZBX_HISTORYCACHESIZE=64M - ZBX_STARTPOLLERS=10 ports: - "10051:10051" volumes: - /usr/lib/zabbix/alertscripts:/usr/lib/zabbix/alertscripts:ro networks: - zabbix-net depends_on: - mysql-server restart: unless-stopped zabbix-web: image: zabbix/zabbix-web-nginx-mysql:alpine-6.4-latest container_name: zabbix-web environment: - ZBX_SERVER_HOST=zabbix-server - DB_SERVER_HOST=mysql-server - MYSQL_DATABASE=zabbix - MYSQL_USER=zabbix - MYSQL_PASSWORD=zabbix_pwd - PHP_TZ=Asia/Shanghai - ZBX_SERVER_NAME=My Monitoring ports: - "8080:8080" networks: - zabbix-net depends_on: - zabbix-server restart: unless-stopped volumes: mysql-data: networks: zabbix-net:这段配置里有几个细节我想专门说明。MySQL 8.0 默认的认证插件是 caching_sha2_password,而某些版本的 Zabbix 连接 MySQL 8.0 时容易报认证失败,所以我在 command 里显式指定了 mysql_native_password,这是一个很实用的兼容性配置,踩过坑的人都知道。
Zabbix Web 的端口我映射成了 8080,用 Nginx 镜像自带的 8080 是 Zabbix 官方镜像的习惯。如果你不想每次访问都带端口号,可以把宿主机端口改成 80,映射写成 "80:8080"。ZBX_SERVER_HOST 指向 zabbix-server 容器,这个变量名和数据库的 DB_SERVER_HOST 不同,别搞混了。
3.3 启动、初始化和界面验证
保存好 docker-compose.yml 之后,在文件所在目录执行启动命令。第一次会拉取镜像,耗时取决于网络环境。启动完成后用 docker compose ps 查看容器状态,正常情况是三个容器都在 Up 状态。
首次启动时 Zabbix Server 容器会自动创建数据库表结构,这个过程需要一点时间。如果马上打开 Web 界面,可能看到“正在安装”的提示,等一两分钟刷新一下就好。MySQL 容器首次初始化时也会执行创建数据库和用户的脚本,同样需要等待。
Web 界面初始化这一步不少人会卡住。打开浏览器访问 http://宿主机IP:8080,会进到 Zabbix 安装向导,但 Docker 部署时绝大部分配置已经通过环境变量填好了,界面上只需要确认数据库信息、时区,然后点下一步。之后会要求填入 Zabbix Server 的数据库密码,这个密码就是 compose 文件里 MYSQL_PASSWORD 的值。注意这里真正连接的是 Zabbix 的数据库,不是 root 密码,很多人填 root 密码会提示 Access denied。
安装完成后默认管理员账号是 Admin,密码是 zabbix,首次登录后强烈建议立刻修改。登录进去看到仪表盘,在这个界面能看到系统运行状态、主机数量等基本信息,到这里整套平台就已经跑起来了。
3.4 添加第一台被监控主机
平台搭起来之后,第一件正事就是添加被监控主机。对于 Linux 服务器,最简单的方式是装 Zabbix Agent2。以 CentOS/RHEL 系列为例,先安装官方源再装 agent2 包,然后编辑 /etc/zabbix/zabbix_agent2.conf,只需要改三个配置,Server 和 ServerActive 填 Zabbix Server 的 IP,Hostname 填一个你自己定义的主机名,要和 Web 界面里添加主机时填的名称保持一致。启动并设置开机自启后,回到 Web 界面,在“数据采集 -> 主机”里点“创建主机”,主机名称必须和 Agent 的 Hostname 一致,填入 Agent 的 IP,端口默认 10050,然后选择一个模板,最简单的选 Linux by Zabbix agent,点击添加。
稍等几十秒,可以看到主机旁边的可用性变成了绿色,说明 Agent 已经连上 Server。这时候去“监测 -> 最新数据”,就能看到 CPU、内存、磁盘、网络等指标的数据流进来了。如果你是 Windows 主机,在 Windows 上安装 agent2 的方式也类似,配置方法一样。
4. 告警配置实战:让平台主动找我们
4.1 告警媒介:邮件通知是最基础的一道
监控平台如果没有告警,就相当于装了监控摄像头但没人看屏幕,没有实际意义。Zabbix 的告警链路是:触发器触发 -> 生成事件 -> 通过告警媒介发出通知。媒介可以理解成“发消息的通道”,最常用的是邮件,此外还有钉钉、企业微信、Telegram、Webhook 等。
配置邮件告警时,在“告警 -> 媒介 -> 创建媒介类型”,选择 Email,设置 SMTP 服务器、端口、发件人邮箱、认证信息。我建议用企业邮箱或专门的告警邮箱,不要用个人免费邮箱,因为免费邮箱的 SMTP 发信频率限制严格,告警一多就容易被封。配置完成后,还需要在用户设置里给管理员账号“添加媒介”,绑定接收邮箱。最后还要在“用户 -> 权限”里确保用户有接收告警的权限,这一步经常被忽略。
4.2 触发器与模板:告警条件怎么设才合理
触发器是 Zabbix 告警的核心。系统自带的模板里已经内置了大量触发器,比如 CPU 使用率过高、磁盘空间不足、服务不可达等。直接使用模板的触发器是最省力的方式,对于大多数场景已经够用。
但默认触发器的阈值未必符合你的业务场景。比如默认的 CPU 触发器可能定义在 90% 以上持续 5 分钟才告警,而有些业务系统 CPU 超过 70% 就要预警。自定义触发器的方式是:在“数据采集 -> 模板”里克隆一个模板,然后修改触发器的表达式,比如 CPU 使用率的表达式可以写成 last(/Template OS Linux by Zabbix agent/system.cpu.util[,total])>80,意思是最近一次采样的 CPU 总使用率超过 80% 就触发告警。
触发器设计的核心思路是“减少噪音,避免告警风暴”。我在生产环境里见过最惨烈的告警风暴,一个业务系统半夜挂了,相似的告警一小时发出几百条,直接把运维人手机打爆。建议给每个触发器设置合理的恢复表达式和持续时间,同时对不紧急的告警设置告警升级,比如磁盘超过 80% 先发警告,超过 90% 才发严重级别。
4.3 实战:配置钉钉/企业微信告警脚本(简单实现)
如果不方便用邮件,走 Webhook 或脚本是目前很流行的做法。以钉钉机器人为例,思路是写一个 Python 或 Shell 脚本,放在 Zabbix Server 的告警脚本目录里(比如 /usr/lib/zabbix/alertscripts),然后在“告警媒介类型”里创建一个脚本媒介。
脚本的伪代码逻辑很简单:接收三个参数,收件人(钉钉机器人的 access_token)、主题、消息内容,然后通过 Python 的 requests 库向钉钉的 Webhook 地址发送 JSON 格式的消息。Zabbix 调用脚本媒介时会把告警标题和内容作为参数传给脚本。整个过程不复杂,但要注意脚本必须有执行权限,Zabbix Server 进程是容器内用户,脚本路径要在容器内也能访问,否则会出现“脚本执行成功但消息没发出去”的怪问题。
我第一次用容器跑告警脚本时就踩过这个坑:脚本放在宿主机的 alertscripts 目录,容器挂载的时候权限没配好,Zabbix Server 根本读不到脚本,告警媒介测试发不出去。后来把所有告警脚本统一放在一个目录,用只读方式挂载进容器,再手动 chmod +x 给执行权限,问题就解决了。
5. 常见问题与排查技巧实录
5.1 Zabbix server is not running 问题全解析
这是 Zabbix 使用中最经典的一个报错。Web 界面顶部会显示红色警告“Zabbix server is not running: the information displayed may not be current.”,看着吓人,但排查思路其实很清晰。
第一步,看 Server 容器状态和日志。docker compose ps 确认 zabbix-server 容器是否在运行,然后执行 docker logs zabbix-server 查看日志输出。最常见的错误是数据库认证失败,日志里会明确写出 Access denied for user。这种情况检查 compose 文件里的 MYSQL_USER 和 MYSQL_PASSWORD 是否与数据库容器初始化的账号密码一致。第二步,检查数据库是否有数据表。刚启动的 Zabbix Server 会自动建表,如果日志停在连接阶段,多半是 MySQL 容器还没初始化完成,等一会再重启 Server 容器就好。第三步,检查时区配置。如果 Server 容器和 Web 容器的时间相差过大,也可能导致界面判断 Server 未运行,虽然这个情况少一些,但我在排查时都会顺手确认。
5.2 数据库连接报错 Access denied for user
互联网上搜 Zabbix 部署问题,出现频率最高的就是 zabbix access denied for user 'replace_user'@'localhost' (using password: YES)。这个报错信息里出现的 replace_user 是官方手册中用来替换的占位符,并不是真实存在的用户,很多人第一次看到会懵,以为系统里有个叫 replace_user 的账号。
出现这个问题的核心原因是数据库账号或密码不对,或者主机限制不允许 Zabbix Server 所在的主机连接。用 Docker 部署时,注意在 MySQL 容器初始化阶段,Zabbix 的用户通常只允许从某个特定主机连接,compose 网络中 Zabbix Server 是通过内部网络访问 MySQL 的,主机名解析的是 mysql-server,一般没问题。如果连外部数据库,要确认 MySQL 用户的 host 允许范围包含 Zabbix Server 的 IP。
5.3 其他主机怎么添加 Zabbix 监控
这个问题是新手老手都高频问的。添加方式取决于被监控主机的类型。最简单的是 Zabbix Agent,适用于 Linux 和 Windows。其次是 SNMP,适用于交换机、路由器、UPS 等网络设备。还有 IPMI,用于监控服务器的硬件状态,比如风扇转速、温度、电源状态。
对于交换机,思路是在核心交换机上开启 SNMP 协议,配置只读的 community 字符串,在 Zabbix Web 界面添加主机时选择 SNMP 接口,填写交换机的 IP 和 community,然后关联一个网络设备模板,比如 Net Cisco IOS SNMP 或 Net Device Generic SNMP。华为、H3C 等品牌的交换机模板在网上也有现成的,可以导入使用。用 SNMP 方式监控的指标主要是接口流量、端口状态、CPU/内存利用率(如果设备支持的话)。
5.4 Docker 镜像下载慢的应对方案
拉取 Zabbix 镜像时经常出现速度慢的问题,尤其是 MySQL 这种体积较大的镜像。解决方案是配置镜像加速器,也就是 registry mirror。在 Docker 的 daemon.json 里配置镜像加速地址,国内云厂商提供的镜像加速器效果还不错,修改后执行 systemctl restart docker 重启。这个操作本质是把拉取请求转发到加速器,不影响镜像的最终来源和内容,整体速度快很多。
如果拉取通宵都拉不完,还有一个思路是换更小的镜像。Zabbix 官方提供 alpine 版本的镜像,体积比默认版本小不少,在镜像标签里选择 alpine- 前缀的版本即可。我们上面的编排文件用的就是 alpine 系列,启动速度和磁盘占用都有优势。
5.5 特殊监控场景:Windows GPU 和监控大屏
Zabbix 的高可扩展性体现在几乎所有 IT 资产都能纳入监控。比如监控 Windows GPU 使用率,思路是通过 Agent2 执行 PowerShell 脚本或者使用 NVML 工具,把 nvidia-smi 的输出解析成指标,再用 Zabbix Sender 协议把数据发送到 Server。这属于自定义监控的范畴,需要写一点脚本,但效果很好。
至于监控大屏,常见的做法是直接用 Grafana 作为前端展示层,通过 Zabbix 数据源插件读取监控数据渲染大屏。Grafana 的图表样式灵活,比 Zabbix 自带的图形界面美观得多,在运维大屏场景下很受欢迎。部署方式依然是 Docker,一个 Grafana 容器加上 Zabbix 数据源插件,配置十几分钟就可以完成。
写在后面:一点实际操作的体会
我把自己这套 Docker 部署 Zabbix 的方案,前前后后在开发测试环境和生产环境各跑过一轮,最深的感受是“用容器部署不等于万事大吉,但它把问题边界划清楚了”。以前排查 Zabbix 故障,得区分是 PHP 的问题、MySQL 的问题还是 Zabbix 自身的问题,有时候根本分不清。现在组件都隔离在容器里,哪个容器出问题就看哪个容器日志,边界清晰,排查效率高了很多。
另外再分享一个小技巧:Docker 部署的 Zabbix 在版本升级时非常简单,先备份数据库,再修改编排文件中的镜像标签,执行 docker compose up -d,系统会自动完成数据库 schema 迁移。每一次升级前我都习惯把官方 release notes 看一遍,尤其是大版本跨版本升级时,有一些兼容性注意事项需要提前了解。
对于刚入门的朋友,不用一上来就追求把所有设备、所有指标都监控起来。先把 Linux 服务器的 CPU、内存、磁盘、网络跑通,然后加一台 Windows 主机,加一台交换机,逐步扩展。监控这件事,稳定压倒一切,跑得通的简单方案,比看起来高大上的复杂架构可靠得多。希望这篇内容能帮你少走一些弯路,尽快把第一套 Zabbix 平台跑起来。