You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NAT环境下Kubernetes节点服务暴露及kubectl exec问题求助

Kubernetes集群中NAT后节点的服务访问与kubectl exec问题解决

问题背景

我正在运行一个包含NAT后无公网IP节点的Kubernetes集群,集群配置如下:

  • 节点组成:
    • 带公网IP的master节点
    • 带公网IP的Node1节点
    • 运行在笔记本VM中、处于NAT下无公网IP的Node2节点
  • 环境版本:所有节点均为Ubuntu 18.04,Kubernetes v1.10.2/3,Docker 17.12
  • 集群创建:通过kubeadm init --pod-network-cidr=10.244.0.0/16初始化,使用Flannel网络(kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml)
  • 节点状态:所有节点均显示Ready:
NAME         STATUS    ROLES     AGE   VERSION
master-node  Ready     master    3h    v1.10.2
node1        Ready     <none>    2h    v1.10.3
node2        Ready     <none>    2h    v1.10.2

问题现象

  1. 公网节点服务正常:在Node1上部署的Nginx NodePort服务(my-nginx)可通过http://MASTER_NODE_PUBLIC_IP:31742和http://NODE1_PUBLIC_IP:31742正常访问
  2. NAT节点服务无法公网访问:在Node2上部署的Nginx NodePort服务(nginx-behind-nat)仅能通过笔记本访问http://MY_VM_IP:32350,无法通过master或Node1的公网IP访问
  3. kubectl exec失败:无法通过kubectl exec进入Node2上的nginx-behind-nat Pod

问题根源

这个问题的核心在于NAT环境下的Node2没有公网IP,集群内其他节点(master、Node1)无法主动发起对Node2的网络连接:

  • NodePort服务的流量转发依赖kube-proxy将公网流量路由到目标节点,但由于无法访问Node2的公网IP,流量无法到达
  • kubectl exec需要K8s apiserver与目标Pod所在节点的kubelet建立连接,apiserver无法主动穿透NAT访问Node2的kubelet端口(默认10250)
  • Flannel的VXLAN隧道(默认UDP 8472端口)可能因NAT阻止入站连接,导致节点间Pod网络连通性存在隐性问题

解决方案

方案1:建立反向隧道打通节点双向通信

这是最直接的解决方式,让Node2主动向公网节点建立隧道,实现双向访问:

1.1 解决kubectl exec问题:转发kubelet端口

在Node2上执行以下命令(需要提前配置Node2到master/Node1的免密SSH):

# 把Node2的kubelet端口(10250)反向转发到master的本地10250端口
ssh -N -R 10250:localhost:10250 your-ssh-user@MASTER_PUBLIC_IP

这样apiserver就能通过master的本地端口访问Node2的kubelet,kubectl exec、kubectl logs等操作就能正常工作。

1.2 解决Flannel网络连通性:转发VXLAN端口

Flannel默认使用UDP 8472端口建立节点间隧道,在Node2上添加反向隧道转发该端口:

ssh -N -R 8472:localhost:8472 your-ssh-user@MASTER_PUBLIC_IP

完成后检查Flannel Pod日志,确认节点间隧道已建立:

kubectl logs -n kube-system -l app=flannel
1.3 解决NodePort服务公网访问:转发服务端口

针对nginx-behind-nat的NodePort(32350),在Node2上建立到Node1的反向隧道:

ssh -N -R 32350:localhost:32350 your-ssh-user@NODE1_PUBLIC_IP

现在访问http://NODE1_PUBLIC_IP:32350就能通过隧道转发到Node2的服务端口。

提示:可以把这些SSH隧道命令配置成systemd服务,实现开机自动启动,避免手动维护。

方案2:修改NodePort服务的外部流量策略

默认情况下NodePort服务的externalTrafficPolicy为Cluster,流量会先路由到任意节点再转发到目标Pod。我们可以修改为Local,让流量仅转发到运行Pod的节点,再结合隧道实现访问:

  1. 编辑nginx-behind-nat服务:
kubectl edit svc nginx-behind-nat
  1. 添加/修改externalTrafficPolicy字段:
spec:
  externalTrafficPolicy: Local
  # 其他配置保持不变
  1. 按照方案1.3的方式建立反向隧道,访问Node1的32350端口即可到达Node2的服务。

方案3:使用虚拟网络工具简化配置(推荐)

如果不想手动维护隧道,可以使用Tailscale/Headscale这类虚拟网络工具,让所有节点加入同一个虚拟私有网络(VPN),自动穿透NAT实现节点间的直接通信:

  1. 在所有节点上安装Tailscale客户端
  2. 完成节点注册后,K8s集群的节点和Pod网络会自动打通,无需额外配置隧道
  3. 此时NodePort服务可以正常通过公网节点访问,kubectl操作也能直接生效

额外检查项

  • 确认Node2的kubelet配置中--node-ip设置为VM的内部IP(可通过ps aux | grep kubelet查看)
  • 检查节点间的防火墙规则,确保kubelet(10250)、Flannel(8472)、NodePort端口的流量允许通过
  • 测试节点间的连通性:在master上通过隧道访问Node2的kubelet健康检查端点:
curl https://localhost:10250/healthz -k

内容的提问来源于stack exchange,提问作者mennanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:08:12