
部署这套方案之前我其实纠结过一阵子Zabbix 是老牌监控系统功能强但组件多传统方式装一套要装 MySQL、装 Server、装 Web、装 Agent光依赖就能折腾半天。后来改用 Docker Compose 把 Zabbix 全家桶拉起来从零到有基本半小时内搞定而且升级、备份、迁移都省心不少。这篇文章就把我的完整实践经验写出来从架构规划、compose 编排、监控项配置到常见问题排查希望能帮想快速上手 Zabbix 的朋友少走弯路。这套方案适合谁适合公司里有几台到几十台服务器、网络设备或 Windows 机器需要统一监控的运维同学也适合想在家搭一套监控环境练手的技术爱好者。读完你不仅能把 Zabbix 跑起来还能掌握添加主机、自定义监控脚本、对接告警消息这套完整链路。1. 为什么我用 Docker 来跑 Zabbix 这套监控体系1.1 Docker 跑监控相比传统安装的几个明显优势以前在 CentOS 7 上装 Zabbix要处理 EPEL 源、Zabbix 官方源、PHP 版本不兼容、数据库初始化失败等问题尤其是内网环境依赖包下载就能卡半天。Docker 部署的好处说白了就是依赖隔离和交付一致性镜像里已经装好了 Zabbix Server 需要的所有运行环境不会污染宿主机也不会受到宿主系统版本影响。另一个很实际的好处是升级和回滚方便。想从 Zabbix 6.0 升到 6.4传统方式要停服务、替换二进制、升级数据库出事还得想办法还原。Docker 方式只需改镜像版本然后把数据库备份好容器重新拉起不行就换回旧镜像整个过程几分钟之内完成。还有一个容易被忽略的点Docker 容器的日志管理比 systemd 日志友好得多。用docker logs可以直接看 Zabbix Server 输出排查问题的时候信息一目了然不用去翻/var/log/zabbix/底下一堆文件。我排查“Zabbix server is not running”这类问题时靠这个节省了大量时间。1.2 我的容器拆分方案与资源规划Zabbix 官方在 Docker Hub 上提供了多个镜像我的拆分方案是 4 个容器zabbix-server监控数据处理核心负责数据收集、触发器计算、告警生成zabbix-webNginx PHP 前端提供浏览器管理界面zabbix-agent被监控端的采集代理我直接部署在宿主机上用来监控 Docker 宿主本身zabbix-dbMySQL 8.0 数据库存储配置和监控数据有人会用 PostgreSQL 替代 MySQL两者官方都支持但 MySQL 的生态更普及遇到问题查资料方便所以我选 MySQL。资源规划方面我实测的参考配置如下规模容器数量CPU内存存储测试/学习10 台4 个容器2 核4 GB20 GB生产50~100 台4 个容器4 核8 GB100 GB大规模500 台建议拆库分开部署8 核16 GB按需扩展需要注意Zabbix Server 对内存的需求主要集中在数据库和 Server 进程上历史数据保留周期越长存储占用增长越快。建议监控数据保留 30 天左右趋势数据保留 365 天就够用了没必要无限堆积。2. 用 Docker Compose 一口气拉起 Zabbix 全家桶2.1 完整 compose 编排文件可直接复制我强烈建议直接用 Docker Compose而不是docker run一个个起容器。Compose 的好处是编排关系清晰、启停方便一条docker compose up -d就能拉起整个环境而且配置全部写在文件里交接给同事也方便。下面是我实际在用的 compose 文件基于 Zabbix 6.4 LTS 版本version: 3.8 services: db: image: mysql:8.0 container_name: zabbix-db environment: MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pass MYSQL_ROOT_PASSWORD: root_pass command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_bin - --default-authentication-pluginmysql_native_password volumes: - ./data/mysql:/var/lib/mysql restart: always server: image: zabbix/zabbix-server-mysql:6.4-ubuntu container_name: zabbix-server environment: DB_SERVER_HOST: db DB_SERVER_PORT: 3306 MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pass ZBX_TIMEOUT: 5 ZBX_STARTPOLLERS: 8 ZBX_CACHESIZE: 256M ports: - 10051:10051 volumes: - ./data/alertscripts:/usr/lib/zabbix/alertscripts depends_on: - db restart: always web: image: zabbix/zabbix-web-nginx-mysql:6.4-ubuntu container_name: zabbix-web environment: ZBX_SERVER_HOST: server DB_SERVER_HOST: db MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pass PHP_TZ: Asia/Shanghai ports: - 8080:8080 depends_on: - server restart: always agent: image: zabbix/zabbix-agent:6.4-ubuntu container_name: zabbix-agent environment: ZBX_SERVER_HOST: 127.0.0.1 ZBX_HOSTNAME: Docker Host ports: - 10050:10050 restart: always保存为docker-compose.yml在文件所在目录执行docker compose up -d等待镜像拉取和容器启动。第一次启动时 MySQL 需要初始化数据库可能要等 1 到 2 分钟。启动完成后访问http://服务器IP:8080用默认账号Admin密码zabbix登录。2.2 环境变量和卷映射里容易被忽略的细节时区配置是我踩过的第一个坑。刚开始我没配置PHP_TZZabbix Web 界面里的时间和实际时间相差 8 小时告警时间看着总是不对。在 web 服务环境变量里加上PHP_TZ: Asia/Shanghai就能解决。另外 MySQL 容器也可以加上TZ: Asia/Shanghai参数保证数据库侧的时间也一致。command参数里我指定了 MySQL 使用utf8mb4字符集和mysql_native_password认证插件。这里有个背景知识MySQL 8.0 默认认证插件是caching_sha2_password而 Zabbix Server 6.4 之前的某些版本连接 MySQL 8.0 时会报认证错误。加上--default-authentication-pluginmysql_native_password可以避免很多连接问题。卷映射是数据安全的关键。我把 MySQL 数据目录、Zabbix Server 的告警脚本目录都映射到了宿主机上。这样的好处是容器删除再重建监控配置和历史数据都还在自定义告警脚本也不需要重新编译进镜像。路径对应关系如下容器内路径宿主路径作用/var/lib/mysql./data/mysql数据库持久化/usr/lib/zabbix/alertscripts./data/alertscripts自定义告警脚本/etc/localtime宿主机 /etc/localtime保持容器与宿主机时区一致还要注意ZBX_CACHESIZE这个参数它的意思是 Zabbix Server 在内存里缓存监控数据的最大值。如果监控的 item 数量很多默认的 8M 或者 16M 可能不够监控项多了以后 Server 会频繁刷写内存缓存性能下降明显。我调成256M后几千个监控项跑起来稳定很多。3. 监控落地从添加主机到告警通知全流程3.1 添加主机、绑定模板、配置宏容器跑起来只是第一步真正干活的是往 Zabbix 里添加被监控的主机。登录 Web 界面后进入“数据采集 → 主机”页面点击“创建主机”。添加 Linux 主机时主机名称要填写一个方便识别的名字群组可以选“Linux servers”接口填写被监控机器的 IP 地址端口保持 10050 不动。添加完主机后立刻做“链接模板”操作。Zabbix 里模板就是一组预定义的监控项、触发器、图形的集合比如“Linux by Zabbix agent”模板自带 CPU、内存、磁盘、网络等几十个监控项不用自己一个个手工添加。模板选好后系统会自动开始借助 zabbix-agent 采集数据。我用一个小技巧验证配置是否成功在模板链接页面查看“最新数据”如果新主机有数据进来自动增加说明 agent 通信正常。如果要监控交换机等网络设备添加主机时“接口”那里选择“SNMP”协议版本根据设备的实际配置选 v2c 或 v3。比如监控一台华为交换机模板选择“Huawei VRP by SNMP”填写 SNMP community默认是 publicZabbix 就能自动收集端口流量、CPU 使用率和内存占用。很多刚上手的朋友容易忽略交换机上要开启 SNMP 服务Agent 方式有 Agent 协议SNMP 方式又是另一套协议两边都没部署的话自然没有数据。宏Macro是管理不同配置差异的利器。比如 30 台 Linux 服务器都套用同一个模板但每台机器的某个路径、端口不一样这时候就在主机级别配置用户宏。我监控 Nginx 状态页时就在每台主机上设置{$NGINX_STATUS_URL}值为各自的访问地址模板里的监控项统一引用这个宏。这样做的好处是模板不动主机间差异通过宏隔离配置管理干净很多。3.2 自定义监控项与告警动作配置对于官方模板覆盖不到的场景自定义监控项是必须掌握的能力。拿我监控某 Java 应用为例应用会定期往一个日志文件里写入心跳时间戳我需要确认应用是否还活着。先在 Zabbix Agent 配置文件里加上 UserParameterUserParameterapp.heartbeat,stat -c %Y /data/app/last_heartbeat.log这个配置的意思是当 Zabbix Server 查询app.heartbeat这个 key 时Agent 会在被监控机器上执行stat命令把文件最后修改时间的时间戳返回给 Server。然后在前端“数据采集 → 监控项”里创建监控项键值填app.heartbeat信息类型选“数字无正负”。光有监控项还不够还得配触发器否则数据只存储不告警。触发器的本质就是“判断监控项是否异常”的规则表达式。比如发现心跳时间戳超过 60 秒没更新就触发告警last(/Application Server/app.heartbeat) (unixtime() - 60)表达式里的/Application Server/是主机名app.heartbeat是监控项 key整个表达式的含义是“最后一次获取的心跳时间戳距离当前时间超过 60 秒”也就是应用已有 60 秒没有刷写心跳日志。添加触发器的界面里可以预览表达式是否可以计算如果配置有误系统会精确提示并有语法检查所以新手不用担心填错。告警动作的配置路径是“告警 → 动作 → 触发动作”。我一般配置两个动作一个是把问题等级为严重和灾难的告警发给运维微信群另一个是把所有恢复通知发给值班邮箱。动作条件可以按触发器严重级别过滤也可以按主机群组过滤避免无关告警轰炸。3.3 告警媒介配置对接邮件、钉钉、企业微信Zabbix 的告警媒介类型默认有 Email、SMS 等但国内用得多的是钉钉和企微这块需要一个告警脚本包一下。我的做法非常直接在宿主机写好脚本把告警内容 POST 到钉钉机器人的 Webhook 地址即可。容器环境里跑脚本需要把脚本目录映射到容器里去这正好对应我在 2.2 节里设置的./data/alertscripts卷映射。脚本逻辑很简单主要就是拼 JSON#!/usr/bin/env python3 import requests import sys webhook https://oapi.dingtalk.com/robot/send?access_token你的token subject sys.argv[1] message sys.argv[2] # 拼接消息内容然后 requests.post 发过去 payload { msgtype: text, text: { content: fZabbix 告警通知\n主题{subject}\n详情{message} } } requests.post(webhook, jsonpayload)脚本写完放到alertscripts目录记得chmod x加执行权限。然后在“告警 → 媒介类型 → 钉钉”里添加一个媒介类型脚本名称填脚本的绝对路径参数按顺序传告警的主题和内容。接下来在用户配置里给 Admin 用户添加该媒介并设置接收告警的严重级别。这里有一个我在实际中踩过坑的细节容器内执行脚本时环境变量和 PATH 和宿主机不一样。刚开始脚本里用了系统 Python3 的某个第三方库容器里没装脚本一直报错。后来我改成脚本里直接用标准库的urllib不依赖第三方包兼容性就好很多。写告警脚本时尽量少依赖外部库这是血的教训。再提一个锦上添花的点Zabbix 大屏。如果领导想看整体系统状态可以在“报表 → 监控大屏”里创建自定义大屏把关键主机的 CPU、内存等指标图形放到一块。默认的“问题主机”大屏也能自动展示当前异常的主机和告警数量。配合 Zabbix 6.4 的暗色主题大屏投影到办公室屏幕上效果还挺专业。4. 实战问题排查这几类坑我基本都踩过4.1 “Zabbix server is not running”的排查全记录如果你在 Zabbix Web 界面顶部看到黄色横幅提示Zabbix server is not running: the information displayed may not be current.不要慌这是 Zabbix 里最常见的问题之一我遇到过好几次。这个提示的本质是Web 前端连不上 Zabbix Server 进程或者 Server 进程本身已经挂了。按照我的排查经验一般按下面的顺序来第一步检查 Server 容器是否在正常运行docker ps | grep zabbix-server docker logs zabbix-server --tail 100docker logs是这里最重要的命令。如果看到数据库连接失败的信息那就是 4.2 节要讲的问题如果看到 Server 正在正常启动、进程没退出那可能是 Web 端配置的ZBX_SERVER_HOST指向错了。我用 compose 编排时会在 web 环境变量里写ZBX_SERVER_HOST: server如果服务名写错Web 端就找不到 Server。第二步确认 Server 的 10051 端口是否能连通。在宿主机上执行telnet 127.0.0.1 10051如果端口通说明 Server 进程在监听。有些云服务器需要安全组放行 10051 端口否则外部 Agent 无法上报数据但 Web 界面访问用的是 8080所以容易出现“网页能打开但其实 Server 收不到数据”的假象此时界面也会提示 Server 未运行。第三步检查 Server 和数据库之间的连接。如果 MySQL 容器因为异常重启过Zabbix Server 的连接池可能没有正常恢复最有效的办法是直接重启整个 compose 栈。我经常说“重启治百病”在容器世界里是有效的更新了配置、改了环境变量后不重启确实不会生效docker compose down docker compose up -d如果重启后问题还在那就需要看看是不是 Server 进程和系统的时区时钟不同步导致的探测超时把容器时区统一调整为 Asia/Shanghai再把宿主时区也校准一下基本能解决。4.2 数据库连接、中文乱码、镜像下载慢等高频问题数据库问题是 Zabbix 部署里的重头戏我列一个高频问题速查表供大家直接对照报错现象核心原因解决办法Access denied for user replace_userlocalhost数据库密码与 Server 配置不一致检查 compose 里 MYSQL_USER/MYSQL_PASSWORD 是否与实际一致Server 日志提示 cant connect to MySQL server数据库容器没起来或网络不通docker ps看 db 容器状态docker logs查看 MySQL 错误日志数据库初始化失败版本升级时 schema 兼容问题先备份数据再尝试官方提供的数据库升级镜像Web 界面中文显示乱码缺少中文字体文件在 web 容器里安装 fonts-noto-cjk或把宿主机中文字体映射进容器中文乱码这个问题我在内网部署时遇到过Zabbix 默认镜像里没包含中文字体标题或主机名有中文时显示为方框。解决方案是在 web 容器里执行apt-get install -y fonts-noto-cjk或者更简单的做法用 Dockerfile 基于官方镜像打一个带中文字体的自定义镜像一劳永逸。镜像下载慢也是很多人卡住的地方。docker pull拉 Zabbix 相关镜像时有 MySQL 8.0、Zabbix Server、Zabbix Web、Agent加起来有几个 GB。如果在国内服务器上直接拉官方 Docker Hub速度可能非常感人。解决办法是配置镜像加速器在/etc/docker/daemon.json里写入{ registry-mirrors: [你的加速器地址] }修改后执行systemctl daemon-reload systemctl restart docker重启 Docker 服务。如果是 Windows 环境用 Docker Desktop直接在“Settings → Docker Engine”里配置镜像源数组即可配置项一样。需要注意不同服务商的加速器地址可能有效期不同如果某一天拉镜像又变慢了优先检查加速器是否还在生效。4.3 进阶场景监控 Windows GPU 与交换机怎么接进来热词里有不少人在搜 Zabbix 监控 Windows GPU这其实是监控非通用硬件的典型场景。官方模板默认不包含 GPU 监控项需要自己去取数。我的做法是在 Windows 目标机器上配置 Zabbix Agent然后用 UserParameter 调用 PowerShell 命令获取 GPU 使用率# 在 zabbix_agentd.conf 里添加 UserParametergpu.utilization,powershell -Command (Get-Counter \GPU Engine(*)\Utilization Percentage -ErrorAction SilentlyContinue | Select-Object -ExpandProperty CounterSamples | Measure-Object -Property CookedValue -Maximum).Maximum需要注意的是PowerShell 命令输出的数字可能会有多余的空格或字符Zabbix Agent 拿到后在监控项里把信息类型设置成“浮点数”这样数值就能正常存储和画图了。GPU 的温度监控更麻烦一些通常需要读取显卡驱动提供的 WMI 接口不同显卡厂商的访问方式不同这块没有统一模板基本只能靠脚本自己实现。交换机监控相对简单一些因为标准网络设备都支持 SNMP 协议。前面在 3.1 章节提过在创建主机时选择 SNMP 接口而不是 Agent 接口填上设备 IP、端口 161、SNMP 版本和 community。模板方面Zabbix 官方模板库里提供了 Cisco、Huawei、H3C 等主流厂商的模板直接链接就能用。需要注意的坑是交换机的 SNMP community 一定不要用默认的 public不然内网里容易被扫描器探测到设备开放信息和端口状态。生产环境建议配置 ACL限制 SNMP 只对监控服务器网段开放。关于“其他主机怎么添加 Zabbix 监控”这类问题方法完全取决于被监控主机的操作系统。Linux 主机一般是装 zabbix-agent 包修改 Server 地址后启动服务Windows 主机就是下载 MSI 安装包安装时填入 Zabbix Server 地址或者静默安装时通过命令行参数传入。不管哪类主机添加完成后在 Zabbix Web 端创建主机并把 IP 填对Zabbix Server 会主动向被监控主机发起连接请求Agent 被动模式所以只要被监控主机能访问到 Server 的 10051 端口即可正常工作。如果网络有隔离可以考虑开启 Agent 主动模式让被监控主机主动上报数据到 Server配置更适应一些跨网段的监控场景。这套 Docker 化的 Zabbix 部署方案我在公司运维环境里跑了快一年稳定性相当可靠期间经历过几次宿主机重启compose 里的restart: always策略让所有容器自动恢复基本做到了无人值守。最后再分享一个小技巧如果想让 Zabbix Server 的采集性能更好一层可以在 compose 的 server 服务里加上ZBX_STARTPOLLERS环境变量数值根据机器核数适当调大比如 8 核机器可以设成 16这能让 Zabbix Server 并发采集更多主机的数据。我调大之后几百台机器的采集延迟明显下降监控数据刷新也快了很多。如果你的监控规模在持续扩大这个参数值得一试。