Zabbix 7.0 从装到告警触发,我踩了这些坑

11 阅读10分钟

Zabbix 7.0 从装到告警触发,我踩了这些坑

前言

最近在搭一套自己的监控环境:VMware 里两台 Ubuntu Server 24.04 分别做 Zabbix 服务端和被监控端,外加一台 Windows Server 2022 域控,Zabbix 版本 7.0.30。从装服务端到三台主机全部接入、告警真实触发,前后花了两天,中间踩了不少坑。

这篇不是教程,是踩坑实录。每个坑都有当时的真实报错和排查过程,写出来一是给自己留档,二是给后来人排雷——尤其是网上教程和实际版本对不上的那些地方。

一、安装期:三个新手必踩的坑

坑 1:sed 替换 Zabbix 源,三行 URIs 纹丝不动

装 Zabbix 的第一步是换源。国内访问官方仓库慢,惯例是换成阿里云镜像,一行 sed 的事。

我改完顺手 grep 了一眼,三行 URIs 纹丝没动。

这就有点诡异了。命令没报错,退出码是 0,sed 甚至没抱怨一句"没找到匹配"。盯着命令看了半天才发现问题:官方源早就全站 https 了,而网上大部分教程还在写 s/http/https/ 这种老掉牙的替换规则。目标串是 http://repo.zabbix.com,文件里实际是 https://repo.zabbix.com——一个字符的差别,sed 找不到匹配,什么都不做,也不告诉你它什么都没做。

后来这个坑我又踩了两次。一次是换 Ubuntu 源时漏了 /ubuntu/ 路径,一次是改 Redis 配置时把 requirepass 打成了 requires。三次剧本完全一样:sed 静默失败,不 grep 回看根本不知道配置没改。最险的是 Redis 那次——要是没回看就重启服务,Redis 会因为不认识 requires 这条指令直接起不来。

现在每次改配置我都会先备份、改完再 grep 一遍。这个习惯救过我不止一次,后面还会提到。

坑 2:MySQL ERROR 1045——-p 和密码之间的那个空格

装完 MySQL 建 Zabbix 库、导完 schema,到验证账号这步:

mysql -uzabbix -p'Zabbix@2026' -e "USE zabbix; SHOW TABLES;"
ERROR 1045 (28000): Access denied for user 'zabbix'@'localhost' (using password: YES)

密码明明是对的。反复试了几次都是 1045,一度怀疑是建用户那步出了问题。

排查到最后发现是个特别蠢的原因:-p 和密码之间多了一个空格。MySQL 的参数规则里,-p 后面紧贴的才是密码;写成 -p 'Zabbix@2026'-p 就成了无值参数,后面那串被当成了数据库名——等于拿密码当库名去连,自然 Access denied。

同一天还撞上第二个账号坑:sudo mysql -e "..." 没写 -u root,MySQL 客户端自己猜了个用户名去连,又是一个 1045。报错里的用户名是 'zabbix'@'localhost', clues 就在报错里,只是当时没看懂。

从这以后我固定了两个写法:密码一律 -p'密码' 紧贴;带 -e 的命令一律显式 -u root,不让客户端猜。

坑 3:浏览器拒绝连接——配置写的 8080,进程听的是 80

装完打开 http://192.168.207.30:8080,Chrome 直接甩了一句:

ERR_CONNECTION_REFUSED

第一反应是 nginx 配置没挂上,翻配置:

sudo nginx -T | grep -i listen
    # listen 8080;

明明有 8080。再用 ss 看:

sudo ss -tlnp | grep nginx
    LISTEN 0  128  0.0.0.0:80  ...  nginx

进程实际听的是 80。回头仔细看 nginx -T 的输出才反应过来:那行 listen 8080; 前面带了个 #,是被注释掉的默认值——nginx -T 会把注释原样打印出来,grep 的时候很容易把注释行当成生效配置。

改成访问 http://192.168.207.30,Web 向导一次通过。

这个坑教给我的是:配置文件说的不算,进程实际干的才算。两个视角矛盾时,信 ss,不信注释。

二、接入期:主机加不上、状态红

坑 4:Templates 弹窗搜不到 Linux

创建主机时挂模板,在弹窗里搜 "Linux",结果列表是空的。

第一反应是装出问题了,模板没导进数据库。但先用 SQL 验证了一下:

mysql -uzabbix -p'...' -e "SELECT COUNT(*) FROM zabbix.hosts WHERE status=3;"
+----------+
| COUNT(*) |
+----------+
|      356 |
+----------+

356 个模板好好的躺在库里,那问题就不是安装,是弹窗的用法——Zabbix 7.0 的选择弹窗默认不加载任何内容,得先设置筛选条件(选模板组、或者填名字回车)才会出列表。

点 Select 之后先出来的是模板组列表,一路进到 Templates/Operating systems 组,总算看到 Linux 系列了。然后手一快,把组里能勾的模板全勾上了——AIX、FreeBSD、HP-UX、macOS、Solaris、Windows,一整个操作系统博览会。保存前发现不对劲,又一个个删掉,只留下 Linux by Zabbix agent 这一个。

当时也确认过一条后路:模板不是必填项,真卡住就先保存主机、之后再进详情页的 Templates 标签页补挂,效果一样。别让一个弹窗卡住整体进度。

这里有个方法论层面的收获:遇到"找不到 X",先证明 X 在不在,再研究怎么点。一条 SQL 就把"要不要重装"这种大问题直接掐死在摇篮里。

坑 5:agent 状态红,nc 报 timed out

被监控端 sv01 接入后 Availability 一直是红色,错误信息里带着 connection timed out——不是"拒绝连接",是"超时"。

先在 sv01 上确认服务本身没问题:

sudo ss -tlnp | grep 10050
LISTEN 0  4096  *:10050  *:*  users:(("zabbix_agent2",pid=2314,fd=7))

agent 好好的监听所有网卡。ping 也通,网络可达。那问题就在中间的拦截上。上 sv01 一看防火墙:

sudo ufw status
Status: active
OpenSSH    ALLOW    Anywhere
80/tcp     ALLOW    Anywhere

UFW 只放行了 22 和 80,10050 被默认策略 DROP 了。

sudo ufw allow 10050/tcp

放行后从服务端复测:

nc -zv 192.168.207.128 10050 -w 5
Connection to 192.168.207.128 10050 port [tcp/zabbix-agent] succeeded!

Web 上 Availability 几分钟后变绿。

这个坑最大的价值是把两个容易混的报错彻底区分开了:

  • Connection refused:主机可达、端口上没服务监听,对方明确回绝——"有人应门说不在"
  • timed out:包石沉大海,被防火墙 DROP 或路由不通——"敲门没人理"

另外 ping 通不代表端口通:UFW 默认不拦 ICMP。排查网络问题时,"ping 通"只能证明主机活着,不能证明服务可达。

三、告警期:告警就是不响

坑 6:Action log 里躺着一行 FAILED

agent 故障实际发生过一次(服务停了),Problems 面板也红了,但通知就是没收到。脚本日志里只有手动测试的那一行。

这次没盯着脚本日志死磕,转头去看 Dashboard 右下角的 Action log,真相直接摆在那:

2026-09-05 10:42:45 PM  Admin  local-script  FAILED
No message defined for media type

Zabbix 尝试发送了,失败原因也写得明明白白:Action 的 Operation 里有个 Custom message 复选框,默认不勾。不勾就等于没定义消息模板——Zabbix 知道要发通知,但不知道发什么内容,直接放弃。

勾上,把 Subject 和 Message 用宏填好({HOST.NAME}{EVENT.SEVERITY}{EVENT.NAME} 这些),保存。

坑 7:通知发出去了,脚本收到的参数是空的

再触发一次,Action log 显示 Sent,脚本日志也多了一行:

2026-09-05 23:20:45 |  |  |

时间戳是新的,说明脚本确实被调用了。但 11 2 $3 全是空。

又查了一轮才知道:Zabbix 的 Script 媒介,参数不是自动传的,必须在 Media type 的 Script parameters 里显式声明:

{ALERT.SENDTO}
{ALERT.SUBJECT}
{ALERT.MESSAGE}

这三个宏分别对应脚本的 1(收件人)、1(收件人)、2(标题)、$3(正文)。加上之后再触发,日志终于变成了:

2026-09-05 23:33:45 | ARGS[3]: local Problem: Average on sv01 - Linux: Zabbix agent is not available (for 3m)
Host: sv01
Severity: Average
Status: PROBLEM
...

这个坑让我沉淀出一套排查顺序,比结论本身更值钱:

  1. 看 Action log——Zabbix 到底有没有尝试发送(区分"没发"和"发了但失败")
  2. 看 Status 列的红字——失败原因写在那
  3. 看脚本日志——脚本有没有被真正执行

一开始只盯着脚本日志,是本末倒置:脚本日志只能证明"脚本被调了",证明不了"Zabbix 尝试调了"。排查"该发生但没发生"的问题,先找离源头最近的观测点。

四、Windows 接入:msi 装到了宿主机

接入 Windows Server 域控(DC01)时先遇到下载问题:Windows 版 agent 的 msi 在阿里云镜像上没有(国内镜像大多只同步 Linux 包),清华镜像一律 403,最后从官方 CDN 拿到了 zabbix_agent2-7.0.30-windows-amd64-openssl.msi

下载完双击安装,向导里填好 Host name 和 Server IP,装完验证:

Get-Service "Zabbix Agent 2"     → Running
netstat -ano | findstr :100500.0.0.0:10050 LISTENING
ping 192.168.207.30              → 通

每一步都"通过"。但 Zabbix Server 那边连 192.168.207.10:10050,永远 timed out。

对着 Test-NetConnection 的输出看了半天,注意到两个不对劲的细节:

InterfaceAlias   : VMware Network Adapter VMnet8
SourceAddress    : 192.168.207.1

DC01 虚拟机里的网卡叫 Ethernet0,IP 是 192.168.207.10。而 VMnet8 和 192.168.207.1 是宿主机上的 VMware 虚拟网卡——这两条命令是在宿主机的 PowerShell 里跑的,不是在虚拟机里。

再一验证:宿主机的 127.0.0.1:10050 也是通的。真相只有一个——msi 在宿主机上双击的,agent 装到了宿主机,DC01 里从头到尾什么都没装。之前每一步"验证通过"都是真的,只是验证的对象从头错到尾。

卸掉宿主机上的,把 msi 弄进 DC01 重新装,一次通过。

这次学到的比任何技术点都重要:多台机器之间操作,执行命令前先 hostname 确认自己在哪。"验证通过"和"验证对了对象"是两回事,后者才是真的。

五、故障演练的两个教训

坑 9:照着教程 dd 写 3GB,差点把盘写挂

某教程验证磁盘告警的写法:

dd if=/dev/zero of=/tmp/bigfile bs=1M count=3000

动手前先 df 了一眼:根分区 9.8G,可用只剩 3.4G。3GB 写下去直接到 96%——日志写不进去、服务随时可能崩。教程的数字在他的机器上是对的,在我这就是事故。

最后改用更安全的方式:不写满磁盘,把触发器的阈值宏临时调低({$VFS.FS.PUSED.MAX.WARN} 从 80 改到 50),配合 Latest data 页面的 Execute now 强制执行一次采集,告警立刻触发,验证完把宏改回去。inode 告警同理:mkdir 后建 10 万个小文件把 inode 吃掉一截,再把 {$VFS.FS.INODE.PFREE.MIN.WARN} 临时从 20 调到 70。

生产环境做告警验证都应该这么干:验证的是链路通不通,不是真的把系统搞挂

坑 10:nohup -stress——命令不存在,报错还被吞了

造 CPU 告警要用 stress 压测:

nohup -stress --cpu 8 --timeout 300 > /dev/null 2>&1 &

-stress 多打了个横杠。shell 返回 [1] 3158,看着像启动了,其实进程立刻就退了。想看为什么,错误早被 > /dev/null 2>&1 吞了。跑 jobs 一看:

[1]+  Exit 125                nohup -stress --cpu 8 ...

Exit 125 = 命令找不到。改成 nohup stress ... 后 jobs 显示 Running,uptime 看 load average 爬到 5.31,几分钟后告警如约而至。

两个教训:后台命令跑完必须用 jobs 或实际效果验证一次(返回提示符不等于执行成功);> /dev/null 2>&1 会连错误一起吞掉,诊断阶段别急着把 stderr 扔了。

写在最后

三天下来,真正值得带走的不是某个命令,而是几条反复被验证的规矩:

  1. sed 改配置后必须 grep 回看。sed 匹配不到就静默跳过,不报错不警告,我在这上面栽了三次,三次都是回看抓回来的。
  2. 任何单一视角的证据都不能证明"能通"。配置文件、进程状态、网络连通、告警日志,是四道独立的关卡,端到端走通才算数。
  3. 排查问题先找离源头最近的观测点。告警没收到,看 Action log(Zabbix 尝试发了吗)比看脚本日志(脚本被调了吗)有效得多。

监控系统本身是个"发现问题"的工具——如果搭建过程里养不成验证和回看的习惯,搭出来的监控也发现不了问题。