k8s ipvs模式下vip nodeport规则未创建原因分析

K8S IPVS模式下VIP规则未创建

辅助IP

LInux中为同一个物理网卡增加多个ip地址,以前通过ifconfig命令来创建和维护ip alias, 而在新的IPROUTE2中通过ip address命令来创建和维护Primary address与Secondary address

  • 在每一个接口上可以配置多个Primary地址和多个Secondary地址
  • 当删除一个Primary地址时,所有相关的Secondary地址也被删除。但通过*/proc*可以配置一个选项,在当前Primary地址被删除时可以将Secondary地址提升为Primary地址
  • 当主机为本地生成的流量选择源IP地址时,只考虑Primary地址
# 查看网卡是否能将second ip提升为primary ip
[root@k8s-node-1 ~]# sysctl -a | grep promote_secondaries
net.ipv4.conf.all.promote_secondaries = 1
net.ipv4.conf.default.promote_secondaries = 1
net.ipv4.conf.docker0.promote_secondaries = 1
net.ipv4.conf.dummy0.promote_secondaries = 1
net.ipv4.conf.ens33.promote_secondaries = 1
net.ipv4.conf.flannel/1.promote_secondaries = 1
net.ipv4.conf.kube-ipvs0.promote_secondaries = 1
net.ipv4.conf.lo.promote_secondaries = 0
net.ipv4.conf.tunl0.promote_secondaries = 1

# 含义
sbin/sysctl net.ipv4.conf.eth0.promote_secondaries=1 # (晋升辅助ip地址)

k8s ipvs模式下vip nodeport规则未创建原因分析_第1张图片

  • 每个节点代表的ip地址标识一个网段,这个节点的ip就是这个网段的 Primary地址,它下面所带的ip就是这个网段的Secondary地址,也就是说一个网卡可以带有各个节点所带链表长度之和个ip地址,而且这些 ip不是线形的,而是上述的吊链结构
  • 在linux中,只要一个网卡上配置的多个ip不是一个网段的,那么都是Primary IP对一个特定的网络掩码(例如网络掩码为/24),只能有一个Primary地址,就是吊链结构中上面的那条主链中的IP,linux中的Secondary address是主链结点的子链结点中的IP,这一点一定注意
  • 吊链在主链上是没有主次的,子链除了第一个节点其它节点也不分主次,都是平行的关系,但是子链中的第一个节点总是链接在主链中,它们携带的地址就是primary地址,它们下面隶属的子链携带的地址就是这个primary地址的secondary地址,如此看来,一 旦主链上一个节点被删除了,那么它的子链也将不复存在。因此linux中特意有了一个选项,就是当一个primary地址被删除时,如果它有secondary地址 的话,那么它的第一个secondary地址(长子)继承被删除的primary地址的位置成为primary地址,这样就显得很合理了,要不然在删除 primary地址的时候,如果有程序用secondary地址,那么要么延迟删除,要么程序崩溃,采用自动提升策略的话就不会出现问题
  • 至于说IP aliases,那是以前版本有的了,就是一个实现问题,解决的问题和现在的secondary IP机制一样,它主要就是在物理网卡名字后面加上后缀从而成为虚拟网络接口,本质上和secondary IP机制没有区别,区别就是IP aliases显得不是那么直观,而secondary IP却是真正让应用看到了一个网卡的多个地址,比如你要是用IP aliases的话,有的时候你总是会问eth0:0是什么?

实验环境

节点 IP
k8s-master-1 192.168.0.10
k8s-node-1 192.168.0.11
VIP 192.168.0.15

问题现象

  • 公司K8S集群内部某些节点安装了keepalived,但是在IPVS模式下,这些节点出现了VIP未创建ipvs 规则,导致无法通过VIP:PORT去访问服务
# 192.168.0.15 为VIP
[root@k8s-node-1 ~]# hostname -I
192.168.0.11 192.168.0.15 172.17.0.1 10.70.1.0

# 查看IPVS规则,可以发现192.168.0.15 并没有相应的ipvs 规则,而192.168.0.11 却有ipvs规则,这将导致我外部无法通过VIP:PORT去访问k8s service暴露出来的服务
[root@k8s-node-1 ~]# ipvsadm -ln | grep -E "192.168.0.11|192.168.0.15" -C 3
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.0.11:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  10.0.0.1:443 rr
  -> 192.168.0.10:6443            Masq    1      1          0  
  
# 查看IP地址,通过下面可以发现ens33的确是本机的IP
[root@k8s-node-1 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:1e:01:7f brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.11/24 brd 192.168.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 192.168.0.15/24 scope global secondary ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe1e:17f/64 scope link 
       valid_lft forever preferred_lft forever
........................................................

解决办法

  • 使用与ens33网卡原始IP不同网段的IP(且不能与原IP拥有相同的子网掩码),那么这个IP将被提升为primary ip(这二个不同网段的IP将会同时存在于ens33这张网卡上),此时kube-proxy就会为primary IP创建相应的IPVS规则
# 删除192.168.0.15
[root@k8s-node-1 ~]# ip addr del 192.168.0.15/24 dev ens33
	
# 添加192.168.0.15/32
[root@k8s-node-1 ~]# ip addr add 192.168.0.15/32 dev ens33

# 清空IPVS规则,kube-proxy 默认会隔段时间检查IPVS规则,并动态更新
[root@k8s-node-1 ~]# ipvsadm -C

# 查看IPVS规则,可以看到192.168.0.15相应的IPVS规则已经存在了
[root@k8s-node-1 ~]# ipvsadm -ln | grep -E "192.168.0.11|192.168.0.15" -C 3
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.17.0.1:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  192.168.0.11:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  192.168.0.15:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  10.0.0.1:443 rr
  -> 192.168.0.10:6443            Masq    1      1          0 
  
# 安装上面思路我们在添加几个不同网段的IP
[root@k8s-node-1 ~]# ip addr add 192.168.1.10/24 dev ens33
[root@k8s-node-1 ~]# ip addr add 192.168.2.10/24 dev ens33

# 这里也并没有创建规则,怀疑不能是/24,换其他的试一下
[root@k8s-node-1 ~]# ipvsadm -ln | grep -E "192.168.0.11|192.168.0.15|192.168.1.10|192.168.2.10" -C 3
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.0.11:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  192.168.0.15:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  192.168.1.10:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  192.168.2.10:39090 rr
  -> 10.70.0.159:9090             Masq    1      0          0         
TCP  10.0.0.1:443 rr
  -> 192.168.0.10:6443            Masq    1      1          0
  
# 添加/16网段
[root@k8s-node-1 ~]# ip addr add 10.8.0.10/16 dev ens33

# 查看IPVS规则,可见生成IPVS规则了
[root@k8s-node-1 ~]# ipvsadm -ln | grep 10.8
TCP  10.8.0.10:39090 rr


# 查看k8s-master-1路由表
[root@k8s-master-1 ~]# ip route show
default via 192.168.0.2 dev ens33 proto static metric 100 
10.70.0.0/24 dev cni0 proto kernel scope link src 10.70.0.1 
10.70.1.0/24 via 10.70.1.0 dev flannel.1 onlink 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
192.168.0.0/24 dev ens33 proto kernel scope link src 192.168.0.10 metric 100

# 清空k8s-master-1节点所有已知MAC地址
[root@k8s-master-1 ~]# ip neigh flush all

# k8s-master-1节点ping 192.168.2.10, 可见与192.168.2.10无法ping通,由于匹配不到路由,所以会把数据包发送给网关192.168.0.2
[root@k8s-master-1 ~]# ping 192.168.2.10
PING 192.168.2.10 (192.168.2.10) 56(84) bytes of data.
^C
--- 192.168.2.10 ping statistics ---
48 packets transmitted, 0 received, 100% packet loss, time 48149ms

# k8s-master-1节点抓包
[root@k8s-master-1 ~]# tcpdump -i ens33 arp or icmp -w cap -Nnv
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
^C23 packets captured
24 packets received by filter
0 packets dropped by kernel

# k8s-node-1节点抓包,可见网关将数据包转发到k8s-node-1节点了,但是k8s-node-1节点并没有对这个ICMP REQUEST数据包做出回应
[root@k8s-node-1 ~]# tcpdump -i ens33 -Nnv arp or icmp
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
21:00:24.423670 IP (tos 0x0, ttl 64, id 24789, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.0.10 > 192.168.2.10: ICMP echo request, id 58528, seq 177, length 64
21:00:25.447510 IP (tos 0x0, ttl 64, id 25524, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.0.10 > 192.168.2.10: ICMP echo request, id 58528, seq 178, length 64
21:00:26.472494 IP (tos 0x0, ttl 64, id 26075, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.0.10 > 192.168.2.10: ICMP echo request, id 58528, seq 179, length 64
^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel

通过上述实验我们验证了只要一个网卡上配置的多个ip不是一个网段的,那么都是Primary IP对一个特定的网络掩码(例如网络掩码为/24),只能有一个Primary地址,如果有多个IP掩码一样,后边的实际上不会起作用,例如上面k8s-node-1节点:192.168.2.10这个IP

参考链接:https://blog.csdn.net/dog250/article/details/5303542
参考链接:http://blog.chinaunix.net/uid-1838361-id-66436.html
参考链接:https://blog.csdn.net/xiewen99/article/details/54729112?utm_source=itdadao&utm_medium=referral

你可能感兴趣的:(Kubernetes,linux,网络,运维)