Iptables代理模式下的Service

service的几种类型

  • clusterIP:只能在集群的节点和pod中访问,解决的就是集群内应用间的相互访问的问题;
  • nodeport:通过节点的地址和端口把pod暴露到集群外,让集群外的应用能访问集群内的应用,设置服务类型为nodeport时,是在clusterIP的基础上再给节点开个端口转发(是特定节点还是每一个节点要看externalTrafficPolicy的值,Cluster是每一个节点都开,Local是只在pod运行的节点开),所以nodeport的服务也会有一个clusterIP

iptables代理模式下的ClusterIP

iptables代理模式下的ClusterIP,每个Service在每个节点上(由kube-proxy负责生成)都会生成相应的iptables规则:

  • KUBE-SERVICES:包含所有ClusterIP类型的Service的流量匹配规则,由PREROUTING和OUTPUT两个内置链直接调用;每个Service对象包含两条规则定义,对于所有发往该Service(目标IP为Service_IP且目标端口为Service_Port)的请求报文,前一条用于为那些非源自Pod网络(! -s 10.244.0.0/16)中请求报文借助于KUBE-MARQ-MASK自定义链中的规则打上特有的防火墙标记,后一条负责将所有报文转至专用的以KUBE-SVC为名称前缀的自定义链,后缀是Service信息hash值。

代码块1

# 用户空间的所有pod或进程的出栈报文全都跳转给KUBE-SERVICES,如果目标地址是某个Services之一其必然会被KUBE-SERVICE中规则所匹配。
root@k8s-node01:~# iptables -t nat -S OUTPUT
-P OUTPUT ACCEPT
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES     # 所有出栈流量跳转给KUBE-SERVICES,以下为追踪demoapp-svc的流量,直接进入第16行。
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT -m addrtype --dst-type LOCAL -j CNI-HOSTPORT-DNAT

# 此处针对demoapp-svc进行对整个iptables规则进行理解
root@k8s-master01:~# kubectl get svc demoapp-svc 
NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
demoapp-svc   ClusterIP   10.97.72.1   <none>        80/TCP    3d16h

# 查看该svc的iptables规则
root@k8s-node01:~# iptables -t nat -S KUBE-SERVICES | grep "demoapp-svc"
# 如果源地址非10.244.0.0/16的网络,目标地址为10.97.72.1/32(此为service的clusterIP),协议为tcp,目标端口为80,做跳转,将其转给KUBE-MARK-MASQ。进入代码块2。
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.97.72.1/32 -p tcp -m comment --comment "default/demoapp-svc:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
# 如果上一条没有匹配到,进入下一条规则
# 目标地址为10.97.72.1/32(此为service的clusterIP),协议为tcp,目标端口为80,将其转给KUBE-SVC-ZAGXFVDPX7HH4UMW,进入代码块3
-A KUBE-SERVICES -d 10.97.72.1/32 -p tcp -m comment --comment "default/demoapp-svc:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-ZAGXFVDPX7HH4UMW
  • KUBE-MARK-MASQ:专用目的自定义链,所有转至该自定义链的报文都将被置入特有的防火墙标记(0x4000)以便于将特定的类型的报文定义为单独的分类,目的在将该类报文转发到目标端点之前由POSTROUTING规则链进行源地址转换。

代码块2

# 所有非pod网络的流量都会被跳转到此自定义链。
root@k8s-node01:~# iptables -t nat -S KUBE-MARK-MASQ
-N KUBE-MARK-MASQ
# 此规则会给非pod网络的出栈报文打一个0x4000/0x4000标记符号。
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000

# 由于此自定义链,没有后续的操作,其流量将会被return,跳回给调用它的链,也就是KUBE-SERVICES链。
# 而后被代码块1中19行规则所处理
  • KUBE-SVC-<HASH>:定义一个服务的流量调度规则,它通过随机调度算法(RANDOM)将请求分发给该Service的所有后端端点,每个后端端点定义在以KUBE-SEP为前缀名称的自定链上,后缀是端点信息的hash值。

代码块3

# 查看KUBE-SVC-ZAGXFVDPX7HH4UMW链的规则。
root@k8s-node01:~# iptables -t nat -S KUBE-SVC-ZAGXFVDPX7HH4UMW
-N KUBE-SVC-ZAGXFVDPX7HH4UMW
# 6-8行3条自定义链代表了该Service背后所关联的4个pod,可在第11行查看。
# statistic模块为请求报文数量统计模块,其支持随机调度算法的调度模块--mode random,以下查看其中KUBE-SEP-W5CYPK4IZKSNY6AN链即可,进入代码块4
-A KUBE-SVC-ZAGXFVDPX7HH4UMW -m comment --comment "default/demoapp-svc:http" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-W5CYPK4IZKSNY6AN
-A KUBE-SVC-ZAGXFVDPX7HH4UMW -m comment --comment "default/demoapp-svc:http" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-SNI6ZIEBIF6J7SOT
-A KUBE-SVC-ZAGXFVDPX7HH4UMW -m comment --comment "default/demoapp-svc:http" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-SLUESE2KECGDKA4X
-A KUBE-SVC-ZAGXFVDPX7HH4UMW -m comment --comment "default/demoapp-svc:http" -j KUBE-SEP-5NZKGQCCADX66CX7
# 以上0.25,为100%/4个pod所得的流量,0.3为去除0.25的pod后的所有流量除以剩下的3个pod所得其表示为100%/3,0.5为去除2个pod的所有流量除以剩下的2个pod所得其表示为100%/2,最后一个没有标识的为100%
# 查看该svc的ep
root@k8s-master01:~# kubectl describe ep demoapp
Name:         demoapp
Namespace:    default
Labels:       app=demoapp
Annotations:  <none>
Subsets:
  Addresses:          10.244.1.4,10.244.2.3,10.244.3.2,172.16.11.81
  NotReadyAddresses:  <none>
  Ports:
    Name  Port  Protocol
    ----  ----  --------
    80    80    TCP

Events:  <none>
  • KUBE-SEP-<HASH>:定义一个端点相关的流量处理规则,它通常包含两条规则,前一条用于为那些源自该端点自身(-s ep_ip)的请求流量调用自定义链KUBE-MARQ-MASK打上特有的防火墙标记,后一条负责将发往该端点的所有流量进行目标IP地址和端口转换,新目标为该端点的IP和端口(-j DNAT –to-destination ep_ip:ep_port)。

代码块4

root@k8s-node01:~# iptables -t nat -S KUBE-SEP-W5CYPK4IZKSNY6AN
-N KUBE-SEP-W5CYPK4IZKSNY6AN
# 源ip为10.244.1.4也就是当前pod的流量发送给KUBE-MARK-MASQ进行打标。进入代码块2打标,打完标后回到此规则链,进入下一条规则。
-A KUBE-SEP-W5CYPK4IZKSNY6AN -s 10.244.1.4/32 -m comment --comment "default/demoapp-svc:http" -j KUBE-MARK-MASQ
# 将所有流量做目标地址转换,目标地址为10.244.1.4,端口为80
-A KUBE-SEP-W5CYPK4IZKSNY6AN -p tcp -m comment --comment "default/demoapp-svc:http" -m tcp -j DNAT --to-destination 10.244.1.4:80
# 报文被处理完毕后将发送给KUBE-POSTROUTING,进入代码块5
  • KUBE-POSTROUTING:专用的自定义链,由内置链POSTROUTING无条件调用,负责将拥有特有防火墙标记0x4000的请求报文进行源地址转换(Target为实现地址伪装的MASQUERADE),新的源地址为报文离开协议栈时流经接口的主IP(primary ip)地址。

代码块5

# 查看POSTROUTING内的规则
root@k8s-node01:~# iptables -t nat -S POSTROUTING
-P POSTROUTING ACCEPT
-A POSTROUTING -m comment --comment "CNI portfwd requiring masquerade" -j CNI-HOSTPORT-MASQ
# iptables规则会将pod的流量跳转给KUBE-POSTROUTING。
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 10.244.0.0/16 -d 10.244.0.0/16 -j RETURN
-A POSTROUTING -s 10.244.0.0/16 ! -d 224.0.0.0/4 -j MASQUERADE --random-fully
-A POSTROUTING ! -s 10.244.0.0/16 -d 10.244.1.0/24 -j RETURN
-A POSTROUTING ! -s 10.244.0.0/16 -d 10.244.0.0/16 -j MASQUERADE --random-fully

# 查看KUBE-POSTROUTING链内容
root@k8s-node01:~# iptables -t nat -S KUBE-POSTROUTING
-N KUBE-POSTROUTING
# 对所有不具有0x4000标记的都返回到POSTROUTING
-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
# 对于所有存在0x4000标记的都置为0,然后进入下一条规则
-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
# 对某些流量(源地址!10.244.0.0/16地址段的流量,源地址为pod自身的流量)进行动态SNAT。为了具有通用性使用MASQUERADE。
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully
# 此处KUBE-POSTROUTING做源地址转换是为了以下2个目的:
# 1.确保非k8s集群内的终端访问集群内的service中跨节点的某个端点时,流量能正确的返回过来所以需要使用SNAT。否则Service的后端的端点将无法得知报文来自哪里。
# 2.源地址为自身的流量,若不进行SNAT直接发回给自身这种流量是不会被处理的,所以也需要进行SNAT。
##########################################################################################################################
# k8s在部署时,允许我们向APIServer的控制器平面的进程传递参数--masquerade-all,用来不区分以上两种情况,所有的流量都做地址伪装。
# 额外加一层地址伪装将导致规则更复杂,所以其性能更低。不建议开启--masquerade-all。

iptable代理模式下NodePort

NodePort的流量的来源都为集群外部,所以其是由PREROUTING链调用的KUBE-SERVICE

# 查看PREROUTING链
root@k8s-node01:~# iptables -t nat -S PREROUTING
-P PREROUTING ACCEPT
# 此处可以看到所有集群外部的流量全部都被跳转给KUBE-SERVICES,需要注意的是集群外访问的只可能是节点IP不可能为Service IP所以ClusterIP的做法在此不适用。
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j CNI-HOSTPORT-DNAT

# 追踪一条NodePort的Service.
root@k8s-master01:~# iptables -t nat -S KUBE-SERVICES | grep "nodeport"
# 群外访问的只可能是节点IP不可能为Service IP所以以下2条规则不会被匹配搭到。其会被KUBE-SERVICE中的最后一条匹配
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.97.56.1/32 -p tcp -m comment --comment "default/demoapp-service-nodeport:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.97.56.1/32 -p tcp -m comment --comment "default/demoapp-service-nodeport:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-YDLXCW2IFVSJIZMR
# 此条规则用来做addrtype地址类型判断,判断目标地址类型是否为LOCAL本节点所拥有的IP,如果不是则送往forward链转发,是则调转到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

# 追踪KUBE-NODEPORTS链
# 每个Service可以在KUBE-NODEPORTS链上生成2条规则。
root@k8s-master01:~# iptables -t nat -S KUBE-NODEPORTS
-N KUBE-NODEPORTS
# 目标端口为31156的跳转给KUBE-MARK-MASQ进行打标,打标完毕后进入下一条规则
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/demoapp:80" -m tcp --dport 31156 -j KUBE-MARK-MASQ
# 目标端口为31156的跳转给KUBE-SVC-AZ2VLIOX5VGKTCYB链,继续追踪KUBE-SVC-AZ2VLIOX5VGKTCYB链
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/demoapp:80" -m tcp --dport 31156 -j KUBE-SVC-AZ2VLIOX5VGKTCYB

# 查看KUBE-SVC-AZ2VLIOX5VGKTCYB链内容
root@k8s-master01:~# iptables -t nat -S KUBE-SVC-AZ2VLIOX5VGKTCYB
-N KUBE-SVC-AZ2VLIOX5VGKTCYB
# 可以看到该链内的规则是将流量通过算法,负载均衡给后端的KUBE-SEP链。继续追踪KUBE-SEP-A5X3QL25Q5UGSWY7
-A KUBE-SVC-AZ2VLIOX5VGKTCYB -m comment --comment "default/demoapp:80" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-A5X3QL25Q5UGSWY7
-A KUBE-SVC-AZ2VLIOX5VGKTCYB -m comment --comment "default/demoapp:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-WSKJMSX5XPODQ46G
-A KUBE-SVC-AZ2VLIOX5VGKTCYB -m comment --comment "default/demoapp:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-ZCPJGBG3WJTOIVRD
-A KUBE-SVC-AZ2VLIOX5VGKTCYB -m comment --comment "default/demoapp:80" -j KUBE-SEP-EKC65ZBALV67XSBV

# 查看KUBE-SEP-A5X3QL25Q5UGSWY7链内容
root@k8s-master01:~# iptables -t nat -S KUBE-SEP-A5X3QL25Q5UGSWY7
-N KUBE-SEP-A5X3QL25Q5UGSWY7
# 源地址为10.244.1.4的,跳转到KUBE-MARK-MASQ进行打标。此条规则类似于pod自身访问了自身的Service服务。
-A KUBE-SEP-A5X3QL25Q5UGSWY7 -s 10.244.1.4/32 -m comment --comment "default/demoapp:80" -j KUBE-MARK-MASQ
# 对所有的流量做目标地址转换,转换后地址为10.244.1.4:80,而后发往POSTROUTING链。
-A KUBE-SEP-A5X3QL25Q5UGSWY7 -p tcp -m comment --comment "default/demoapp:80" -m tcp -j DNAT --to-destination 10.244.1.4:80

# 而后的流量转发与ClusterIP相同。


原文始发于微信公众号(TechOps之窗):Iptables代理模式下的Service

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/286285.html

(0)
码上实战的头像码上实战

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!