用Docker Compose部署Zabbix 7.4监控平台:从配置到告警的完整实践
想了很久在监控工具里到底该选谁最后还是把 Zabbix 7.4 用 Docker 跑了起来。这套组合不是灵光一闪而是因为 Zabbix 本身是开源监控里功能最完整的那一档加上 7.4 这个版本在可视化、告警和采集性能上都做了不少优化Docker 又能把部署成本压到最低。这篇东西就是记录我实际部署的全过程包括 compose 文件的写法、环境变量怎么配、踩过哪些坑适合正在做监控选型、或者刚接手 Zabbix 的人直接抄作业。1. 为什么要用 Docker 跑 Zabbix 7.41.1 Zabbix 7.4 解决了什么问题Zabbix 7.4 给我的第一感觉是“终于把界面和配置逻辑理顺了”。老版本里常用的仪表盘、主机组、模板关联都藏在多级菜单里新版本明显做了一次收拢很多操作不用再跳来跳去。另一个比较实在的变化是监控项的处理效率官方给出的数据是单台 server 可以支撑的监控项数量比之前版本更进一步实际用下来同一套配置下历史数据查询的响应速度也要快一些。不过选 7.4 最重要的原因是它对容器环境更友好。官方镜像仓库里提供了 server、web、agent 的全套镜像tag 直接对应版本号不再需要自己用源码编译或者手工改配置文件。这一点对中小团队尤其关键监控系统本身越省事才越有精力去整理业务侧的告警规则。1.2 Docker 部署与裸机部署的取舍如果只有两三台服务器很多人会觉得直接装个 RPM 包就够了。确实单机部署 Zabbix 的安装过程也不算复杂但一旦涉及升级、回滚、迁移问题就来了。我见过不止一个团队因为服务器上残留着旧版本的依赖库导致升级到新版本时数据库 schema 迁移失败最后只能重新部署。Docker 把运行环境和依赖一起打包很大程度上规避了这类问题。容器化也让“一个监控平台同时跑多个监控场景”变得更简单。比如需要临时测试告警规则可以在同一台宿主机上再起一个隔离的实例想升级版本把镜像 tag 改掉重启 compose 项目不行就切回旧 tag整个过程对现有监控数据的影响很小。当然代价也有Docker 网络、存储卷、容器日志这些概念需要额外理解但相比之下收益远大于学习成本。1.3 整体架构与运行原理Zabbix 7.4 的 Docker 部署通常拆成三个核心容器数据库、Zabbix Server、Zabbix Web另外再加一个 Agent2 容器用于采集宿主机自身状态。数据库负责存配置和监控历史数据Server 是逻辑大脑负责轮询、数据处理、触发告警Web 是前面的界面层负责渲染仪表盘和接受操作指令。三个容器各司其职通过一个自定义 bridge 网络互相通信。Agent2 的作用容易被低估。它不只是“装在被监控机器上”的东西在 Docker 部署场景里还可以把宿主机本身纳入监控顺便通过主动模式汇报数据。这样即便被监控网络的防火墙限制比较严格只要宿主机能出站到 Server 的 10051 端口监控链路仍然是通的。2. 部署前的规划与关键决策2.1 数据库选型PostgreSQL 还是 MySQLZabbix 7.4 官方支持 PostgreSQL 和 MySQL 两种主流数据库。我的建议是新部署无脑选 PostgreSQL。原因不是 MySQL 不能用而是 Zabbix 在 PostgreSQL 上的分区表、历史数据批量清理机制支持得更成熟遇到大规模监控项时不容易出现锁表现象。此外官方镜像里zabbix/zabbix-server-pgsql和zabbix/zabbix-web-nginx-pgsql的 tag 维护最及时避坑概率更高。如果团队里已经有成熟的 MySQL 运维体系也不是不能选 MySQL但要注意字符集和时区设置避免写入中文乱码或者时间偏移。真要我给一个硬性建议只要不是历史包袱太重数据库就选 PostgreSQL后续备份、调优、迁移都会轻松不少。2.2 镜像 tag 与版本配套Docker 部署最容易犯的错误是乱用 tag导致 server 是 7.4 而 web 是 7.2数据库 schema 直接不兼容。官方镜像仓库里 7.4 对应的核心镜像如下组件镜像名推荐 tag数据库postgres16-alpineServerzabbix/zabbix-server-pgsql7.4-latestWebzabbix/zabbix-web-nginx-pgsql7.4-latestAgentzabbix/zabbix-agent27.4-latest这里有个细节Web 镜像里其实已经内置了 Nginx 和 PHP-FPM不需要额外再装一个 Nginx外部访问直接映射 Web 容器的 8080 端口即可。数据库镜像我选了 Alpine 版体积小不少对监控系统这类长时间运行的服务来说也更干净。2.3 数据持久化方案Zabbix 的数据安全完全依赖于持久化配置做对了没有。最稳妥的方案是数据库用 Docker volume而 server 和 web 容器不需要持久化任何数据因为真正的状态都在数据库里。有人习惯用宿主机目录 bind mount 来存数据库也可以但要注意目录权限PostgreSQL 容器内的postgres用户 UID 是 70权限不对会出现“Permission denied”导致数据库起不来。建议在部署前就定义好 volume 的命名后续做备份和迁移时可以直接用docker run --volumes-from或者pg_dump从容器里把数据导出来避免跟不同项目的挂载点搞混。3. 基于 Docker Compose 的一键部署实操3.1 准备工作与目录规划我先在一台干净的 Linux 服务器上做演示系统是 CentOS 7.9 的内核层面兼容方案但实际用的发行版是 Debian 系原因不再展开重点是想说明这个方案跟发行版关系不大只要 Docker Engine 和 Compose 插件可用就行。安装 Docker 后先建好项目目录mkdir -p /opt/zabbix在/opt/zabbix下放一个docker-compose.yml以及后续会用到的.env文件。为什么要单独建目录因为 compose 项目名称默认以目录名命名后续执行docker compose down时只会影响这个项目内的容器不会误伤其他服务。3.2 完整 compose 文件直接贴出我实际使用的 compose 配置services: zabbix-db: image: postgres:16-alpine container_name: zabbix-db environment: POSTGRES_USER: zabbix POSTGRES_PASSWORD: zabbix_pwd POSTGRES_DB: zabbix volumes: - zabbix-db-data:/var/lib/postgresql/data networks: - zabbix-net restart: unless-stopped healthcheck: test: [CMD-SHELL, pg_isready -U zabbix -d zabbix] interval: 5s timeout: 3s retries: 10 zabbix-server: image: zabbix/zabbix-server-pgsql:7.4-latest container_name: zabbix-server environment: DB_SERVER_HOST: zabbix-db DB_SERVER_PORT: 5432 POSTGRES_USER: zabbix POSTGRES_PASSWORD: zabbix_pwd POSTGRES_DB: zabbix ZBX_CACHESIZE: 128M ZBX_HISTORYCACHESIZE: 128M ZBX_TRENDCACHESIZE: 64M ports: - 10051:10051 volumes: - zabbix-server-alertscripts:/usr/lib/zabbix/alertscripts networks: - zabbix-net depends_on: zabbix-db: condition: service_healthy restart: unless-stopped zabbix-web: image: zabbix/zabbix-web-nginx-pgsql:7.4-latest container_name: zabbix-web environment: ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_PORT: 10051 POSTGRES_USER: zabbix POSTGRES_PASSWORD: zabbix_pwd POSTGRES_DB: zabbix PHP_TZ: Asia/Shanghai ports: - 8080:8080 networks: - zabbix-net depends_on: - zabbix-server restart: unless-stopped zabbix-agent2: image: zabbix/zabbix-agent2:7.4-latest container_name: zabbix-agent2 environment: ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_PORT: 10051 ZBX_HOSTNAME: Docker Host pid: host privileged: true networks: - zabbix-net depends_on: - zabbix-server restart: unless-stopped volumes: zabbix-db-data: networks: zabbix-net: driver: bridge几个关键点我单独说一下。ZBX_CACHESIZE这些缓存参数初始环境用默认值也能跑但我给的是适合几千个监控项的经验值后续监控项增加后可以按需调整。zabbix-server-alertscripts卷是给自定义告警脚本预留的一开始就挂出来后面要做 Webhook 或发短信脚本时不用动容器。Agent2 容器加了privileged: true是因为我想让它通过 mount 方式采集宿主机的磁盘和进程数据如果只是采基本 CPU、内存指标这个权限可以不开放。3.3 启动与日志检查在/opt/zabbix目录下执行docker compose up -d第一次启动会因为拉镜像和初始化数据库花一两分钟不要急着看页面。用下面的命令观察 server 是否正常docker compose logs -f zabbix-server正常日志里会出现类似server #0 started [Zabbix Server]的字样这时候再去访问 Web 端。数据库初始化过程最怕 server 容器在数据库未就绪时反复重启我的 compose 里已经用 healthcheck 加了依赖等待所以基本不会出现这个问题。如果日志一直在报连接拒绝优先查数据库容器状态。3.4 Web 界面初始化与中文设置浏览器打开http://服务器IP:8080第一次访问会进入安装向导。过程很简单确认数据库连接信息无误后Zabbix 会自动执行 schema 导入完成后跳转到登录页默认账号是Admin默认密码是zabbix。进来后第一件事是把界面语言改成中文。点右上角头像进入 User settings把 Language 改为Chinese (zh_CN)。这里有个常见坑如果PHP_TZ环境变量没设置或设置错误中文界面下时间会偏移告警时间对不上号所以我在 Web 容器的环境变量里已经写好了PHP_TZ: Asia/Shanghai。4. 常见故障与排查实录4.1 数据库连接不上的连锁反应刚部署完最容易遇到的现象是zabbix-server容器每隔几秒重启一次日志显示failed to connect to database。多数原因是 server 启动时数据库还没 ready或者 compose 里的depends_on条件写得太简单。我现在的写法是让 server 依赖数据库的 healthcheck 结果只有pg_isready返回成功才开始拉 server。如果已经把 compose 文件改成这样还重启那就手工进数据库容器验证docker exec -it zabbix-db psql -U zabbix -d zabbix -c select 1能返回1说明数据库本身没问题问题大概率在密码或者 host 配置。环境变量里的POSTGRES_PASSWORD必须和数据库初始化时保持一致改密码后要同步改 compose 里的所有引用位置。4.2 Agent 显示不可达的问题监控宿主机时如果 Agent2 容器已经跑了但 Web 界面上主机状态一直是红色先别急着怀疑网络。Zabbix 的主机名匹配机制是常见原因Agent 上报的Hostname要和主机配置里的名字一致不一致时 server 会把数据当未知来源丢掉。我在 Web 上配置主机时主机名写的是“Docker Host”Agent2 容器的ZBX_HOSTNAME也必须是“Docker Host”。同时要把主机类型改成主动或被动对应模式默认的 Agent 模式是主动检查如果 Agent 配成被动检查但对端端口不通界面一样显示不可达。4.3 容器重启后数据全丢这个问题多半是没挂 volume。数据库容器如果没挂zabbix-db-datadocker compose down之后容器删除数据跟着就没了。验证方法很简单docker volume ls | grep zabbix能查到对应 volume 才说明持久化正常。备份时直接用pg_dump导出数据库内容不需要整个 volume 快照但如果是迁移服务器还是建议用 volume 快照加pg_dump双保险。4.4 时区错乱引发的告警误差PHP 默认时区是 UTC国内服务器如果不显式设置PHP_TZ页面上的时间会比北京时间慢 8 小时。这个问题的隐蔽之处在于Zabbix Server 内部的告警判断是基于 UTC 的Web 端展示时间会通过 PHP 时区转换所以最后看到的就是“告警时间对不上”。排查技巧先在数据库里查now()和current_timestamp确认数据库时区正常再看 Web 容器环境变量是否有PHP_TZ。修改环境变量后不需要重建容器只需要docker compose up -d重新创建 Web 容器即可。5. 上线后的配置、备份与加固5.1 基础监控模板与告警通道Zabbix 7.4 自带了很多官方模板比如 Linux 主机模板、Windows 主机模板、SNMP 设备模板。建议先把宿主机通过 Agent2 接入跑一遍自带模板确认监控项数据正常后再扩展其他设备。告警通道方面先配置一个最简单的邮件告警确认触发链路通再去搞 Webhook 或钉钉机器人。在配置告警媒介时千万不要只在 Media type 里填写服务器地址还要在 Users 里给用户添加“告警媒介”。我见过很多新手卡在这一步告警动作配置了媒介也配置了但用户没有绑定媒介结果一条告警都收不到。5.2 数据库的备份策略Docker 部署环境的备份比物理机简单。我推荐每天凌晨用 cron 执行一次pg_dump到宿主机备份目录保留最近 7 天docker exec zabbix-db pg_dump -U zabbix zabbix | gzip /backup/zabbix_$(date \%F).sql.gz find /backup -name zabbix_*.sql.gz -mtime 7 -delete执行前确保宿主机libpq客户端可用或者直接在容器内执行并挂载备份目录。恢复时先用gunzip解压再通过psql导入到新数据库注意导入顺序要保证目标库是空的否则会有主键冲突。5.3 安全加固的几个动作默认密码Admin/zabbix上线后必须第一时间改掉。其次是把 Guest 用户禁用这个用户默认存在但基本用不上留着只会增加暴露面。Web 容器如果只在内网访问建议端口映射时绑定内网 IPports: - 127.0.0.1:8080:8080需要从公网访问时前面加一层带有 HTTPS 证书的反向代理不要直接暴露 Zabbix Web 的 8080 端口。数据库 5432 端口不需要映射到宿主机compose 里只放在自定义网络内即可外部连不上反而安全。最后再分享一个小技巧Zabbix Server 容器日志默认是标准输出长时间运行会积累不少数据建议在运行 Docker 的宿主机上配置 log rotation。/etc/docker/daemon.json里加上log-driver和max-size配置避免/var/lib/docker/containers目录被日志撑爆。这个坑是我在监控平台跑了三个月之后才遇到的提前配置好能省掉不少清理工作。