前阵子打算在自己的环境里上 Zabbix 时,我最开始纠结的其实不是“会不会装”,而是:
监控中心到底应该放在哪里,应该怎么放,才能既顺手又不容易把自己坑到。
我的环境不算大,但也已经不是“纯空白新机”那种状态了:
- 一台 PVE 宿主机,
i7-8700 / 64G RAM - PVE 上已经跑着其他业务和实验环境
- 宿主机本身也已经承担了一些 Docker 服务
- 另外还有几台需要一起纳管的机器
所以问题的重点并不是 Zabbix 能不能跑,而是:
- 要不要直接装在 PVE 宿主机上
- 还是单独开一台 VM
- 如果单独开 VM,Server 是原生装,还是用 Docker 编排
- 宿主机本身又该怎么被监控
最后我的选择是:
- Zabbix Server 放在一台独立 VM 里
- Server / Web / DB 用 Docker 部署
- PVE 宿主机本体安装
zabbix-agent2
这篇文章就记录一下这套选择背后的考虑,以及这套架构后来真实踩到的一个坑:
Linux: Zabbix agent is not available (for 3m)为什么我没有把 Zabbix Server 直接装在 PVE 宿主机上
从“能不能运行”这个角度说,把 Zabbix Server 直接装在 PVE 宿主机上当然是可行的。PVE 本质上就是 Debian 系统,技术上没有障碍。
但我最后还是没有这么做,原因主要有三点。
1. 宿主机应该尽量少承担额外耦合
PVE 宿主机最核心的职责是:
- 跑虚拟化平台
- 托管 VM / LXC
- 维护网络、存储、宿主层稳定性
一旦把 Zabbix Server 直接塞进宿主机,就会额外把这些东西也绑上去:
- Web 前端
- PHP / Nginx
- 数据库
- Server 自身守护进程
- 历史数据写盘和维护
这样做不是不能用,而是会让宿主机的角色变得更混杂。
对于个人实验环境来说,偶尔混一点业务也不是世界末日;但如果目标是长期把监控系统保留下来,那么“少耦合一点”通常会更舒服。
2. Zabbix 真正重的部分,不在界面,而在数据库和持续写入
很多人一开始会把 Zabbix 想成“一个带网页的监控工具”,但真正会慢慢变重的部分,其实是:
- 历史数据
- 趋势数据
- 事件记录
- 数据库持续写入
- 长期保留带来的磁盘与 I/O 压力
哪怕我现在监控规模不大,这些东西的增长趋势也是确定的。
如果一开始就把它和宿主机绑死,后面一旦要:
- 调整保留策略
- 迁移数据库
- 升级版本
- 做回滚或快照
都会比单独放在 VM 里更麻烦。
3. 监控中心和被监控核心宿主最好不要完全同生共死
这点是我最后最看重的。
我当然要监控 PVE 宿主机本身,但如果 Zabbix Server 也直接跑在宿主机上,那么一旦宿主机出现:
- 网络异常
- 磁盘爆满
- Docker 抢资源
- 升级失败
- 某些宿主层服务问题
监控中心本身也可能跟着一起受影响。
这样一来,“我在监控谁”和“谁在负责监控”就重叠得太厉害了。
从架构上看,把 Zabbix Server 放进独立 VM,至少隔离性会更好一点:
- 可以单独快照
- 可以单独备份
- 可以单独迁移
- 可以单独回滚
- 不会因为宿主机上某个额外服务折腾而直接把监控中心一起带崩
那为什么我最后又选了 Docker,而不是在 VM 里原生装
确定“单独 VM”这件事之后,第二个问题就是:
这台 VM 里是原生装 Zabbix,还是继续用 Docker。
我最后选了 Docker,理由其实很现实。
1. 组件天然适合拆分
Zabbix 这一套本来就不是一个单进程小工具,而是至少包含:
zabbix-server- Web 前端
- 数据库
- 可能还有 Java Gateway 等组件
这种结构用 Docker 编排起来,本身就比较顺手:
- 每个组件边界清楚
- 配置文件和环境变量更集中
- 容器重建成本低
- 升级路径也更清晰
对我这种本来就已经习惯 Docker 工作流的人来说,这种部署方式明显更自然。
2. 更符合我自己的维护习惯
比起“尽量原生装所有东西”,我平时其实更习惯:
- 服务组件容器化
- 配置收敛到 compose / 环境变量
- 出问题优先看容器状态、日志、网络
这种习惯不是绝对更正确,但它和我的日常工作流更一致。
如果一个工具最终是要长期留在环境里的,那我会更偏向:
用我自己最容易维护、最容易理解、最容易回溯的方式去部署它。
3. 方便把监控中心作为一个独立可迁移单元保留下来
把 Zabbix Server 放进一台独立 VM,再在 VM 里用 Docker 跑组件,最后得到的效果就是:
- VM 是隔离边界
- Docker 是服务编排边界
这样后续无论是:
- 做备份
- 做迁移
- 调整资源
- 把这套监控中心搬到别的宿主
操作上都会比较清楚。
那为什么 agent2 不一起塞进容器,而是留在宿主机本体
如果说前面是在解决“监控中心怎么放”,那这里解决的就是:
宿主机本身应该怎么被监控。
我最后没有把 agent 也一起塞进容器,而是直接在宿主机本体安装了 zabbix-agent2。
这个选择的理由也很明确。
1. 我想看的是宿主机本体,不是某个容器视角里的宿主机投影
如果监控的是 PVE 宿主机,那我更希望采到的是:
- 宿主机自己的 CPU / Load
- 宿主机自己的内存和磁盘状态
- 宿主机自己的网络与系统资源
- 宿主机上的真实进程和服务可达性
而不是经过容器隔一层之后的某种不完整视角。
对于“被监控对象就是宿主机本体”这种场景,把 agent 放在宿主机上会更直接,也更自然。
2. agent2 本身足够轻,没必要为了形式统一强行容器化
zabbix-agent2 本身不是什么特别重的组件,跑在宿主机上对资源压力很小。
既然它的职责就是:
- 采集本地数据
- 响应检查请求
- 或主动回传数据
那直接贴着宿主机跑,反而更贴合它的角色。
3. 这样更容易把“监控中心”和“被监控对象”分开
最终这套结构就变成了:
- 独立 VM:作为监控中心
- Docker:承载 Zabbix Server / Web / DB
- 宿主机 agent2:负责把宿主机本体暴露给 Zabbix 监控
这套结构在逻辑上很清晰:
- 监控中心是一层
- 被监控宿主机是另一层
- 两者通过 agent 通信
从架构上看,这比“所有东西全堆在宿主机里”要更像一个可以长期维护的方案。
但这套方案后来踩了一个很典型的坑
这也是我后来真正觉得值得写出来的部分。
部署完成后,前端、登录、仪表盘都正常,结果问题页里却一直躺着一条 一般严重 告警:
Linux: Zabbix agent is not available (for 3m)出问题的主机正是:
Zabbix server
也就是我那台跑监控中心的 VM 对应的监控对象。
一开始这种告警很容易让人往错误方向想,比如:
- 是不是前端坏了
- 是不是 Zabbix server 本身有问题
- 是不是 agent2 没启动
- 是不是数据库连接炸了
但实际查下来,都不是。
先确认 agent2 自己没死
在宿主机上检查:
systemctl status zabbix-agent2ss -lntp | grep 10050结果都正常:
zabbix-agent2处于active (running)10050端口正在监听
这说明至少从宿主机本地视角看,agent2 是活着的。
真正的问题在访问来源控制
继续看 zabbix_agent2.conf:
Server=127.0.0.1ServerActive=127.0.0.1:10051Hostname=Zabbix server这里的问题一下就出来了。
Server= 的含义不是“agent 要去连谁”,而是:
哪些 Zabbix server / proxy 被允许来请求这个 agent。
而当时我的 zabbix-server 并不在宿主机本体上,它跑在 Docker 里。
继续查容器 IP:
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}} {{end}}' zabbix-server结果是:
172.18.0.4于是问题就完全坐实了:
zabbix-agent2只允许127.0.0.1zabbix-server实际来源是172.18.0.4- 所以 server 发起的被动检查会被 agent2 拒绝
- 最终触发:
Linux: Zabbix agent is not available (for 3m)这其实就是这类“容器里的 server + 宿主机上的 agent”架构最常见的坑之一:
从宿主机本地看,agent2 没问题;但真正访问它的不是 localhost,而是 Docker 网络里的容器。
最终修复方式
最直接的修法是先把当前容器 IP 放进 Server=:
Server=127.0.0.1,172.18.0.4然后重启 agent2:
systemctl restart zabbix-agent2这样可以立刻恢复。
但这种写法不够稳,因为 Docker 容器 IP 以后可能会变。
所以最后我改成了更合理的网段方式:
Server=127.0.0.1,172.18.0.0/16ServerActive=127.0.0.1:10051Hostname=Zabbix server这样做的好处是:
- 当前容器来源被放行
- 以后容器重建、IP 变化,只要还在这个 Docker 网段里,就不需要再改一次
这次经历真正让我确认了什么
回过头看,这次部署和排障让我更确认了一件事:
把 Zabbix Server 放进独立 VM,再用 Docker 跑组件,本身是一个合理选择;但一旦监控对象跨越了“容器”和“宿主机”两个层次,就一定要认真处理好两者的网络关系。
换句话说,这套架构的问题不在于“选错了”,而在于:
- 架构是对的
- 但细节必须跟上
尤其是 agent 侧的:
Server=ServerActive=- Hostname
- 容器来源 IP / 网段
这些配置如果还按“全部都在同一台裸机上”的思路去写,就很容易踩坑。
最后的结论
如果现在让我重新总结这次部署选择,我会这么说:
为什么我没把 Zabbix Server 直接放在 PVE 宿主机上
因为我更看重:
- 宿主机少耦合
- 监控中心可隔离
- 数据库和写盘负担不要直接压在宿主层
- 后续升级、备份、迁移、回滚都更清楚
为什么我最后选择“独立 VM + Docker”
因为这符合我的维护习惯,也适合 Zabbix 本身的组件结构:
- VM 提供隔离边界
- Docker 提供服务编排边界
- 整套监控中心更容易保留和迁移
为什么 agent2 仍然留在宿主机上
因为我要监控的是宿主机本体,而不是某个容器视角下的宿主机投影。
这套方案真正需要注意什么
只要 server 在容器里、agent 在宿主机上,就必须记住:
宿主机本地的
127.0.0.1,并不等于 Docker 里的 server 容器。
如果不把容器来源放进 agent 的允许列表里, 前端看上去一切正常,问题页里照样会给你躺一条:
Linux: Zabbix agent is not available (for 3m)这类问题表面上像“agent 挂了”,实际上很多时候只是:
容器网络视角和宿主机本地视角,不是同一个世界。