一次 monitoring prometheus跨节点访问失败问题的排查与解决

背景

最近在 Kubernetes 集群中通过 kube-prometheus 项目部署了监控系统,希望使用 NodePort 方式从集群外部访问 Prometheus 的 Web UI(端口 9090),以便团队成员查看监控指标。

集群环境:

  • Kubernetes 版本:v1.x
  • 网络插件:Calico (IPIP 模式)
  • Prometheus 部署:kube-prometheus(通过 manifests 或 Helm)
  • 测试的 Nginx 应用:部署在 default 命名空间,使用 NodePort 对外暴露,访问正常

奇怪的是,Prometheus 的 NodePort 服务虽然创建成功,但外部访问总是超时或连接失败,而同一个集群中自己部署的 Nginx 却能正常工作。这引发了我们的排查兴趣。

问题现象

  1. 为 Prometheus 创建 NodePort Service:

    kubectl expose svc prometheus-k8s -n monitoring --name prom-nodeport --type NodePort --port 9090

    Service 创建成功,分配的 NodePort 端口为 30231(示例)。

  2. 尝试通过任意节点 IP 访问 http://<node-ip>:30231,浏览器一直加载超时,curl 命令卡住或报 Connection timeout
  3. 但自己部署的 Nginx NodePort 服务(端口 31300)可以正常访问,返回 Welcome to nginx 页面。
  4. 集群内部访问 Prometheus 的 ClusterIP Service 正常:

    kubectl run test --rm -it --image=busybox -- wget -O- http://prometheus-k8s.monitoring:9090

    能正常返回 302 跳转。

  5. 直接访问 Prometheus Pod IP 从 master01 节点超时,但从 Pod 所在节点(work02)本地访问成功。

这提示问题可能出在跨节点网络安全策略层面。

排查过程

第一步:检查 Service 和 Endpoints

kubectl get endpoints -n monitoring

输出显示 Prometheus 的 Endpoints 正常,包含两个 Pod IP。

第二步:检查 Pod 监听地址

进入 Prometheus 容器查看端口监听情况:

kubectl exec -n monitoring prometheus-k8s-0 -- netstat -tlnp | grep 9090

输出 tcp6 :::9090 LISTEN,表示监听在 IPv6 的 ::,这在 Linux 默认配置下(net.ipv6.bindv6only=0)同样接受 IPv4 连接,理论上不是问题。

查看完整启动参数,没有 --web.listen-address 参数,默认应为 0.0.0.0:9090

第三步:测试直接访问 Pod IP

获取 Prometheus Pod IP:100.90.254.202,从 master01 节点访问:

curl -v http://100.90.254.202:9090

卡住,无响应。从 work02(Pod 所在节点)访问:

curl -v http://100.90.254.202:9090

成功返回 302 跳转。

结论:master01 到 work02 的 Pod 网络不通,但 work02 本机到 Pod 是通的。

第四步:对比 Nginx Pod 的跨节点访问

查看 Nginx Pod(也在 work02 上)的 IP:100.90.254.216,从 master01 访问:

curl -v http://100.90.254.216

成功返回 Nginx 欢迎页。

说明 master01 到 work02 的 Pod 网络基础是通的,问题只针对 Prometheus Pod。

第五步:检查网络路由

在 master01 上查看路由:

ip route get 100.90.254.202

输出:

100.90.254.202 via 100.100.157.14 dev tunl0 src 100.85.170.128

路由正常,下一跳是 work02 的物理 IP,走 IPIP 隧道。

master01 能 ping 通 work02 的物理 IP 100.100.157.14,但 ping 不通 Pod IP。说明 IPIP 隧道本身可能正常,但数据包被中间环节丢弃。

第六步:怀疑 NetworkPolicy

monitoring 命名空间下的 NetworkPolicy 可能限制了入站流量。查看:

kubectl get networkpolicies -n monitoring

存在 prometheus-k8s 策略。查看详情:

kubectl describe networkpolicy prometheus-k8s -n monitoring

关键片段:

Ingress:
  To Port: 9090/TCP
    From:
      PodSelector: app.kubernetes.io/name=prometheus
  To Port: 9090/TCP
    From:
      PodSelector: app.kubernetes.io/name=prometheus-adapter
  To Port: 9090/TCP
    From:
      PodSelector: app.kubernetes.io/name=grafana

规则只允许带有特定标签的 Pod 访问 9090 端口,不允许来自其他 Pod 或节点 IP 的请求。

这解释了为什么:

  • 从 master01 节点直接访问 Pod IP 被拒绝(源 IP 是节点 IP,不在白名单中)。
  • 即使通过 NodePort,流量经过 kube-proxy 转发后源 IP 变为节点 IP,同样被拒绝。
  • 从集群内部其他 Pod(如 test Pod)访问可能成功,如果那些 Pod 具有允许的标签。

而 Nginx 所在的 default 命名空间没有 NetworkPolicy,所以访问不受限。

解决方案

修改 NetworkPolicy prometheus-k8s,允许来自集群节点子网的访问,或者直接允许所有来源(测试环境可用)。

方法一:允许所有来源(快速测试)

kubectl edit networkpolicy prometheus-k8s -n monitoring

ingress 规则改为:

spec:
  ingress:
  - {}   # 空规则表示允许所有入站流量

保存退出后立即生效。

验证:

curl -v http://100.90.254.202:9090   # 成功
curl http://<任意节点IP>:<NodePort>   # 成功

方法二:添加 ipBlock 白名单(推荐生产环境)

保留原有策略,额外添加一条允许节点子网访问的规则:

  ingress:
  # ... 原有规则 ...
  - from:
    - ipBlock:
        cidr: 100.100.0.0/16   # 替换为你的节点网段
    ports:
    - port: 9090
      protocol: TCP

这样既保持了内部 Pod 之间的安全隔离,又允许集群外通过 NodePort 或直接从节点访问 Prometheus。

总结

  1. NodePort 不通不一定是 Service 或 kube-proxy 的问题,有可能是更高层级的网络策略(NetworkPolicy)拦截了流量。
  2. NetworkPolicy 作用范围:它作用于 Pod 的网络层,可以限制进出 Pod 的流量。默认 deny 或精细 allow 策略会导致外部访问失败。
  3. 排查思路:当 NodePort 不通时,逐步缩小范围:

    • 检查 Service Endpoints
    • 测试直接访问 Pod IP(从不同节点)
    • 检查 Pod 监听端口
    • 检查跨节点基础网络(ping Pod IP)
    • 检查 NetworkPolicy
  4. 生产环境建议:不要直接允许所有来源,而是通过 ipBlock 限制在可信网络段内,或使用 Ingress + 基本认证来保护 Prometheus 端点。
正文到此结束
  • 本文作者:xinyu.he
  • 文章标题:k8s-pod跨节点通信问题记录
  • 本文地址:https://www.hxy.bj.cn/archives/819/
  • 版权说明:若无注明,本文皆Xinyu.he blog原创,转载请保留文章出处。
最后修改:2026 年 05 月 26 日
如果觉得我的文章对你有用,请随意赞赏