
最近好几个朋友问我同一个问题生产环境里到底要不要用 Docker 跑 Zabbix他们的顾虑很典型——Zabbix 组件多、依赖重、版本升级麻烦直接用 Docker 又怕官方镜像和裸机部署行为不一致出了问题不好排查。我自己的结论是用而且推荐用 Docker Compose 统一编排前提是你得先把 Zabbix 启动后的组件关系、数据库初始化逻辑和告警链路搞清楚。这篇就把我从零部署到接入主机、配好告警、怼完各种坑的完整过程写出来不是官档复读机全是实际敲过命令、看过日志之后留下的东西。文章覆盖从镜像选型、Compose 编排、常见报错排查到添加主机、配置邮件告警、再往监控大屏、GPU 和交换机方向扩展。适合已经会一点 Docker、准备把 Zabbix 落地到测试环境或者中小规模生产环境的同学也适合那些裸机装过 Zabbix 但没试过容器化部署的老人。1. 为什么用 Docker 跑 Zabbix先把服务拆开看1.1 一整套 Zabbix 到底由哪些组件组成很多人第一次装 Zabbix 就被绕晕其实整套系统拆开以后就四块。第一块是 Zabbix Server负责接收采集数据、触发计算、执行告警逻辑是整个平台的大脑。第二块是数据库Zabbix Server 本身不带存储能力所有监控项历史数据、触发器状态、报表配置全都要落到数据库里生产环境最常见的是 PostgreSQL 和 MySQL 两派。第三块是 Web 前端也就是你浏览器里打开的那个界面官方镜像用 Nginx PHP 把界面跑起来。第四块是 Agent部署在被监控主机上负责采集 CPU、内存、磁盘这类基础指标现在官方主推的是 Agent2比老版 Agent 多了很多内置插件扩展性好得多。除此之外还有两个按需组件。一个是 Zabbix Proxy适合跨机房、大规模环境由 Proxy 代替 Server 去采集数据再把数据转发回来能分担 Server 压力。另一个是 Java Gateway专门用来监控 JMX 类的 Java 应用。刚开始用的话后两个可以先不碰把核心四件套跑起来就能覆盖绝大多数场景。容器化部署和裸机部署的本质区别在于裸机安装时系统服务帮你处理了组件启动顺序、环境变量配置、日志文件位置这些事而 Docker 世界里这些事全要你自己负责镜像只是把软件本体和运行环境打包好编排得靠 Compose 或 K8s。这就是为什么很多人第一次用 Docker 跑 Zabbix会遇到Web 能打开但显示 Zabbix server is not running这类问题——不是镜像坏了而是组件之间没对齐。1.2 镜像版本与仓库选型官方在 Docker Hub 上有完整的镜像矩阵命名非常有规律关键要看后缀。zabbix/zabbix-server-pgsqlServer 组件打包了 PostgreSQL 客户端用于连接外部数据库zabbix/zabbix-web-nginx-pgsqlWeb 组件Nginx PHP带 PostgreSQL 驱动zabbix/zabbix-agent2Agent2采集本机指标zabbix/zabbix-web-nginx-mysqlWeb 组件对应的 MySQL 版本同理 server 也有 mysql 后缀版本号建议直接上 7.0 LTS当前最新的长期支持版本官方会持续维护到 2029 年左右。不要用 latest 标签跑生产环境latest 每次拉取都可能悄悄变更版本哪天升级了数据库结构你可能都没注意到。我习惯固定到大版本再带一个具体小版本比如 7.0-ubuntu-latest 这种既保证稳定性又能吃到 Bug 修复补丁。数据库镜像我选的是 PostgreSQL 16。Zabbix 7.0 官方文档里明确了支持的数据库版本范围PostgreSQL 16 没问题。选 PG 而不是 MySQL 的主要原因是 Zabbix 在 PG 上的分区表维护、历史数据清理能力表现更稳而且官方镜像的 pg 版本更新也更积极。当然你如果公司已有 MySQL 基础设施选 mysql 后缀也没问题后续配置思路完全一致。网络方面如果服务器在国内Docker Hub 直连经常会慢到你怀疑人生。这个我放到后面排查部分专门说这里先提醒一句先用加速器或者配置 mirror否则编排文件写好了一拉镜像就卡住特别打击信心。2. 编排文件怎么写网络规划、存储规划、环境变量2.1 网络与存储先把数据目录和时区定好动手写 Compose 之前有两件事值得先花十分钟想清楚数据要存哪里容器之间怎么通信。Zabbix 的数据全在数据库里监控模板、告警配置、历史性能数据丢了等于整个平台白装。所以 PostgreSQL 容器必须挂载一个宿主机目录或者 Docker Volume。我习惯挂宿主机目录原因很简单——备份时可以直接看到文件不需要在容器里执行 pg_dump 再拷出来。目录结构大概这样。/opt/zabbix ├── docker-compose.yml ├── data │ └── postgres └── alertscriptsalertscripts 目录也是必须的Zabbix 在执行自定义脚本类型的告警媒介时要读取这个目录下的脚本。官方镜像默认路径是 /usr/lib/zabbix/alertscripts如果不把宿主目录挂载进去你以后想接企业微信、钉钉机器人这类自定义告警就得进容器改文件容器一重建改动全丢。吃过这个亏之后就老老实实挂出来了。网络方面同一台机器上的容器之间建议走自定义 bridge 网络而不是用容器 IP 互联。容器重建后 IP 会变如果你在环境变量里写了硬编码 IP重建一次挂一次。Compose 会自动为你创建网络服务之间直接用服务名互相访问比如 zabbix-server 连接数据库时填写主机名 zabbix-db这个由 Docker 内置 DNS 自动解析。时区问题也是容器部署特有的坑。很多镜像默认时区是 UTCZabbix 前端如果不设置 PHP 时区界面上所有时间都比北京时间慢 8 小时。排查告警时间对不上先看时区这个比看什么配置都快。2.2 docker-compose.yml 全量配置解读直接贴我目前在生产环境验证过的编排文件Zabbix 7.0 全家桶。version: 3.8 services: zabbix-db: image: postgres:16-alpine container_name: zabbix-db restart: always environment: POSTGRES_USER: zabbix POSTGRES_PASSWORD: Zabbix2024!Strong POSTGRES_DB: zabbix volumes: - ./data/postgres:/var/lib/postgresql/data networks: - zabbix-net zabbix-server: image: zabbix/zabbix-server-pgsql:7.0-ubuntu-latest container_name: zabbix-server restart: always environment: DB_SERVER_HOST: zabbix-db POSTGRES_USER: zabbix POSTGRES_PASSWORD: Zabbix2024!Strong POSTGRES_DB: zabbix ZBX_CACHESIZE: 256M ZBX_HISTORYCACHESIZE: 128M ZBX_TRENDCACHESIZE: 128M ports: - 10051:10051 volumes: - ./alertscripts:/usr/lib/zabbix/alertscripts:ro depends_on: - zabbix-db networks: - zabbix-net zabbix-web: image: zabbix/zabbix-web-nginx-pgsql:7.0-ubuntu-latest container_name: zabbix-web restart: always environment: ZBX_SERVER_HOST: zabbix-server DB_SERVER_HOST: zabbix-db POSTGRES_USER: zabbix POSTGRES_PASSWORD: Zabbix2024!Strong POSTGRES_DB: zabbix PHP_TZ: Asia/Shanghai ports: - 8080:8080 depends_on: - zabbix-server - zabbix-db networks: - zabbix-net zabbix-agent2: image: zabbix/zabbix-agent2:7.0-ubuntu-latest container_name: zabbix-agent2 restart: always environment: ZBX_SERVER_HOST: zabbix-server ZBX_HOSTNAME: Zabbix server ports: - 10050:10050 networks: - zabbix-net networks: zabbix-net: driver: bridge逐个说下关键点。数据库连接三件套 DB_SERVER_HOST、POSTGRES_USER、POSTGRES_PASSWORD 必须和数据库容器完全一致。Zabbix Server 在启动过程中会去连数据库、跑迁移脚本、写入初始数据任何一个字段不一致都会导致 Server 启动失败然后你在前端页面就会看到那个著名的报错。ZBX_CACHESIZE这类配置属于调优参数默认值偏保守。监控主机数量超过 50 台或者监控项数量很多时建议把 Cachesize 从默认的 64M 提到 256MHistoryCacheSize 和 TrendCacheSize 也一并加大。不要一开始就堆很大我见过有人直接给 2G结果内存全被缓存吃掉容器被 OOM 杀掉这种反而得不偿失。端口映射有一个容易忽略的点Zabbix Server 的 10051 端口必须暴露出来这是被监控 Proxy 和 Agent 主动上报数据的入口。Web 端口暴露 8080 是前端访问入口用宿主机 8080 是为了避免和常见的 80 端口业务冲突。Agent2 暴露 10050 端口只是为了让宿主机也能被监控。2.3 首次启动的等待与初始化验证编排文件写好后执行 docker compose up -d 启动。这里有个新手最容易误判的点Zabbix Server 和 Web 容器第一次启动时处于一个等待数据库就绪的状态日志里会反复出现重试连接数据库的记录看起来像报错其实是在等 PostgreSQL 初始化完成。我用过的判断方法很简单docker compose logs -f zabbix-server看到日志中出现类似 server started 的字样时说明 Server 已经就绪。接着再看 Web 容器的日志直到 Nginx 输出访问日志就可以打开浏览器访问了。打开 http://服务器IP:8080 后默认管理员账号是 Admin密码是 zabbix首次登录系统会要求修改密码。很多人在这一步就以为部署完了实际上距离企业级监控还差得远——你还没有任何监控数据。下一节先处理那些影响部署体验的报错因为这些坑不填掉后面配置告警时会反复被干扰。3. 部署中的高频报错排查过程完整复盘3.1 Zabbix server is not running 不是玄学打开前端页面后顶部出现黄条提示 Zabbix server is not running: the information displayed may not be current. 这是容器化部署里出现率最高的告警。别慌它不是指服务器宕机了而是 Web 前端无法确认 Server 进程的实时状态。我的排查链路是这样走的按顺序看基本十次能解决九次。第一步确认 Server 容器是否还活着。docker ps | grep zabbix-server docker compose ps如果容器状态不是 Up大概率容器启动到一半退出了用 docker compose logs zabbix-server 看最后的堆栈。最常见的是数据库连接失败导致的退出。第二步如果容器是 Up 状态但日志没有任何输出那问题可能出在 Web 前端和 Server 的配置一致性上。最典型的场景是你在 zabbix-web 容器里设置 ZBX_SERVER_HOST 时写了 localhostWeb 容器认为 Server 在它自己里面当然找不到。必须写成服务名 zabbix-server或者写宿主机的真实 IP并保证从 Web 容器能访问到宿主机的 10051 端口。第三步检查宿主机的防火墙。10051 和 8080 这两个端口如果你在服务器上启用了 firewalld 或者 ufw外部访问就会被拦。尤其是云服务器安全组里不放行 8080 端口前端页面根本打不开而 10051 不放行Agent 主动上报就会被丢包。第四步Zabbix 7.0 之后还有一个特殊场景前端显示 not running但容器日志完全正常。这时候要看一下数据库里是不是有残留的旧 Zabbix 服务记录。如果你之前用裸机或容器跑过另一套 Zabbix复用了同一个数据库实例旧的监控记录可能导致 Web 混乱。这种情况建议重新建一个全新的数据库不要复用。3.2 Access denied for user replace_userlocalhost 的来历这个报错在启动 Server 容器时很常见尤其当你看了网上一些较早的教程照着配置了 MySQL 版本的镜像后报错里会出现一个莫名其妙的 replace_userAccess denied for user replace_userlocalhost (using password: YES)看到这行字先笑一下然后冷静判断。它本质是数据库账号密码认证失败。replace_user 这个字符串来源于 Zabbix 镜像里的一个临时占位符环境变量很多老教程或者自动化脚本会直接用 ZBX_DB_USERreplace_user 占位如果你没有覆盖成真实的数据库用户名容器启动时就会拿着 replace_user 去连数据库数据库里当然没有这个用户于是 Access denied。解决办法很简单把连接数据库相关的环境变量统一改正确我用的是 zabbix 用户密码和 POSTGRES_PASSWORD 保持一致。这里有个很容易踩的次要坑PostgreSQL 容器在首次初始化时通过 POSTGRES_USER、POSTGRES_PASSWORD 创建数据库用户和密码这个初始化只在数据卷为空时执行一次。如果你改过密码但数据卷还是老的新密码不会生效。所以改密码的正确姿势是把 data/postgres 目录删掉重新初始化或者用 psql 手动在数据库里 ALTER USER。还有一个变种报错里的用户名不是 replace_user而是 zabbix但密码不对。这种情况通常是你在 compose 文件两个服务里写的密码不一致或者数据库数据卷是之前用另一个密码初始化的。统一检查三处——db 容器、server 容器、web 容器里的密码是否完全一致。3.3 镜像拉取慢与国内加速方案Docker 镜像拉取慢这个问题几乎每个部署的人都会遇到。尤其是 zabbix-server-pgsql 这种镜像体积大而且层级多直连 Docker Hub 经常卡在几十 KB/s。我的处理方式是配置 Registry Mirror。Docker Daemon 支持在 /etc/docker/daemon.json 里配置多个加速地址配置完要重启 docker 服务sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [https://docker.m.daocloud.io] } EOF sudo systemctl restart docker配置好之后再用 docker info 确认 Registry Mirrors 已经生效。注意如果之前已经拉取了一部分层可能仍然从旧源继续拉最省事的是重试一次 docker compose pull。这个属于环境层面的问题和 Zabbix 本身无关但是不解决它后续升级镜像版本、拉 Agent2 镜像都会难受。还要补充一句有些公司内网有私有镜像仓库可以先把 Zabbix 官方镜像推送到内网 Harbor生产服务器全部走内网拉取。这种方式速度最稳也是我在比较大的团队里强烈推荐的方式。4. 跑起来之后添加主机、套模板、把告警送到手里4.1 先在 Zabbix Server 容器本机加第一台主机平台跑通后第一件事是监控一台真实主机验证从采集到展示的完整链路。我建议先监控 Zabbix Server 容器宿主机本身因为这个动作排障路径最短。在数据采集 → 主机页面点击创建主机主机名称填一个你认识的比如 localhost可见名称随意。所属群组建议先建一个Linux servers群组后面主机多了好归类。关键字段是接口Zabbix Agent 接口的 IP 地址填 127.0.0.1 或宿主机内网 IP端口默认 10050。模板选择这一步很关键。Zabbix 官方自带模板里有一组 Linux by Zabbix agent不同版本名称略有差异它会自动关联 CPU、内存、磁盘、网络、系统负载等一整套监控项和触发器。选好模板后点击更新等一两分钟再到监测 → 最新数据里按主机过滤如果能看到 CPU iowait、内存 available 这类数据在跳说明采集链路已经通了。这里有个常见误区很多人在接口里填了容器 IP或者填了 127.0.0.1但 Zabbix Server 跑在容器里主动去连接 Agent 时网络路径不通。因为 Server 容器和宿主机不是同一个网络命名空间它访问 127.0.0.1 访问的是容器自己压根碰不到宿主机的 Agent。所以要么填宿主机在 Docker 桥接网络中的 IP要么让 agent2 容器和 server 容器都在同一个 compose 网络里使用服务名互通。二者相比后者更稳。4.2 邮件告警的完整链路监控没告警等于白装。Zabbix 告警链路一共四段每一段都要配通有一个环节断掉警报就发不出去。第一段是报警媒介类型就是告警发送通道。Zabbix 自带 Email、脚本、Webhook 等类型。我生产环境里最常用的是脚本类型因为它能对接企业微信、钉钉、飞书机器人。进入报警媒介类型页面选择脚本填写脚本名称脚本内容预先放在我们第一卷挂载的 alertscripts 目录里。比如写一个 send_dingtalk.sh脚本思路很简单收取 Zabbix 传入的收件人、主题、消息三个参数拼成飞书或钉钉的消息结构然后 curl 到机器人 Webhook。第二段是用户和报警媒介。在用户里创建一个告警接收账号并给这个账号添加报警媒介关联到上一步配置的脚本。注意一个细节Zabbix 要求用户至少有一个报警媒介后告警动作才会触发消息发送如果告警没有发送给任何用户系统不会自动投递。第三段是动作。进入告警 → 动作 → 触发动作创建一条新动作。条件里一般设置触发器严重性 ≥ 警告这样误报率能低很多。操作配置里勾选发送消息给指定用户并通过步骤持续时间来定义升级策略比如 0 分钟立即通知30 分钟后再次通知。第四段是触发器本身。每个模板自带很多触发器比如 CPU 负载过高、磁盘使用率超阈值。你不需要自己写但要确认这些触发器状态是已启用。模板套用后触发器默认启用大多数情况下不用动。4.3 验证告警闭环从故意触发到消息落地配置完所有环节必须做一次真实的告警演练。我的做法很粗暴在一台测试主机上跑一个命令把 CPU 打满。yes /dev/null 等一两分钟Zabbix 的触发器检测到负载超过阈值触发动作消息发到钉钉或邮箱。这时候你回到监测 → 问题页面应该能看到一条状态为问题的记录。处理完测试后kill 掉那个进程过几分钟再去看问题应该自动恢复为已解决。我第一次配的时候就踩了消息能发但恢复通知不触发的坑原因是动作里只配置了问题状态的操作没有配置恢复状态的操作。后来在动作的恢复操作里同样加上发送消息才算闭环。还有一个经验验证告警时不要直接在生产主机上测试。你永远不知道一个负载命令会在哪个模块引发连锁告警。先在测试机上打满记录下告警消息的格式、时间延迟、是否重复发送确认无误后再把同样的媒介配置应用到生产主机。5. 贴近实际场景的扩展大屏、GPU 与网络设备5.1 监控大屏怎么快速做出效果Zabbix 7.0 自带仪表盘功能在监测 → 所有仪表盘里可以创建拖拽式大屏CPU 曲线、内存趋势、磁盘空间、网络流量这些都能直接放进去。默认模板自带了很多图形和聚合面板新建仪表盘后从左侧组件列表拖出来即可。不过如果你追求更漂亮的视觉效果或者想让大屏同时展示 Zabbix 之外的 Prometheus、Elasticsearch 数据我更推荐用 Grafana 做前端展示层。Grafana 有官方的 Zabbix 数据源插件安装后可以直连 Zabbix Server 的 API把监控项数据查出来画成各种面板。网上不少团队的做法是Zabbix 负责采集和告警Grafana 负责展示和汇报。用 Grafana 接 Zabbix 时要注意一个兼容性问题插件版本和 Zabbix API 版本必须匹配。Zabbix 7.0 的 API 兼容性不错但建议在 Grafana 里先创建一个只读账户避免把 Admin 密码写在数据源配置里。另一个细节是时间范围Zabbix 数据库里的历史数据有保留周期默认趋势数据保留 365 天历史数据保留更短大屏上如果时间范围跨越了保留周期曲线尾部会被截断注意这一点别拿去汇报时才发现。5.2 Windows GPU 和交换机监控容器化部署 Zabbix 之后最常被问到的就是怎么监控 Windows 服务器的 GPU 温度以及那些不支持安装 Agent 的网络设备。这两个场景代表了 Zabbix 扩展能力的两种路径。先看 Windows GPU。Zabbix Agent2 自带基于第三方工具的 GPU 插件实测下来这个方案最省事。在 Windows 主机上安装 nvidia-smi 之后Agent2 插件可以直接读取 GPU 利用率、显存占用、温度这些指标。配置方面提前做一步确认 Windows Agent2 能读到 nvidia-smi 的路径并把路径加入系统 PATH。如果 Agent2 以服务方式运行还要注意服务账户是否有权限执行 nvidia-smi很多人卡在这一步——本地运行命令没问题服务运行就是数据为 0基本是权限问题。再看交换机监控走 SNMP 协议。在 Zabbix 里创建主机时接口类型选择 SNMP填入交换机的管理 IP 和团体名或者 SNMP v3 用户凭据再关联官方自带的网络设备模板比如 Cisco IOS by SNMP 或 Generic by SNMP。大多数品牌的交换机都能通过这种方式采集端口状态、流量、CPU 负载。唯一要注意的是交换机上必须开启 SNMP 读写至少只读并且访问控制要收紧到只有 Zabbix Server 所在网段能访问不要让团体名暴露在公网。5.3 容器化部署后的日常运维心得最后分享几条只有把 Zabbix 跑在容器里之后才会明白的经验。升级这件事容器化反而更简单了。Zabbix 7.0 升级到新 patch 版本时只要停掉旧容器修改镜像标签为新的小版本然后 docker compose up -d数据库结构迁移会自动跑一遍。但千万不要先把数据库容器升级再启动旧版 Server这种版本错位会让数据库里的 schema 和 Server 代码不匹配启动直接失败。升级顺序必须是 Server 和 Web 一起升数据库可以保持不动除非你同时也要升 PG 大版本。备份策略上容器化部署的备份重点是数据库不是整个目录。我最常用的备份命令docker exec zabbix-db pg_dump -U zabbix zabbix | gzip zabbix_backup_$(date %F).sql.gz每天凌晨跑一次保留最近 7 天和每月月初一份恢复时只需要把备份文件导入一个新的 PG 容器再启动 Server 和 Web 指向这个数据库即可。配置文件本身都在 docker-compose.yml 和挂载目录里只要这两样不丢整套平台随时可以重建。还有一个细节容器日志的保留策略。Docker 默认不对容器日志做切割Zabbix Server 跑久了/var/lib/docker/containers/ 下的 json 日志文件会越来越大。在 daemon.json 里加上 log 配置限制单文件大小和保留数量这个动作比什么日志清理脚本都有效。{ log-driver: json-file, log-opts: { max-size: 50m, max-file: 3 } }我在实际工作中发现很多团队部署 Zabbix 不是为了看那几个花哨图表而是希望在凌晨 3 点服务器磁盘写满之前收到一条告警能提前介入。容器化部署的真正优势在于你可以用一套模板快速复建整套监控平台数据库、Server、Web、Agent 的配置全部代码化无论部署到哪台服务器结果都是一样的。这比在裸机上靠记忆做手工配置要可靠得多。后续如果监控规模变大还可以横向加 Proxy或者把当前这套 Compose 文件移植到 K8s 里跑方向都在你已经建立的这套基础上延伸。