问题现场

自己的实验集群,使用的k3s v1.25.7+k3s1, 网络使用的默认flannel vxlan模式。

NAME          STATUS   ROLES                  AGE    VERSION
whoops-home   Ready    <none>                 253d   v1.25.7+k3s1
whoops-k3s    Ready    control-plane,master   268d   v1.25.7+k3s1

节点whoops-k3s是CentOS7.9,折腾网络,改了ifcfg-eth0配置,systemctl restart network重启网络,一开始没发现,第二天发现nginx到集群的访问504。

这个小集群是在家里NAS和软路由上跑的,whoops-home上有一个内网穿透了的nginx,集群流量都经过这个nginx转进来走traefik ingress controller。

链路大概这样:

域名流量->nginx(whoops-home)->traefik(nodeport)->pod

Nginx报504,那就是Nginx到traefik不通,现在nginx在whoops-home上,traefik在whoops-k3s上,查了下发现从whoops-home上ping不通whoops-k3s上的Pod,但是从whoops-k3s可以ping通whoops-home上的pod。

whoops-k3s上的flannel vxlan因为重启网络挂了?

原因分析

先来看看netfilter的FORWARD,没问题

iptables -t filter -nvL | grep FORWARD
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)

看看路由, 也没问题,whoops-k3s是10.42.0.0/24网段,whoops-home是10.42.1.0/24网段。

default via 192.168.31.1 dev eth0
10.42.0.0/24 dev cni0 proto kernel scope link src 10.42.0.1
10.42.1.0/24 via 10.42.1.0 dev flannel.1 onlink
...

看看fdb? 不应该啊,whoops-k3s都能ping通whoops-home上的pod,arp要是有问题,咋ping出去的包,一看果然没问题。

sudo bridge fdb show | grep flannel.1
# 192.168.31.166 是 whoops-home
d6:f8:ec:13:3c:07 dev flannel.1 dst 192.168.31.166 self permanent

vxlan是走的flannel.1设备,这个设备是flanneld创建的,重启网络影响它了?但是如果配置不对,flanneld是不是应该自己感知调整回去呢?重启下k3s试试。

systemctl restart k3s

好了!重启k3s/flanneld,因为重配了flannel.1? 复现一下,特意检查flannel.1,网段配置、路由、arp、设备状态重启前后都没问题,重配重不配flannel.1应该不影响的啊,而且个人认为flanneld不应该这么不健壮,节点重启下network,整个节点的pod网络都挂掉了。

flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.42.0.0  netmask 255.255.255.255  broadcast 0.0.0.0
        inet6 fe80::b45b:f1ff:fe24:82e4  prefixlen 64  scopeid 0x20<link>
        ether b6:5b:f1:24:82:e4  txqueuelen 0  (Ethernet)
        RX packets 237089  bytes 37524217 (35.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 174244  bytes 32444345 (30.9 MiB)
        TX errors 29  dropped 5 overruns 0  carrier 29  collisions 0

抓包!

tcpdump -i flannel.1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes
22:28:45.852513 IP 10.42.1.0 > 10.42.0.210: ICMP echo request, id 12, seq 48, length 64
22:28:46.872698 IP 10.42.1.0 > 10.42.0.210: ICMP echo request, id 12, seq 49, length 64
22:28:47.896618 IP 10.42.1.0 > 10.42.0.210: ICMP echo request, id 12, seq 50, length 64
22:28:49.851093 IP 10.42.1.0 > 10.42.0.210: ICMP echo request, id 13, seq 1, length 64
22:28:50.872665 IP 10.42.1.0 > 10.42.0.210: ICMP echo request, id 13, seq 2, length 64
22:28:51.896473 IP 10.42.1.0 > 10.42.0.210: ICMP echo request, id 13, seq 3, length 64

从whoops-home上的ping包到flannel.1了,但是没给到Pod网卡,丢哪了?重启网络操作到底干了啥?真的要研究kernel怎么实现的vxlan了么?debug flannel.1设备?

network.service

直接看/etc/rc.d/init.d/network脚本,看看重启网络做了哪些操作。

start)
    apply_sysctl
...
stop)
   sysctl -w net.ipv4.ip_forward=0 > /dev/null 2>&1
...
restart|force-reload)
    cd "$CWD"
    $0 stop
    $0 start
...

好嘛,stop时候关了net.ipv4.ip_forward,flannel.1当然不把包往pod的网卡转了,重启k3s/flanneld,flanneld动态又把参数改回来了,所以就通了,复现验证一下,还真是。
搞不懂network.service stop为啥关这个,但是start时候也应该把之前的参数还回来吧?对不起,没有持久化的sysctl在start的apply_sysctl里还不回来。

修复搞定

echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf

验证一下,重启网络不影响Pod网络联通性了!

总结

之前特意研究了下flannel的vxlan模式,这次遇这么个case,又深刻了~