ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Docker 部署 Zabbix 监控系统:compose 编排、分离部署与 API 验证

Docker 部署 Zabbix 监控系统:compose 编排、分离部署与 API 验证 简介这份资源面向需要在 Linux 服务器上快速搭建监控平台的运维人员与开发者提供用 Docker 部署 Zabbix 的完整代码包解决传统安装依赖繁琐、环境配置易出错的问题。压缩包共 5 个文件约 11KB以 docker-compose.yml 为核心编排文件配合 README.md 说明文档、index.html 页面、.gitignore 与 .inscode 配置覆盖容器定义、环境变量与端口映射等关键内容结构精简、开箱即用。资源围绕两种部署思路展开一是通过 Compose 文件一键启动 Zabbix 服务、MySQL 数据库与前端二是借助宝塔面板已有数据库创建 Zabbix 容器适合不同服务器管理习惯的用户。读者可据此快速复现监控环境掌握 Zabbix 对服务器、网络设备与网络服务的实时监控和报警配置并理解容器化部署的排错思路。目前已有 45 人学习适合具备基础 Docker 与 Linux 知识、希望提升运维效率的技术人员参考。1. Docker 装 Zabbix为什么老手都劝你别把 MySQL 塞进同一个 compose如果你在 CentOS 7.9 或 Ubuntu 上敲过docker run装 Zabbix大概率经历过这种场面Web 页面能打开但登录后一直提示「Zabbix server is not running」翻日志发现数据库连不上或者net.tcp.port那行配置怎么改都不生效。Docker 安装 Zabbix 这件事坑不在 Zabbix 本身而在容器之间的网络、时区、数据库初始化和版本匹配这四件事上。这篇笔记面向的是想用 Docker 快速拉起一套可用 Zabbix 监控的运维和开发从镜像选型、compose 编排、数据库初始化一路写到 Web 与 Zabbix 分离部署和排错。我不会只给你一份能跑的 yaml而是把每个参数为什么这么设、改错了会怎样讲清楚让你在 Ubuntu 或 CentOS 7.9 上都能复现也能在翻车时知道去哪找后悔药。2. 镜像选型与 compose 编排先把 Zabbix 全家桶拆开看2.1 官方镜像的四种角色别指望一个容器全包Zabbix 从 5.0 之后官方在 Docker Hub 上维护了四个独立镜像zabbix-server-mysql、zabbix-web-nginx-mysql、zabbix-agent、zabbix-java-gateway。很多人第一次装的时候想找一个「all-in-one」镜像结果找到的都是第三方打包的版本停在 4.x遇到新版前端直接白屏。常见做法是老老实实按角色拆容器用 docker compose 把它们编在一个网络里。拆开的好处很直接数据库可以单独换成外部 MySQL 8.0Web 可以横向扩Zabbix server 挂了不影响前端展示历史数据。代价是你要多写几行 compose并且理解容器间怎么互相找到对方。这里的关键是服务名即主机名——compose 默认会创建一个 bridge 网络容器之间可以直接用 service 名通信所以 Zabbix server 连数据库写DB_SERVER_HOSTmysql就行不需要写 IP。镜像 tag 的选择上我一般锁具体版本而不是latest。比如zabbix/zabbix-server-mysql:ubuntu-6.4-latest这种带基础系统和主版本的 tag比裸latest可控得多。原因是 Zabbix 大版本之间数据库 schema 不兼容6.0 的库直接给 6.4 的 server 用会报 schema 版本错误回滚又得清库。锁版本能让你在升级前有明确的对照。2.2 一份能跑通的 docker-compose.yml 与逐行参数说明下面这份 compose 是我在 Ubuntu 22.04 和 CentOS 7.9 上都验证过的骨架MySQL 用 8.0Zabbix 用 6.4。注意 MySQL 8.0 的认证插件和字符集是两个高频翻车点我在参数里都做了处理。version: 3.8 services: mysql: image: mysql:8.0 container_name: zabbix-mysql restart: unless-stopped command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_bin - --default-authentication-pluginmysql_native_password environment: MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pwd MYSQL_ROOT_PASSWORD: root_pwd TZ: Asia/Shanghai volumes: - ./mysql-data:/var/lib/mysql networks: - zbx-net zabbix-server: image: zabbix/zabbix-server-mysql:ubuntu-6.4-latest container_name: zabbix-server restart: unless-stopped environment: DB_SERVER_HOST: mysql MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pwd TZ: Asia/Shanghai ports: - 10051:10051 depends_on: - mysql networks: - zbx-net zabbix-web: image: zabbix/zabbix-web-nginx-mysql:ubuntu-6.4-latest container_name: zabbix-web restart: unless-stopped environment: ZBX_SERVER_HOST: zabbix-server DB_SERVER_HOST: mysql MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pwd PHP_TZ: Asia/Shanghai TZ: Asia/Shanghai ports: - 8080:8080 depends_on: - mysql - zabbix-server networks: - zbx-net networks: zbx-net: driver: bridge逐行说几个不能乱改的地方。--default-authentication-pluginmysql_native_password这行是给 MySQL 8.0 用的因为 Zabbix server 的数据库驱动对caching_sha2_password支持在部分版本上不完整不改会出现「Access denied」但密码明明是对的玄学现象。utf8mb4_bin排序规则是 Zabbix 官方要求的用默认的utf8mb4_0900_ai_ci建表时可能报索引长度超限。ZBX_SERVER_HOST在 web 容器里指向zabbix-server服务名这是前端去连 server 的 10051 端口用的。PHP_TZ和TZ要一起设只设一个会出现页面时间比实际差 8 小时的情况。端口映射上server 的 10051 是给 agent 主动上报用的web 的 8080 是你浏览器访问的两个别搞混。2.3 启动顺序与数据库初始化的正确姿势compose 的depends_on只保证容器启动顺序不保证 MySQL 已经 ready。Zabbix server 启动时如果连不上库会直接退出restart: unless-stopped会让它反复重启直到 MySQL 初始化完成。所以第一次docker compose up -d之后别急着看 web先确认 MySQL 真的起来了。# 看 mysql 是否完成初始化出现 ready for connections 才算好 docker logs -f zabbix-mysql # 确认 zabbix server 有没有连上库 docker logs zabbix-server | grep -i database # 检查三个容器状态 docker compose ps数据库表结构是 Zabbix server 首次启动时自动创建的不需要你手动导入 SQL。如果你看到 server 日志里出现cannot connect to database然后退出八成是 MySQL 还没 ready 或者密码不对。等 MySQL 日志出现ready for connections后docker compose restart zabbix-server一次即可。这一步的坑在于有人手动去 MySQL 里建了 zabbix 库但没给 zabbix 用户授权server 建表时权限不足日志里报的是Access denied for user看着像密码问题其实是权限问题。3. Web 与 Zabbix 分离部署跨主机时 net.tcp.port 到底填什么3.1 分离部署的两种场景与网络前提Web 与 Zabbix 分离通常出现在两种场景一是 Web 要放到有公网入口的机器上server 留在内网二是监控规模大了前端查询压力想单独扛。分离之后Web 容器里的ZBX_SERVER_HOST就不能再写服务名了得写 server 所在主机的可达 IP 或域名。这里第一个要确认的是网络连通性。Web 容器要能访问 server 的 10051 端口server 要能访问数据库的 3306。常见做法是给 server 主机开固定内网 IPWeb 容器通过--add-host或者 compose 的extra_hosts把域名指过去。如果你在 Web 容器里ping不通 server 主机先查宿主机防火墙CentOS 7.9 默认的 firewalld 会拦 10051。zabbix-web: image: zabbix/zabbix-web-nginx-mysql:ubuntu-6.4-latest environment: ZBX_SERVER_HOST: 192.168.1.50 ZBX_SERVER_PORT: 10051 DB_SERVER_HOST: 192.168.1.51 MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix_pwd PHP_TZ: Asia/Shanghai extra_hosts: - zbx-server:192.168.1.50ZBX_SERVER_PORT默认就是 10051写不写都行但分离场景下我建议显式写出来方便排查时一眼看到连的是哪个端口。extra_hosts是给容器内加 hosts 解析用的如果你习惯用域名而不是 IP这行能省掉改配置的麻烦。3.2 net.tcp.port 配置项的真实作用与改法热词里出现的zabbix net.tcp.port指的是 Zabbix agent 配置里的ServerActive和Server参数以及 server 端zabbix_server.conf里的ListenPort。很多人搜这个词是因为 agent 主动模式上报不通。默认 agent 主动模式会连 server 的 10051如果你改了 server 的监听端口agent 这边必须同步改。在 Docker 场景下server 容器的 10051 映射到宿主机某个端口后agent 配置里要写宿主机的 IP 和映射后的端口。比如你把 server 的 10051 映射成了宿主机的 15051那 agent 的ServerActive宿主机IP:15051。这里有个容易忽略的点agent 主动模式连的是ServerActive被动模式等的是Server来连它的 10050两个方向别搞反。# 在 agent 容器里测试到 server 的连通性 docker exec -it zabbix-agent bash # 用 nc 测端口没有的话先装 nc -zv 192.168.1.50 10051如果nc不通先别改 Zabbix 配置去查网络和防火墙。Zabbix 的配置错误日志通常很直白agent 日志里会写no active checks on server看到这个就是ServerActive没配对或者网络不通。3.3 用 Postman 调 Zabbix API 验证分离后的数据链路分离部署后验证 Web 到 server 再到数据库这条链路是否通最直接的办法是调一次 API。Zabbix 的 API 入口在 Web 的/api_jsonrpc.php用 Postman 发一个user.login就能确认前端和数据库都正常。{ jsonrpc: 2.0, method: user.login, params: { username: Admin, password: zabbix }, id: 1 }请求地址填http://Web主机:8080/api_jsonrpc.php方法 POSTHeader 里Content-Type: application/json-rpc。返回里拿到result字段的 token说明 Web 到数据库这条链路是通的。如果返回Unable to connect to Zabbix server问题在 Web 到 server 的 10051如果返回数据库相关错误问题在 server 到 MySQL。用 API 分层定位比盯着页面报错猜要快得多。拿到 token 后还能顺手调host.get拉主机列表确认监控数据确实在写库。4. 避坑与排查Docker 装 Zabbix 最常见的五个翻车现场4.1 现象Web 页面提示 Zabbix server is not running原因通常有三个server 容器根本没起来、server 连不上数据库、Web 容器里的ZBX_SERVER_HOST写错。先docker compose ps看 server 是不是Up如果是Restarting就去docker logs zabbix-server看退出原因。日志里出现database is not ready就等 MySQL出现Access denied就查密码和授权。解决顺序是先保 MySQL ready再重启 server最后确认 Web 的ZBX_SERVER_HOST指向的是 server 的服务名或 IP不是数据库。4.2 现象MySQL 8.0 容器启动后 Zabbix server 反复重启原因是 MySQL 8.0 默认认证插件是caching_sha2_password部分 Zabbix server 镜像里的驱动不认。解决是在 MySQL 的 command 里加--default-authentication-pluginmysql_native_password然后删掉./mysql-data重新初始化。注意这个参数在 MySQL 8.4 之后被移除了如果你用的是 8.4得改用--mysql-native-passwordON版本不同参数名不一样别照抄。4.3 现象页面时间比实际时间差 8 小时原因是容器时区没设或者只设了TZ没设PHP_TZ。Zabbix Web 是 PHP 写的PHP 有自己的时区配置光设系统TZ不够。解决是在 web 容器的 environment 里同时写TZ: Asia/Shanghai和PHP_TZ: Asia/Shanghai然后重启 web 容器。server 容器也要设TZ否则采集到的时间戳本身就是偏的。4.4 现象agent 主动模式数据不上报日志报 no active checks原因是ServerActive没配或者配的端口不对。Docker 场景下如果 server 的 10051 做了端口映射agent 里要写映射后的宿主机端口。解决是进 agent 容器nc -zv serverIP 端口先测通再改ServerActive。另外 agent 的 hostname 必须和 Web 里添加主机时填的主机名完全一致大小写敏感不一致会报host not found。4.5 现象docker compose up 报 permission denied while trying to connect to the Docker API原因是当前用户不在 docker 组里或者用了 sudo 但环境变量没带过去。解决是把用户加进 docker 组sudo usermod -aG docker $USER然后重新登录。CentOS 7.9 上如果 docker 服务本身启动失败先systemctl status docker看是不是failed to start docker application container engine常见原因是/etc/docker/daemon.json写错了 JSON 格式或者存储驱动和内核不匹配。5. 进阶用 API 批量拉取 CPU 内存磁盘指标并做告警静默装好只是开始真正让 Zabbix 有价值的是把 CPU、内存、磁盘这些指标用起来。我习惯在部署完成后立刻用 API 验证数据采集是否正常而不是等告警响了才发现某个 item 没数据。下面这段 Python 用host.get和item.get拉指定主机的 CPU 和内存 item再取最近的值。import requests import json URL http://Web主机:8080/api_jsonrpc.php HEADERS {Content-Type: application/json-rpc} def call(method, params, authNone): payload { jsonrpc: 2.0, method: method, params: params, id: 1 } if auth: payload[auth] auth r requests.post(URL, headersHEADERS, datajson.dumps(payload)) return r.json() # 登录拿 token token call(user.login, {username: Admin, password: zabbix})[result] # 拉主机列表按名字过滤 hosts call(host.get, { output: [hostid, host], search: {host: web} }, token)[result] for h in hosts: # 拉该主机的 CPU 和内存 item items call(item.get, { output: [name, key_, lastvalue, lastclock], hostids: h[hostid], search: {name: CPU}, sortfield: name }, token)[result] for it in items: print(h[host], it[name], it[lastvalue])这段代码的关键在item.get的search参数它按 item 名称模糊匹配所以搜「CPU」能同时命中「CPU utilization」和「CPU load」。lastvalue是最近一次采集的值如果为空说明采集没跑起来得回去查 agent 和模板。lastclock是时间戳和当前时间差太多说明数据是旧的。告警手动消除这件事很多人找不到入口。Zabbix 的告警分「问题」和「事件」在「监测 → 问题」里选中问题点「确认」只是标记已读问题本身还在。要真正消除得等触发条件恢复或者去「配置 → 主机 → 触发器」里临时禁用对应触发器。我一般用 API 的event.acknowledge做批量确认用trigger.update把status改成 1 来临时禁用恢复后再改回 0。这个操作要谨慎禁用触发器等于关掉了这条告警线做完记得记一笔。最后说个我自己的习惯每次部署完 Zabbix我都会先跑一遍 API 把关键 item 的lastvalue拉出来看一遍确认 CPU、内存、磁盘、网络四类数据都有值再去看页面。页面好看不代表数据在采API 拉出来的值才是黑匣子里真实的东西。这套流程帮我在好几次「页面正常但实际没数据」的翻车里提前发现了问题。希望帮到你。本文还有配套的精品资源点击获取
返回列表