在K8S已经是多数公司基础设施标配的今天,监控这块反而成了很多运维团队的老大难。Prometheus生态固然强大,但如果你所在的公司已经在用Zabbix 6统一做物理机、虚拟机、中间件和云资源的监控,再单独为K8S搭一套Prometheus + Grafana,就意味着两套监控体系长期并存、两边的告警规则和值班流程互相割裂。我个人的观点是:与其强行迁移,不如让Zabbix 6把K8S也纳管进来。这篇博文就围绕Zabbix 6通过Zabbix-Proxy监控K8S集群的完整落地过程来写,适合那些已经跑了Zabbix 6、又想在不推翻现有监控体系的前提下把K8S集群纳入统一监控的运维同学参考。
整个方案的核心思路是:在K8S集群的sidecar网络或机房内网部署一个Zabbix-Proxy,由Proxy主动调用K8S API Server的REST接口拉取指标数据,再统一回传Zabbix-Server。这样既不需要在每个K8S节点上安装Zabbix Agent,也不需要暴露API Server给Zabbix-Server所在网段,安全性和扩展性都更可控。下面我把这套方案的选型逻辑、配置步骤、模板细节和踩坑记录完整展开,希望能帮你少走弯路。
1. 方案选型:为什么监控K8S要用Zabbix-Proxy
1.1 K8S监控的三种主流落地方式
K8S监控选型这件事,业内其实没有标准答案。大体上分成三派:纯Prometheus流派、Zabbix直连流派、Zabbix-Proxy中转流派。纯Prometheus方案在云原生场景下确实很顺手,ServiceMonitor机制可以自动发现应用指标,Grafana的社区Dashboard也多到看不完。但它的短板也明显:指标存储在TSDB里的成本不低,长期留存需要Thanos或者VictoriaMetrics来做扩展,而且告警规则和值班体系往往和公司已有的Zabbix告警流程是两套,出问题的时候需要在两个系统之间来回切换。
Zabbix直连K8S API这种方式,适合集群规模很小、API Server可以直接被Zabbix-Server网络访问的测试环境。但生产环境一般不推荐,原因有三:一是Zabbix-Server通常部署在独立的监控网段,和K8S管理网段之间有防火墙策略,为监控单独放通API Server的6443端口本身就是一次安全评审;二是Zabbix-Server要对几十个采集项做数据拉取,一旦K8S集群规模大了,这边拉取频率稍微调高一点,API Server的负载就会出现可感知的波动;三是如果K8S集群做了网络隔离或者处于多个机房,Zabbix-Server直连的网络路径根本不一定通。
Zabbix-Proxy中转流派是目前生产环境里最稳的组合方式。Proxy部署在K8S集群所在的机房或者集群内部,由它去访问API Server的6443端口,然后Proxy和Server之间只保持一个主动模式的TCP连接。这个连接走的是Zabbix自身的通信协议,端口可以自定义,防火墙策略也只需要放通这一条链路,比直接暴露API Server要干净得多。
1.2 Proxy模式解决的核心痛点
我最早在测试环境里做Zabbix 6 + K8S监控时,图省事直接让Server去拉K8S API,结果踩了两个坑:第一个是网络隔离,K8S集群的管理网段和监控网段之间隔了好几层防火墙,申请放通6443端口走了快一周的流程;第二个是采集压力,K8S集群有十几个节点、几百个Pod,Zabbix Server默认的采集频率一跑起来,发现规则加上API拉取请求数量很快就上去了,Server端的历史数据存储和网络IO都出现明显压力。
换成Proxy模式之后,这两个问题都迎刃而解。Proxy部署在K8S集群附近,和API Server之间的网络路径短、延迟低,而且Proxy本身会做数据缓冲,即使Proxy和Server之间的网络出现短暂抖动,采集到的数据也会缓存在Proxy本地,等网络恢复之后再补传。这种架构实际上是把“监控采集”这一层从Server中解耦出来了,Server只负责存储、计算和告警,采集的压力全部下沉到Proxy,压力分散之后整条链路都稳了不少。
1.3 整体数据采集链路设计
这套方案的数据采集链路大概是这样的:Zabbix-Proxy通过kubeconfig文件携带ServiceAccount的token去访问K8S API Server,API Server返回JSON格式的资源数据;Proxy上的模板通过预处理脚本和JSONPath从返回数据里提取出节点状态、Pod数量、容器重启次数、CPU和内存请求量等指标,然后统一回传到Zabbix-Server。Zabbix-Server再做数据入库、触发器和告警通知。
这套链路里最关键的一点是:Zabbix 6官方提供了专门的Kubernetes监控模板,模板通过HTTP Agent类型的监控项从API Server采集数据,不需要在K8S节点上装任何Agent,也不需要在Pod里塞exporter。官方模板覆盖了集群节点、Pod、容器、命名空间、Deployment等维度的核心指标,基本能满足日常监控需求。如果有更细粒度的自定义指标,还可以在模板基础上扩展。
2. 环境准备与K8S侧认证授权配置
2.1 K8S侧创建ServiceAccount与RBAC授权
要让Zabbix-Proxy读取K8S API的数据,第一步不是在Zabbix这边配什么,而是先到K8S集群里创建一个专用的认证账号。很多初学者会直接用K8S集群的admin kubeconfig去对接Zabbix,这是非常危险的操作,等于把整个集群的管理权限交给了监控系统。我们只需要给Zabbix一个“读权限”就够了。
我建议创建一个名为zabbix-monitor的ServiceAccount,并绑定到只读权限的ClusterRole上。以下manifest是生产环境验证过的:
apiVersion: v1 kind: ServiceAccount metadata: name: zabbix-monitor namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: zabbix-monitor-readonly rules: - apiGroups: [""] resources: - nodes - pods - services - endpoints - namespaces - componentstatuses - persistentvolumes - persistentvolumeclaims - configmaps - secrets verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: - deployments - statefulsets - daemonsets - replicasets verbs: ["get", "list", "watch"] - apiGroups: ["metrics.k8s.io"] resources: - pods - nodes verbs: ["get", "list"] - apiGroups: ["batch"] resources: - jobs - cronjobs verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: zabbix-monitor-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: zabbix-monitor-readonly subjects: - kind: ServiceAccount name: zabbix-monitor namespace: kube-system这里有一个细节需要注意:如果你的K8S集群部署了metrics-server,而且你想让Zabbix通过metrics.k8s.io这个API组拿到Pod和Node的CPU、内存实时指标,就要把metrics.k8s.io这个apiGroup加进去。否则Zabbix只能拿到资源请求量和限制量这些静态数据,拿不到实时使用率。
2.2 生成对接用的kubeconfig文件
ServiceAccount创建好之后,我们需要拿到它的token,并生成一个kubeconfig文件。这个文件就是Zabbix-Proxy访问K8S API的“身份证”。但K8S 1.24版本之后,ServiceAccount的Secret不再自动生成,需要手动创建并绑定,操作方式跟旧版本有一点区别。
先拿到ServiceAccount的token。如果K8S版本是1.24及以上,需要先创建一个Secret引用这个ServiceAccount:
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Secret metadata: name: zabbix-monitor-token namespace: kube-system annotations: kubernetes.io/service-account.name: zabbix-monitor type: kubernetes.io/service-account-token EOF然后获取token内容:
TOKEN=$(kubectl -n kube-system get secret zabbix-monitor-token -o jsonpath='{.data.token}' | base64 -d) echo $TOKEN接着创建kubeconfig文件。这里有个坑,直接手动编辑kubeconfig很容易出错,因为certificate-authority-data的值需要经过base64编码,而且client-certificate-data和client-key-data这两个字段可以由ServiceAccount自动生成,我们只需要把token填进去。更省事的方式是先用kubectl生成一个基础的配置文件,再手动替换token:
kubectl config set-cluster k8s-zabbix \ --server=https://<K8S-API-SERVER-IP>:6443 \ --certificate-authority=/etc/kubernetes/pki/ca.crt \ --embed-certs=true \ --kubeconfig=/opt/zabbix/kubeconfig kubectl config set-credentials zabbix-monitor \ --token=$TOKEN \ --kubeconfig=/opt/zabbix/kubeconfig kubectl config set-context k8s-zabbix \ --cluster=k8s-zabbix \ --user=zabbix-monitor \ --kubeconfig=/opt/zabbix/kubeconfig kubectl config use-context k8s-zabbix \ --kubeconfig=/opt/zabbix/kubeconfig生成好之后,用下面的命令验证一下能否正常访问集群:
kubectl --kubeconfig=/opt/zabbix/kubeconfig get nodes如果能够正常列出节点信息,说明kubeconfig文件没问题,可以放心给Zabbix-Proxy使用。这里生成的kubeconfig文件要放到Zabbix-Proxy服务器本机,路径建议放在/etc/zabbix/kubeconfig这个比较固定的位置,配置模板的时候会用到。
2.3 Zabbix-Server与Zabbix-Proxy的对接配置
K8S侧准备好之后,接下来就是在Zabbix这套体系里把Proxy加进去。Zabbix 6在Web管理界面的“Agent代理程序”菜单里可以直接添加Proxy,方式很简单,填一个Proxy名称,选择主动模式,保存即可。这里核心的坑在于Zabbix-Server和Proxy之间的连接配置。
Proxy的主动模式和被动模式区别很大。主动模式是Proxy主动向Server发起连接,Server不需要知道Proxy的公网IP;被动模式是Server去连Proxy,需要做端口映射和防火墙放通。K8S监控这种场景,我强烈建议用主动模式。因为Proxy部署在靠近K8S集群的位置,网络环境往往比较复杂,主动模式需要放通的端口更少,配置也更稳定。
在Zabbix-Proxy服务器上安装好zabbix-proxy之后,修改zabbix_proxy.conf文件的关键配置:
Server=<Zabbix-Server-IP> ServerPort=10051 Hostname=K8S-Monitor-Proxy LogFile=/var/log/zabbix/zabbix_proxy.log DBName=zabbix_proxy DBUser=zabbix DBPassword=your-proxy-db-password ConfigFrequency=300 DataSenderFrequency=5这里的Hostname必须和在Zabbix Web管理界面创建的Proxy名称完全一致,否则Proxy启动后会一直报“Hostname not found”的错误,这个坑非常常见,我后面排查章节会详细说。
配置好之后重启zabbix-proxy服务,去Zabbix Web界面“Agent代理程序”里看,如果Proxy状态显示为绿色“正常”,说明链路已经通了。到这一步,Zabbix-Proxy已经具备向Server上报数据的能力。
3. Zabbix模板配置与K8S监控主机接入
3.1 导入官方Kubernetes模板集
Zabbix 6官方其实已经提供了比较完善的K8S监控模板,模板名一般为“Kubernetes cluster”和“Kubernetes nodes”等,你需要手动导入。这套模板集的原生路径在Zabbix-Server安装目录下,也可以在官方GitHub仓库中找到——名字一般是ZBX_KUBERNETES_XX.json,不同版本细节略有不同。
导入方式就是从Web界面的“模板”->“导入”上传JSON文件。如果找不到官方模板包,还有一种变通方案:通过Zabbix Git仓库直接下载对应版本模板,然后导入。实际测试下来,Zabbix 6.0 LTS版本的K8S模板兼容性最好,6.4版本也没有太大问题。
导入后你会看到一整套模板,包括:
- Kubernetes cluster
- Kubernetes nodes
- Kubernetes pods
- Kubernetes namespaces
- Kubernetes system
这几个模板之间是有依赖关系的。比如Kubernetes system里面包含了整个集群级别的API Server可用性、调度器健康状态、ETCD状态这些核心指标;而Kubernetes nodes则是和节点相关的具体监控项。导入模板之后,先别急着创建主机,先把模板里的宏定义梳理清楚。
3.2 创建监控主机并配置关键宏
在Zabbix Web界面创建一台主机,主机名称可以叫k8s-cluster-prod,这是逻辑上的“K8S集群监控入口”。主机组按自己公司的规范来,比如可以单独建一个“Kubernetes”组。最关键的一步是,这台主机的“由代理程序监控”选项里,必须选择之前创建的K8S-Monitor-Proxy,这样所有K8S的采集任务才会通过Proxy下发和执行。
接下来是宏配置。模板里定义了若干个关键宏,其中K8S_URL和相关认证参数的填写直接决定了采集能否成功。参考我用的配置:
- {$K8S.API.URL}:https:// :6443
- {$K8S.API.TOKEN}:之前生成的ServiceAccount token值
- {$K8S.API.CA}:CA证书内容,注意这里填的是certificate-authority-data解码后的原始内容,不是base64编码后的字符串
- {$K8S.CLUSTER.NAME}:集群自定义名称,比如production
- {$K8S.POD.NAME}:Pod名称匹配正则,默认可以不填,用模板默认值
这里需要特别注意CA证书的处理。很多人在这个环节卡住,是因为Kubernetes的config文件里certificate-authority-data是base64编码的,而Zabbix模板里的{$K8S.API.CA}宏要求的是原始明文证书内容。如果你直接复制config文件里那串base64字符串过去,Zabbix的API请求会一直报证书错误。要把那串字符串解码之后再把明文内容填进去:
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d如果是自签证书或者测试环境不想校验证书,也可以把{$K8S.API.CA}留空,但我不推荐在生产环境这么做,证书校验还是应该要的。
宏配置完成之后,把“Kubernetes cluster”、“Kubernetes nodes”、“Kubernetes pods”这几个模板链接到主机上。稍等几分钟,到“监测”->“主机”页面看这台主机的可用性状态,如果显示绿色Zabbix图标,说明Proxy和K8S API之间的链路已经通了。如果还是灰色,点击“检测”按钮看具体的错误信息,排查方向上先确认kubeconfig路径和宏里的API地址是不是Proxy能直接访问的。
3.3 数据采集验证与常用指标解读
链路通了之后,下一步是验证数据是否真的进来了。到“监测”->“最新数据”页面选择k8s-cluster-prod这台主机,你会看到很多监控项,包括集群节点数、Pod总数、CPU请求量、内存请求量、容器重启次数、Deployment可用副本数等。我习惯先看这三个关键指标:
第一个是集群节点状态。这个监控项是通过发现规则扫出来的,每扫到一个K8S节点就会生成一个带节点名称的子监控项,包含Ready状态、CPU核心数、内存容量、kubelet版本等信息。如果在“最新数据”里看不到节点相关数据,说明发现规则没有执行成功,要去“采集”->“发现规则”里手动执行一次,看看报错什么。
第二个是Pod状态分布。Zabbix官方模板会把Pod按Running、Pending、Failed等状态统计出来。这个指标对判断集群健康度非常直观,如果Pending的Pod数量突然多起来,八成是资源不足或者有调度异常。
第三个是容器重启次数。这个指标是从Pod的containerStatuses字段里拿到的restartCount值,对定位线上服务稳定性问题很有帮助。如果某个容器的重启次数在持续上涨,说明进程在频繁崩溃,即使Pod还是Running状态,也要尽快介入排查。
数据进来之后,告警规则也要顺手确认一下。官方模板自带了一些触发器,比如节点NotReady、Pod频繁重启、API Server不可用等。我建议自己再补两条:
- 节点CPU使用率超过85%持续10分钟,这个阈值要根据集群实际规格来调,不要照搬。
- Deployment可用副本数少于期望副本数,这个对高可用应用非常重要。
自定义触发器的时候,表达式里需要用到通过metrics.k8s.io API拿到的实时CPU使用量,然后除以节点可分配CPU总量来算使用率。这个计算逻辑在Zabbix模板里已经内置了,你只要找到对应的监控项key,写触发器表达式时引用它就行。
4. 常见问题与排查技巧实录
4.1 API权限与证书报错
这套方案在配置过程中最容易踩的坑,基本都集中在K8S API访问这一层。最常见的一个报错是HTTP 403 Forbidden。这个错误的意思是认证通过了,但权限不足。排查思路依次确认三点:第一,ClusterRoleBinding是否创建成功,有没有正确绑定到kube-system命名空间下的zabbix-monitor这个ServiceAccount;第二,token有没有过期或者被轮换,如果集群开启了TokenRequest功能,token是有实效的,建议使用长效token或者定期轮换;第三,检查请求的API是否在RBAC规则里放通了,比如你要拉取metrics.k8s.io的指标,但ClusterRole里漏掉了这个apiGroup,那就会看到403。
另外一个高频问题就是证书校验失败。报错信息里一般会带certificate signed by unknown authority或者x509: certificate is valid for xxx, not xxx这样的关键字。前者说明{$K8S.API.CA}宏填的内容不对或者格式有问题,后者说明API Server的证书里没有包含你访问的那个IP或者域名。局域网环境里的K8S集群经常遇到后者,因为API Server证书签发时只写了节点IP或者ClusterIP,你用的地址不在证书的SAN列表里。解决办法有两个:要么把{$K8S.API.URL}改成证书SAN里已有的域名或IP;要么把证书校验跳过,但只在测试环境这么干。
遇到这种问题,我建议直接用curl模拟Zabbix的请求来排查,这样能把Zabbix模板里的复杂逻辑隔离掉,直接看K8S API返回什么:
curl -X GET https://<K8S-API-SERVER-IP>:6443/api/v1/nodes \ -H "Authorization: Bearer $TOKEN" \ --cacert /path/to/ca.crtcurl能够正常返回JSON,说明K8S侧没有问题,问题就出在Zabbix模板宏配置上;如果curl都报错,那就要先解决K8S这侧的证书和网络问题了。
4.2 数据不上报或监控项不出现
链路通了、模板也挂上了,但发现规则扫出来的监控项特别少,甚至什么都没有,这种情况多半是Zabbix的发现规则还没有执行。Zabbix的发现规则默认执行周期是3600秒,也就是一小时,如果你是刚配好的环境,等一小时才出数据,体验确实很煎熬。可以在“采集”->“发现规则”里找到对应的K8S发现规则,手动点一下“立即执行”,然后去“最新数据”里刷新看看结果。
另一种情况是Proxy一直显示红色不可达。进入zabbix_proxy.conf所在的服务器,检查日志:
tail -n 100 /var/log/zabbix/zabbix_proxy.log常见错误有几种:第一种是Hostname不匹配,Proxy配置里的Hostname和Web界面创建的Proxy名称不一致,日志里会明确提示;第二种是数据库连接失败,Proxy本地需要一个数据库来缓存数据,如果你的DBPassword配错了,Proxy会起不来;第三种是时间不同步问题,Proxy和Server之间时间差超过一定阈值,数据上报会被丢弃,这个在生产环境很隐蔽,建议把NTP统一配好。
4.3 指标延迟与历史数据异常
采集链路都正常之后,还有一些性能层面的坑需要留意。首先是数据延迟,如果你发现K8S的监控数据和实际时间差了好几分钟,需要检查zabbix_proxy.conf里的DataSenderFrequency参数,默认是5秒,就是说Proxy每5秒向Server发送一次缓冲数据。如果网络状况不好,可以适当调大这个值,但不要调太大,否则数据的实时性会变差。
另一个问题是历史数据出现断档。这种情况多数是因为Proxy的本地数据库存储空间满了,或者历史数据过期时间配置得太短。Zabbix 6在数据库层面做了自动清理,但如果Proxy的数据库表损坏了,也会导致数据无法正常写入。处理方式是重建Proxy数据库,然后重新启动Proxy服务,让它和Server重新同步。
如果发现监控项的值一直不变,比如Pod数量永远显示0,但实际集群里明明跑着几十个Pod,这种情况要去看监控项的具体错误信息。在“最新数据”页面点开监控项,看“错误”标签页,如果显示JsonPath查询失败之类的提示,往往是K8S API返回的数据结构和模板里定义的JSONPath不匹配,一般出现在K8S版本升级之后。解决办法是去模板里手动调整JSONPath,让它适配新版API返回的数据结构,或者直接更新到Zabbix官方最新模板。
4.4 模板选择与应用的小建议
最后聊聊模板使用上的几个心得。Zabbix 6官方K8S模板的监控项非常丰富,但并不是所有监控项都是你需要的。监控项越多,Proxy采集的负担越重,历史数据占用的存储空间也越大。我建议刚开始接入时,先只挂Kubernetes cluster和Kubernetes nodes两个模板,等运行稳定了,再视需要把pods、namespaces等模板挂上去。
模板里的宏不要统一放在全局宏里,因为不同集群的API地址和token都不一样,全局宏会让所有K8S主机共用同一套配置,容易串数据。每个K8S集群的主机单独配置宏,这样多集群管理的时候才能相互隔离。
另外,K8S版本的API兼容性也要留意。K8S废弃了一些API版本之后,如果你还在用旧模板,会遇到一些监控项拿不到数据的情况。比如K8S 1.16版本之后,apps/v1beta1这种旧API就不存在了,但有些第三方模板没有及时更新。Zabbix 6官方模板在这方面维护得比较及时,除非遇到特殊情况,否则优先用官方模板,少去折腾第三方模板,能省下不少时间。
跟着这套方案走下来,Zabbix 6 + Zabbix-Proxy监控K8S的链路基本就是生产可用的状态了。我个人在实际操作中体会最深的一点是:K8S监控的难点不在于Zabbix配置本身,而在于对K8S API数据结构、RBAC权限模型和证书体系的熟悉程度。你只要把K8S这侧的口子开得足够规范、足够小,Zabbix这边基本上就是填几个宏就能跑通的事。建议大家在自己的测试环境里先完整走一遍这套流程,然后逐步迭代,不用一上来就追求把所有指标都接进来。