使用ip-masq-agent灵活的控制容器服务Kubernetes集群的SNAT规则
在容器服务的集群中,默认情况下的flannel会对POD访问到非POD的网段做SNAT,以确保POD到集群外部的资源访问,但在某些情况下,比如在容器服务的VPC集群中,POD到集群外部的资源是直接可以访问的,这时我们就可以自己定义节点上的SNAT规则,而达到直接用容器IP访问VPC内其他服务。
安装配置ip-masq-agent组件
我们使用kubernetes 官方项目中的 ip-masq-agent 组件来实现对某些网段不做SNAT的需求,部署方式如下:
curl -L -O http://acs-public.oss-cn-hangzhou.aliyuncs.com/kubernetes/network/ip-masq-agent.yaml # 下载ip-masq-agent的配置文件
vim ip-masq-agent.yaml # 修改其中的nonMasqueradeCIDRs的配置增加或者删除不需要做SNAT的网段,并保存
kubectl apply -f ip-masq-agent.yaml # 使配置生效
然后我们使用如下命令判断ip-masq-agent
都已正常运行:
# kubectl get pod -n kube-system -o wide | grep ip-masq-agent
ip-masq-agent-557qt 1/1 Running 0 30m
ip-masq-agent-dtzds 1/1 Running 0 30m
ip-masq-agent-f6kb6 1/1 Running 0 30m
ip-masq-agent-qmkgl 1/1 Running 0 30m
ip-masq-agent-rtkv8 1/1 Running 0 30m
关闭掉既有的SNAT规则
在配置好ip-masq-agent组件后,还是没有起到作用的,因为默认情况下容器服务使用flannel
的网络插件,我们下面也将说明如何配置关闭掉flannel
的SNAT
的功能:
-
1. 修改CNI的配置:
kubectl edit configmap kube-flannel-cfg -n kube-system
打开修改编辑器后,修改其中的cni-config.json的内容,在其中添加两处"ipMasq: false"的配置,修改如下:
cni-conf.json: | { "name": "cb0", "type": "flannel", "ipMasq": false, "delegate": { "ipMasq": false, "isDefaultGateway": true } }
然后保存修改退出编辑器。
-
2. 修改flannel daemonset的配置:
# kubectl edit ds kube-flannel-ds -n kube-system
打开修改编辑器后,修改flannel daemonset中kube-flannel容器的配置中的command,删除掉其中的
--ip-masq
,然后保存,修改后如下:containers: - command: - /opt/bin/flanneld - --kube-subnet-mgr
然后保存修改退出编辑器。
-
3. 使修改生效:
因为kubernetes的daemonset配置后不会自动重新创建,需要手动重新创建flannel的pod,通过
kubectl
手动删除掉每个节点上的flannel-ds
的pod使其重新创建:# kubectl get pod -o wide -n kube-system | grep kube-flannel-ds kube-flannel-ds-5tbjt 2/2 Running 4 6d 192.168.193.159 cn-hangzhou.i-bp1e5terjg0bgppqy6j3 kube-flannel-ds-6mgjm 2/2 Running 13 6d 192.168.193.156 cn-hangzhou.i-bp1im9citpwp20zebrcr kube-flannel-ds-df9l9 2/2 Running 9 6d 192.168.193.155 cn-hangzhou.i-bp1j1j7011icxiaz0miu kube-flannel-ds-qdjhz 2/2 Running 6 6d 192.168.193.158 cn-hangzhou.i-bp1e5terjg0bgppqy6j4 kube-flannel-ds-xdkpv 2/2 Running 20 6d 192.168.193.157 cn-hangzhou.i-bp1d7nsqol0apr1thvb7 # kubectl get pod -o wide -n kube-system | grep kube-flannel-ds | awk '{print $1}' |xargs kubectl delete -n kube-system pod pod "kube-flannel-ds-5tbjt" deleted pod "kube-flannel-ds-6mgjm" deleted pod "kube-flannel-ds-df9l9" deleted pod "kube-flannel-ds-qdjhz" deleted pod "kube-flannel-ds-xdkpv" deleted # kubectl get pod -o wide -n kube-system | grep kube-flannel-ds # 等待kube-flannel-ds重建完成 kubectl get pod -o wide -n kube-system | grep kube-flannel-ds kube-flannel-ds-c2pvx 2/2 Running 0 40s 192.168.193.156 cn-hangzhou.i-bp1im9citpwp20zebrcr kube-flannel-ds-htkmt 2/2 Running 0 30s 192.168.193.157 cn-hangzhou.i-bp1d7nsqol0apr1thvb7 kube-flannel-ds-k6pfq 2/2 Running 0 20s 192.168.193.155 cn-hangzhou.i-bp1j1j7011icxiaz0miu kube-flannel-ds-p6tzx 2/2 Running 0 36s 192.168.193.158 cn-hangzhou.i-bp1e5terjg0bgppqy6j4 kube-flannel-ds-sz5zg 2/2 Running 0 8s 192.168.193.159 cn-hangzhou.i-bp1e5terjg0bgppqy6j3
这样flannel就被配置为了不会创建SNAT的规则了。
-
4. 到每个节点上清理之前flannel创建的SNAT的规则:
# iptables -t nat --line-numbers -vnL POSTROUTING # 查看flannel创建的SNAT规则 Chain POSTROUTING (policy ACCEPT 4 packets, 240 bytes) num pkts bytes target prot opt in out source destination 1 14M 814M KUBE-POSTROUTING all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes postrouting rules */ 2 0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 3 5468K 328M RETURN all -- * * 172.16.0.0/16 172.16.0.0/16 4 209 12540 MASQUERADE all -- * * 172.16.0.0/16 !224.0.0.0/4 5 0 0 RETURN all -- * * !172.16.0.0/16 172.16.2.0/24 6 4364K 262M MASQUERADE all -- * * !172.16.0.0/16 172.16.0.0/16 7 481 29926 IP-MASQ-AGENT all -- * * 0.0.0.0/0 0.0.0.0/0 /* ip-masq-agent: ensure nat POSTROUTING directs all non-LOCAL destination traffic to our custom IP-MASQ-AGENT chain */ ADDRTYPE match dst-type !LOCAL
在上面这个命令中可以看到我们部署的
ip-masq-agent
的规则已经加到最后了,然后我们需要移除掉flannel
添加的集群网段的4条规则,我们这个集群中的集群POD网段是172.16.0.0/16
,这个需要根据您的集群选择的网段进行判断,所以我们这个集群中的flannel
添加的规则是序号3~6这4条。在机器重启时会重新生成iptables,我们可以重启下需要生效的节点,就会清理掉之前的iptables了,如果不希望影响运行中的服务,也可以通过iptables命令手动删除掉这4条多余的iptables规则:
# iptables -t nat -D POSTROUTING 6 # iptables -t nat -D POSTROUTING 5 # iptables -t nat -D POSTROUTING 4 # iptables -t nat -D POSTROUTING 3
大工告成,验证配置
通过kubectl run启动一个测试容器,并指定我们修改好的一个节点:
# kubectl run -it --rm --image registry.aliyuncs.com/wangbs/netdia --overrides='{ "apiVersion": "extensions/v1beta1", "spec": { "nodeName": "cn-hangzhou.i-bp1e5terjg0bgppqy6j4"}}' test
/ # ping 192.168.200.253
然后通过抓包查看POD ping的包就不会再做SNAT了:
# tcpdump -i eth0 -nn -vv host 192.168.200.253
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
18:54:54.430700 IP (tos 0x0, ttl 63, id 33571, offset 0, flags [DF], proto ICMP (1), length 84)
172.16.4.11 > 192.168.200.253: ICMP echo request, id 4096, seq 10, length 64
18:54:55.430828 IP (tos 0x0, ttl 63, id 33740, offset 0, flags [DF], proto ICMP (1), length 84)
172.16.4.11 > 192.168.200.253: ICMP echo request, id 4096, seq 11, length 64
18:54:56.430947 IP (tos 0x0, ttl 63, id 33890, offset 0, flags [DF], proto ICMP (1), length 84)
172.16.4.11 > 192.168.200.253: ICMP echo request, id 4096, seq 12, length 64