自建k8s网络_nodeport不通排查思路

🎉 太棒了!你已经完成了一个完整的 Kubernetes 网络故障排查实战。现在我为你整理一篇 高质量技术博客,标题为:


📌 背景问题

在搭建 Kubernetes 集群时,我们常使用 NodePort 类型 Service 将 Pod 暴露到节点端口(如 30081)。但在某些环境下,即使配置正确,访问 http://<node-ip>:30081 却始终超时或卡住。

本文记录一次真实生产级排错过程,从 IPVS 规则缺失 → 内核模块未加载 → Calico IPIP 隧道干扰 → tunl0 接口残留 的完整链路,最终彻底解决 NodePort 不通问题。


❌ 故障现象

  • 创建了 NodePort Service:

    apiVersion: v1
    kind: Service
    metadata:
      name: custom-nginx-service
    spec:
      type: NodePort
      ports:
        - port: 80
          targetPort: 80
          nodePort: 30081
      selector:
        app: custom-nginx
    
  • 执行 curl -I http://192.168.122.96:30081 始终卡住,需 ^C 中断。

  • netstat -tulnp | grep :30081 无监听。

  • kubectl get endpoints 显示后端 Pod 正常。

  • 防火墙已关闭(ufw status inactive)。


🔍 排查思路与步骤

✅ Step 1:确认 kube-proxy 是否正常工作

netstat -tulnp | grep :30081
# 输出为空 → 表示没有进程监听该端口

虽然 NodePortiptables/ipvs 层实现,并非传统监听,但仍需检查代理状态。


✅ Step 2:检查 kube-proxy 模式(IPVS 还是 iptables)

查看配置:

kubectl exec -n kube-system kube-proxy-xxxxx -- cat /var/lib/kube-proxy/config.conf | grep mode
# 输出:mode: ipvs

说明使用的是 IPVS 模式,应通过 ipvsadm 查看规则。


✅ Step 3:验证 IPVS 规则是否存在

ipvsadm -ln | grep :30081
# 初始输出为空 → 规则未生成!

这说明:kube-proxy 未能创建转发规则


✅ Step 4:检查内核模块是否加载

IPVS 依赖以下内核模块:

lsmod | grep ip_vs
# 初始为空 → 模块未加载!

手动加载必要模块:

modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack
modprobe br_netfilter

持久化配置:

echo -e 'ip_tables\nip_vs\nbr_netfilter' > /etc/modules-load.d/k8s.conf

✅ Step 5:重启 kube-proxy 强制重建规则

kubectl delete pod -n kube-system -l k8s-app=kube-proxy

等待新 Pod 启动后再次检查:

ipvsadm -ln | grep :30081
# 现在有输出了!
TCP  192.168.122.96:30081 rr
  -> 10.244.169.159:80            Masq    1      0          0

✅ IPVS 规则已生成!

curl 仍不通?继续深挖……


✅ Step 6:检查 Calico 的 IPIP 配置

查看 IPPool:

kubectl get ippool -o yaml

发现关键问题:

spec:
  ipipMode: Always   # ← 错误!强制所有流量走 IPIP 隧道

在局域网或单节点环境中,ipipMode: Always 会导致:

  • 流量被封装进 tunl0
  • 对端无法解包或丢弃
  • 回包丢失,连接超时

✅ Step 7:禁用 IPIP 模式

使用 kubectl patch 修改配置(注意必须加 --type=merge):

kubectl patch ippool default-ipv4-ippool --type=merge --patch '{
  "spec": {
    "ipipMode": "Never",
    "vxlanMode": "Never"
  }
}'

验证更新成功:

kubectl get ippool -o yaml | grep ipipMode
# 输出:ipipMode: Never

✅ Step 8:关闭残留的 tunl0 接口

⚠️ 即使禁用了 IPIP,Linux 内核中的 tunl0 设备不会自动 down!

ip link show tunl0
# 输出:state UNKNOWN 或 UP → 仍在运行!

# 必须手动关闭
ip link set tunl0 down

再次检查:

ip link show tunl0
# 应显示 state DOWN

✅ Step 9:最终测试

curl -I http://192.168.122.96:30081

🎯 输出:

HTTP/1.1 200 OK
Server: nginx/1.25.3
...

🎉 成功!NodePort 终于通了!


🧩 根本原因总结

问题 原因 解法
1. IPVS 规则未生成 ip_vs 内核模块未加载 modprobe ip_vs* + 持久化
2. Calico 封装流量 ipipMode: Always 导致隧道封装 改为 Never
3. 路由冲突 tunl0 接口仍处于 UP 状态 ip link set tunl0 down

⚠️ 这三个问题叠加,导致看似“配置正确却无法访问”的诡异现象。


✅ 最佳实践建议

1. 安装阶段就设置好内核模块

# 所有节点执行
cat > /etc/modules-load.d/k8s.conf <<EOF
ip_tables
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
br_netfilter
EOF

modprobe br_netfilter
sysctl -p /etc/sysctl.d/k8s.conf

2. Calico 默认关闭 IPIP(除非跨公网)

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  cidr: 10.244.0.0/16
  natOutgoing: true
  ipipMode: Never     # 👈 生产推荐
  vxlanMode: Never
  nodeSelector: all()

3. 使用 kubectl patch --type=merge 修改 CRD

不要用默认 patch,要显式指定类型:

kubectl patch ippool xxx --type=merge --patch '{...}'

4. 定期清理废弃接口

特别是升级或变更网络插件后:

ip link set tunl0 down
ip link set vxlan.calico down

📚 参考资料


💬 结语

Kubernetes 网络问题是运维中最复杂的部分之一。本次排错历时多步,涉及 kube-proxy、IPVS、Calico、内核模块、tunl0 接口 多层联动。

希望这篇实战记录能帮助你在遇到类似问题时快速定位,少走弯路。

记住一句话:
当 NodePort 不通时,先查 ipvsadm -ln,再看 ip link show tunl0,最后别忘了 kubectl patch --type=merge


📌 如果你觉得这篇文章有用,请点赞、收藏、分享给更多人!

💬 欢迎留言讨论你遇到的 K8s 网络问题,我们一起攻克!


附:一键修复脚本(适用于同类环境)

#!/bin/bash
# fix-k8s-nodeport.sh

echo "👉 加载必要内核模块"
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack
modprobe br_netfilter

echo "👉 持久化模块"
echo -e 'ip_tables\nip_vs\nbr_netfilter' > /etc/modules-load.d/k8s.conf

echo "👉 禁用 Calico IPIP"
kubectl patch ippool default-ipv4-ippool --type=merge --patch '{
  "spec": {
    "ipipMode": "Never",
    "vxlanMode": "Never"
  }
}' || echo "⚠️ 请确保 calico 已安装"

echo "👉 关闭 tunl0"
ip link set tunl0 down

echo "✅ 修复完成,请测试 curl 访问 NodePort"

📝 发布建议

  • 发布平台:掘金、知乎、CSDN、SegmentFault、个人博客
  • 标签:#kubernetes #calico #nodeport #网络故障 #运维实战

需要我帮你生成 Markdown 文件或 HTML 版本吗?也可以做成 PDF 手册哦 😊

posted @ 2025-10-23 10:28  完颜振江  阅读(13)  评论(0)    收藏  举报