K8s公网集群内Pod无法跨节点通信排查案例

环境说明

  • K8s集群内节点通过公网IP互通(关键点
  • 域名解析正常
  • 集群使用Flannel网络插件
    • 使用 VXLAN (udp 8472端口)
    • 采用默认配置

转载说明

  • 原创内容,请注明出处

1. 排查思路

1.1 控制平面节点抓包

bash 复制代码
sudo tcpdump -i eth0 -n port 8472

抓包日志如下

bash 复制代码
# Overlay 通信, pod间通信
IP 10.244.0.0.47464 > 10.244.1.72.10250: Flags [S], seq 2153322784, win 64240, options [mss 1460,sackOK,TS val 1895790326 ecr 0,nop,wscale 7], length 0

# Underlay 传输,将pod间通信信息通过节点传输
00:54:02.148025 IP 49.232.87.190.33673 > 82.156.88.229.8472: OTV, flags [I] (0x08), overlay 0, instance 1

---

IP 10.244.0.0.14642 > 10.244.1.72.10250: Flags [S], seq 3355553120, win 64240, options [mss 1460,sackOK,TS val 1895790740 ecr 0,nop,wscale 7], length 0

00:54:02.561412 IP 49.232.87.190.49894 > 82.156.88.229.8472: OTV, flags [I] (0x08), overlay 0, instance 1

这些流量是K8s中Flannel从控制平面节点发往工作节点的流量,从length 0 明显可以看出没有收到来自工作节点的响应,但理论上如果两个节点连通是可以收到响应的

停掉如上抓包进程,我们进行更精确的抓包

bash 复制代码
sudo tcpdump -i eth0 -n port 8472 | grep -3 -C 3 invalid

1.2 工作节点抓包

bash 复制代码
sudo tcpdump -i any -n udp port 8472

可以发现工作节点没有接收到任何流量,但实际上控制平面节点却不断往工作节点发送流量

维持抓包进程

1.3 控制平面节点手动往工作节点发送一条消息

bash 复制代码
# 一条"invalid"的信息,方便控制平面精确抓包
echo "VXLAN" | nc -u 82.156.88.229 8472

1.4 查看控制平面节点的抓包日志

bash 复制代码
IP 10.244.0.0.19215 > 10.244.1.72.10250: Flags [S], seq 1293368681, win 64240, options [mss 1460,sackOK,TS val 1897566360 ecr 0,nop,wscale 7], length 0

01:23:38.181413 IP 49.232.87.190.42458 > 82.156.88.229.8472: OTV, flags [I] (0x08), overlay 0, instance 1

----重点信息 START

01:23:38.537738 IP 10.2.24.12.50511 > 82.156.88.229.8472: OTV, [length 6 < 8] (invalid)

--- 重点信息 END

IP 10.244.0.0.9238 > 10.244.1.72.10250: Flags [S], seq 3574053469, win 64240, options [mss 1460,sackOK,TS val 1897567380 ecr 0,nop,wscale 7], length 0

01:23:39.201415 IP 49.232.87.190.48421 > 82.156.88.229.8472: OTV, flags [I] (0x08), overlay 0, instance 1

我们可以看到刚才发送消息对应的流量,它是从控制平面节点内网IP到工作节点公网IP,此处虽然length 0,但那是因为我们没有在工作节点发送响应

1.5 查看工作节点的抓包日志

bash 复制代码
01:23:38.537383 eth0  In  IP 49.232.87.190.50511 > 10.2.24.3.8472: OTV, [length 6 < 8] (invalid)

工作节点接收到了流量,而且流量的 src 变成了控制平面节点的公网IP, 由此我们猜想 : 只有 src控制平面节点内网IP的流量从网卡出来,才能被工作节点接收到, 下一步我们进行猜想的验证

1.6 控制平面节点手动往工作节点发送一条消息

指定消息请求的 src 为控制平面节点公网IP

bash 复制代码
echo "VXLAN" | nc -u -s 49.232.87.190 82.156.88.229 8472

1.7 查看控制平面节点的抓包日志

bash 复制代码
IP 10.244.0.0.36977 > 10.244.1.72.10250: Flags [S], seq 4056525145, win 64240, options [mss 1460,sackOK,TS val 1898115736 ecr 0,nop,wscale 7], length 0

01:32:50.369407 IP 49.232.87.190.40861 > 82.156.88.229.8472: OTV, flags [I] (0x08), overlay 0, instance 1

----重点信息 START

01:32:53.778916 IP 49.232.87.190.42542 > 82.156.88.229.8472: OTV, [length 6 < 8] (invalid)

----重点信息 END

IP 10.244.0.0.39586 > 10.244.1.72.10250: Flags [S], seq 140640535, win 64240, options [mss 1460,sackOK,TS val 1898125336 ecr 0,nop,wscale 7], length 0

01:32:57.157869 IP 49.232.87.190.34355 > 82.156.88.229.8472: OTV, flags [I] (0x08), overlay 0, instance 1

可以看到,流量的 src 确实是控制平面节点公网IP,下一步去看工作节点的抓包日志

1.8 查看工作节点的抓包日志

没有任何信息输出,这证明了我们的猜想,

结论 : Pod无法跨节点访问Service是因为我们经过Flannel的网络请求的 src控制平面公网IP, 这样的流量是无法被云厂商转发的;

因为我们使用的轻量应用服务器,网卡和内网IP都是虚拟的,任何从机器的内网IP流出的流量,都会先到达云厂商的网关,云厂商会将内网IP伪装成对应的公网IP, 发送到目标公网IP对应的机器, 机器将响应数据再通过请求方的公网IP回传,这样才能达成通信的完整链路;

如果网络请求的 src 是公网IP,一是云厂商的网关不允许这样的流量,会抛弃掉这样的流量,第二就是,就算请求能到达目标机器,目标机器响应的时候在网络空间根本无法路由到请求方的 内网IP , 也就无法达成通信的完整链路。

2. 解决思路

在K8s集群节点通过公网IP互通的环境下,节点网络请求从网卡出的时候,保证 src 为内网IP

比如我们使用 Flannel 作为网络插件的话,安装 Flannel 可以采用如下配置:

控制平面机器上执行

bash 复制代码
# 下载Flannel的Manifest文件
# 如果网络原因阻碍,可以本地下载文件后上传到服务器使用
sudo wget -O kube-flannel.yml https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml


# 修改 kube-flannel.yml

## 第一处修改点
containers:
- args:
  - --public-ip=$(PUBLIC_IP)  # 新增行
  - --iface-regex=10\.2\.\d+\.\d+  # 新增行,正则匹配你所有机器内网IP, 因为每个节点都会有一个flannel的Pod
  - --ip-masq=true
  - --kube-subnet-mgr
  command:
  - /opt/bin/flanneld
    
## 第二处修改点
env:
- name: PUBLIC_IP # 新增环境变量
  valueFrom:
	fieldRef:
	  fieldPath: status.podIP
- name: POD_NAME
  valueFrom:
	fieldRef:
	  fieldPath: metadata.name
	  

# 部署 Flannel
kubectl apply -f kube-flannel.yml

创作不易,希望大家多多支持,文章持续更新,我们下期见.

程序员白话 | [原创]

点关注不迷路

可以抖音搜索「程序员白话」,大家有任何问题都可以私聊我,知无不言~

相关推荐
Olrookie9 小时前
ruoyi-vue(十二)——XSS脚本,防重复提交,全局异常处理,框架验证,日志配置以及上传下载
笔记·后端
深蓝淘宝API9 小时前
从 0 到 1 学 Python 爬虫:30 分钟爬取电商商品列表(附完整代码 + 注释)
后端
程序员清风9 小时前
贝壳三面:RocketMQ和KAFKA的零拷贝有什么区别?
java·后端·面试
爱吃烤鸡翅的酸菜鱼10 小时前
Ubuntu环境下的 RabbitMQ 安装与配置详细教程
后端·ubuntu·rabbitmq·java-rabbitmq
小蒜学长10 小时前
校园外卖点餐系统(代码+数据库+LW)
java·数据库·spring boot·后端
Sweety丶╮79410 小时前
【Kubernetes】知识点2
云原生·容器·kubernetes
人生苦短12810 小时前
k8s常用命令
linux·容器·kubernetes
IT_陈寒11 小时前
SpringBoot 3.2 踩坑实录:这5个‘自动配置’的坑,让我加班到凌晨三点!
前端·人工智能·后端
绝无仅有11 小时前
系统面试设计架构的深度解析:方法论、宏观与微观分析
后端·面试·github