本文永久链接: https://www.xtplayer.cn/kubernetes/svc/k8s-svc-iptables-flow-process/

Service 介绍

K8S 中 Service 通过使用 labels 直接指向 Pods,这种设计的灵活性极高,因为创建 Pods 的方式有很多,而 Service 不需要关心 Pods 通过哪种方式创建。同时也避免了 Pod 重建后 Pod IP 自动更换导致服务崩溃的问题。下文将对 Service ClusterIP 和 NodePort 这两种类型做详述。

  • ClusterIP:集群内部 IP,用于连接后端 Pod 实例的内部 IP,集群中 Pod 可通过 http://ClusterIP:Port 访问到后端 Pod 的 TargetPort 端口上,能够让集群中的 Pod 通过一个 ServiceName 或者 ClusterIP 达到可用性。

  • NodePort:NodePort 在集群中的主机节点上为 Service 提供一个代理端口,以允许从主机网络上对 Service 进行访问。

Service 之 Iptables 流转过程

在 Rancher UI 上部署工作负载,选择 Service 类型为 NodePort,为了方便用户使用,默认会新建出两种类型的 Service(NodePort+ClusterIP),后端 POD IP 为 10.42.1.24。

登录 POD 所在主机节点,通过 netstat 命令可以看到 kube-proxy 在主机网络上创建了 31967 监听端口,用于接收从主机网络进入的外部流量。

iptables 流转过程 —> NodePort类型

[root@node01 ~]# iptables-save > iptables-dump.txt
[root@node01 ~]# cat iptables-dump.txt
# 通过 PREROUTING 链 reject 到 KUBE-SERVICES 链
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
# KUBE-SERVICES 链都是 ClusterIP 的匹配规则,NodePort 只能匹配最后一条 reject 到 KUBE-NODEPORTS 链
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
# 第一条规则 reject 到 KUBE-MARK-MASQ 链,目的是打标签,为匹配这个标签的数据包进行 SNAT;
# 第二条规则 reject 到 KUBE-SVC-AZNGHPMS24SQXQFB 链
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-test-nodeport:80tcp01" -m tcp --dport 31967 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-test-nodeport:80tcp01" -m tcp --dport 31967 -j KUBE-SVC-AZNGHPMS24SQXQFB
# 流转到 KUBE-MARK-MASQ 链将打上 0x4000/0x4000 的标签
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
# 流转到 KUBE-SVC-AZNGHPMS24SQXQFB 将 reject 到 KUBE-SEP-BBE6YPFJIF2XXMLH
-A KUBE-SVC-AZNGHPMS24SQXQFB -j KUBE-SEP-BBE6YPFJIF2XXMLH
# 第一条规则源 IP 为后端 POD 时 reject 到 KUBE-MARK-MASQ,同上述一样目的是打标签,为匹配这个标签的数据包进行 SNAT;
# 第二条规则 DNAT,将主机节点:31967--->10.42.1.24:80
-A KUBE-SEP-BBE6YPFJIF2XXMLH -s 10.42.1.24/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-BBE6YPFJIF2XXMLH -p tcp -m tcp -j DNAT --to-destination 10.42.1.24:80
# 最后 POSTROUTING 链 reject 到 KUBE-POSTROUTING 链
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
# KUBE-POSTROUTING 链对匹配标签的数据包进行 SNAT
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE

iptables 流转过程 —> ClusterIP类型

# 通过 PREROUTING 链 reject 到 KUBE-SERVICES 链
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
# 第一条规则是源 IP 不在 POD IP 范围段内的 reject 到 KUBE-MARK-MASQ,目的是打标签,为匹配这个标签的数据包进行 SNAT,打标签的 iptables 规则与上述一直,省略;
# 第二条规则是 reject 到 KUBE-SVC-FQ4KKJK52D4C6QCF 链
-A KUBE-SERVICES ! -s 10.42.0.0/16 -d 10.43.250.103/32 -p tcp -m comment --comment "default/nginx-test:80tcp01-nginx-test cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.43.250.103/32 -p tcp -m comment --comment "default/nginx-test:80tcp01-nginx-test cluster IP" -m tcp --dport 80 -j KUBE-SVC-FQ4KKJK52D4C6QCF
# 流转到 KUBE-SVC-FQ4KKJK52D4C6QCF 链将 reject 到 KUBE-SEP-6R4HQWWR3BRXNUXG 链
-A KUBE-SVC-FQ4KKJK52D4C6QCF -j KUBE-SEP-6R4HQWWR3BRXNUXG
# 第一条规则源 IP 为后端 POD 时 reject 到 KUBE-MARK-MASQ,同上述一样目的是打标签,为匹配这个标签的数据包进行 SNAT;
# 第二条规则 DNAT,将 ClusterIP:80--->10.42.1.24:80
-A KUBE-SEP-6R4HQWWR3BRXNUXG -s 10.42.1.24/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-6R4HQWWR3BRXNUXG -p tcp -m tcp -j DNAT --to-destination 10.42.1.24:80
# 最后 POSTROUTING 链 reject 到 KUBE-POSTROUTING 链
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
# KUBE-POSTROUTING 链对匹配标签的数据包进行 SNAT
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE