写点什么

Kubernetes Service Proxy 无秘密

用户头像
绅鱼片
关注
发布于: 刚刚

翻译:Kubernetes Service Proxy

背景

kube-proxy 是负责 k8s 集群内通信规则创建的组建,k8s 官方文档解释


Kubernetes 网络代理在每个节点上运行。网络代理反映了每个节点上 Kubernetes API 中定义的服务,并且可以执行简单的 TCP、UDP 和 SCTP 流转发,或者在一组后端进行 循环 TCP、UDP 和 SCTP 转发。


但是 kube-proxy 本身并不负责流量转发等工作。Kubernetes 支持三种 Service Proxy 模式:iptables、IPVS 和 Userspace。根据服务代理方式分析服务请求报文路径。

Service 和 Pod 信息

$ kubectl get pod -o wideNAME                              READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODEmy-nginx-756f645cd7-gh7sq         1/1     Running   14         15d   192.167.2.231   kube03   <none>my-nginx-756f645cd7-hm7rg         1/1     Running   17         20d   192.167.2.206   kube03   <none>my-nginx-756f645cd7-qfqbp         1/1     Running   16         20d   192.167.1.123   kube02   <none>
$ kubectl get pod -o wideNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTORmy-nginx-cluster ClusterIP 10.103.1.234 <none> 80/TCP 15d run=my-nginxmy-nginx-loadbalancer LoadBalancer 10.96.98.173 172.35.0.200 80:30781/TCP 15d run=my-nginxmy-nginx-nodeport NodePort 10.97.229.148 <none> 80:30915/TCP
复制代码


这里展示了 Kubernetes Service ProxyServicePod 信息。可以从上面的信息看出部署了三个 nginx Pod。并添加了ClusterIP 类型的 my-nginx-clusterNodePort 类型的 nginx-nodeportLoadBalancermy-nginx-loadbalancer

Iptables 模式


iptables 模式下的 KUBE-SERVICES


Chain KUBE-SERVICES (2 references) pkts bytes target     prot opt in     out     source               destination    0     0 KUBE-MARK-MASQ  tcp  --  *      *      !192.167.0.0/16       10.96.98.173         /* default/my-nginx-loadbalancer: cluster IP */ tcp dpt:80    0     0 KUBE-SVC-TNQCJ2KHUMKABQTD  tcp  --  *      *       0.0.0.0/0            10.96.98.173         /* default/my-nginx-loadbalancer: cluster IP */ tcp dpt:80    0     0 KUBE-FW-TNQCJ2KHUMKABQTD  tcp  --  *      *       0.0.0.0/0            172.35.0.200         /* default/my-nginx-loadbalancer: loadbalancer IP */ tcp dpt:80    0     0 KUBE-MARK-MASQ  tcp  --  *      *      !192.167.0.0/16       10.103.1.234         /* default/my-nginx-cluster: cluster IP */ tcp dpt:80    0     0 KUBE-SVC-52FY5WPFTOHXARFK  tcp  --  *      *       0.0.0.0/0            10.103.1.234         /* default/my-nginx-cluster: cluster IP */ tcp dpt:80     0     0 KUBE-MARK-MASQ  tcp  --  *      *      !192.167.0.0/16       10.97.229.148        /* default/my-nginx-nodeport: cluster IP */ tcp dpt:80    0     0 KUBE-SVC-6JXEEPSEELXY3JZG  tcp  --  *      *       0.0.0.0/0            10.97.229.148        /* default/my-nginx-nodeport: cluster IP */ tcp dpt:80    0     0 KUBE-NODEPORTS  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
复制代码


iptables 模式下的 KUBE-NODEPORTS


Chain KUBE-NODEPORTS (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 KUBE-MARK-MASQ  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-loadbalancer: */ tcp dpt:30781    0     0 KUBE-SVC-TNQCJ2KHUMKABQTD  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-loadbalancer: */ tcp dpt:30781    0     0 KUBE-MARK-MASQ  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-nodeport: */ tcp dpt:30915    0     0 KUBE-SVC-6JXEEPSEELXY3JZG  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-nodeport: */ tcp dpt:30915 
复制代码


iptables 模式下的 KUBE-FW-XXX


Chain KUBE-FW-TNQCJ2KHUMKABQTD (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 KUBE-MARK-MASQ  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-loadbalancer: loadbalancer IP */    0     0 KUBE-SVC-TNQCJ2KHUMKABQTD  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-loadbalancer: loadbalancer IP */    0     0 KUBE-MARK-DROP  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-loadbalancer: loadbalancer IP */
复制代码


iptables 模式下的 KUBE-SVC-XXX


Chain KUBE-SVC-TNQCJ2KHUMKABQTD (2 references) pkts bytes target     prot opt in     out     source               destination    0     0 KUBE-SEP-6HM47TA5RTJFOZFJ  all  --  *      *       0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.33332999982    0     0 KUBE-SEP-AHRDCNDYGFSFVA64  all  --  *      *       0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.50000000000    0     0 KUBE-SEP-BK523K4AX5Y34OZL  all  --  *      *       0.0.0.0/0            0.0.0.0/0      
复制代码


iptables 模式下的 KUBE-SEP-XXX


Chain KUBE-SEP-6HM47TA5RTJFOZFJ (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 KUBE-MARK-MASQ  all  --  *      *       192.167.2.231        0.0.0.0/0    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp to:192.167.2.231:80 
复制代码


iptables 模式下的 KUBE-POSTROUTING


Chain KUBE-POSTROUTING (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match0x4000/0x4000 
复制代码


iptables 模式下的 KUBE-MARK-MASQ


Chain KUBE-MARK-MASQ (23 references) pkts bytes target     prot opt in     out     source               destination    0     0 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x4000 
复制代码


iptables 模式下的 KUBE-MARK-DROP


Chain KUBE-MARK-DROP (10 references) pkts bytes target     prot opt in     out     source               destination    0     0 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x8000
复制代码


这里的 Service Proxy 使用是 iptables 模式。这是 Kubernetes 当前使用的默认代理模式。在上方图中展示了 iptables 模式下服务请求包的路径。上方的 bash 是展示了主要 NAT 表的内容。


由于大多数 Pod 传输的请求包是通过 Podveth 传递到主机的网络命名空间,因此请求包通过 PREROUTING 表传递到 KUBE-SERVICES 表。Pod 或者 Host进程 使用 Host 的网络命名空间传输的请求数据包由 OUTPUT 表传递到 KUBE-SERVICES 表。


如果KUBE-SERVICES 表中请求包的目标IP和目标PortClusterIP ServiceIPPort匹配,则请求的包被转发到KUBE-SVC-XXX 表,即ClusterIP ServiceNAT表.


如果 KUBE-SERVICES 表中请求包的目标 IP 是节点自己的 IP,则将请求包转发到 KUBE-NODEPORTS 表。如果 KUBE-NODEPORTS 表中请求报文的目标 PortNodePort ServicePort匹配,则将请求报文传送到 KUBE-SVC-XXX 表,即 NodePort ServiceNAT 表。


如果KUBE-SERVICES 表中请求包的目标 IP和目标 PortLoadBalancer ServiceExternal IPPort匹配,则将请求包转发到KUBE-FW-XXX 表,LoadBalancer ServiceNAT表,然后再将 LoadBalancer Service 传送到 KUBE-SVC-XXX 表,也就是 NAT


KUBE-SVC-XXX 表中,请求包通过iptables的统计功能,在构成ServicePod之间起到随机均匀负载均衡的作用。在 KUBE-SVC-TNQCJ2KHUMKABQTD 中,由于Service由三个pod组成,可以看出请求包设置为随机均衡负载均衡,使用三个KUBE-SEP-XXX表。在 KUBE-SEP-XXX 表中,请求包使用 PodIPService 中设置的 Port 进行 DNAT。由PodIP发出的DNAT请求包通过CNI Plugin构建的容器网络传递给该Pod


由于传递给service的请求包是通过iptablesDNAT传递给Pod的,所以Pod发出的响应包的Src IP应该SNATService IP,而不是Pod IPiptables 中未指定 SerivceSNAT 规则。但是,iptables根据Linux KernelConntrack(连接跟踪)的TCP 连接信息对从 Service Pod 收到的响应数据包进行 SNAT

Source IP

Service请求包的Src IP将被留存,或通过Masquerade作为HostIP进行SNATKUBE-MARK-MASQ 是一个表,将使用 Masquerade 对请求包进行标记。MarkingPacketKUBE-POSTROUTING 表中成为MasqueradeSrc IP作为HostIP成为SNAT。在iptables 表中,你会发现KUBE-MARK-MASQ 表会检测出被Masquerade标记过的包。



根据 NodePort、LoadBalancer Service 的 externalTrafficPolicy 的数据包路径图


图中左侧为externalTrafficPolicy值为Cluster,执行 MasqueradeLoadBalancer ServiceNodePortexternalTrafficPolicyCluster。如果externalTrafficPolicy值设置为Cluster,则请求包的Src IP通过MasqueradeSNATHostIP。在 KUBE-NODEPORTS 表中,可以通过 KUBE-MARK-MASQ 表检查所有以 NodePortLoadBalancer Service Port作为 Dest Port 的数据包。


图右侧是通过将externalTrafficPolicy设置为Local,不执行Masquerade如果将 externalTrafficPolicy 值设置为 Local,则 KUBE-MARK-MASQ 表中相关规则将不会出现在 KUBE-NODEPORTS 表中,所以就不会执行到 Masquerade。请求数据包的 Src IP 不会被修改。另外,请求包在宿主机中不会被负载均衡,而是将请求包发送到的 Host 中的目标pod。如果请求数据包被发送到主机不存在目标 pod,那么请求数据包将被丢弃。


ExternalTrafficPolicy Local主要用于LoadBalancer Service。因为由 Cloud Provider 的负载均衡器执行负载均衡,所以主机不需要负载均衡,所以可以保留请求包的Src IP。如果externalTrafficPolicy值为Local,云服务提供商的负载均衡器会对目标 Pod 执行健康检查,如果健康检查失败或者目标 Pod 不存在,那么发送到主机上的数据包将会被丢弃删除。



Pod中向自己所属的ServiceIP发送请求数据包,在请求数据包返回时也需要 Masquerade。图中左边就标识这种情况。请求数据包被 DNAT, 数据包的Src IPDest IP都是Pod本身的IP。因此,Pod返回响应数据包时,响应数据包不通过HostNAT表,因此不会执行SNAT,直接在 Pod 中处理。


如果使用 Masquerade,则可以通过将返回 Pod 的请求包强制传递给 Host 来执行 SNAT。这种通过故意绕过数据包来接收数据包的方法称为Hairpinning。图中的右侧显示了使用Masqurade应用Hairpinning的情况。如果KUBE-SEP-XXX表中请求数据包的 Src IP 与 DNAT 的 IP 相同,即Pod发送到Service的数据包由自己接收时,则请求的数据包经过KUBE-MARK-MASQ 表是被 Marking,在KUBE-POSTROUTING 表中被Masquerade因为Pod接收到的数据包的Src IP被设置为HostIP,因此Pod的响应被发送到HostNAT 表,然后进行SNATDNAT传递给Pod

用户空间

Userspace Mode 下的服务请求报文路径图:



用户空间模式下的 KUBE-PORTALS-CONTAINER:


Chain KUBE-PORTALS-CONTAINER (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            10.96.98.173         /* default/my-nginx-loadbalancer: */ tcp dpt:80 redir ports 38023    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            172.35.0.200         /* default/my-nginx-loadbalancer: */ tcp dpt:80 redir ports 38023    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            10.103.1.234         /* default/my-nginx-cluster: */ tcp dpt:80 redir ports 36451    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            10.97.229.148        /* default/my-nginx-nodeport: */ tcp dpt:80 redir ports 44257
复制代码


用户空间模式下的 KUBE-NODEPORT-CONTAINER:


Chain KUBE-NODEPORT-CONTAINER (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-loadbalancer: */ tcp dpt:30781 redir ports 38023    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-nodeport: */ tcp dpt:30915 redir ports 44257
复制代码


用户空间模式下的 KUBE-PORTALS-HOST:


Chain KUBE-PORTALS-HOST (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            10.96.98.173         /* default/my-nginx-loadbalancer: */ tcp dpt:80 to:172.35.0.100:38023    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            172.35.0.200         /* default/my-nginx-loadbalancer: */ tcp dpt:80 to:172.35.0.100:38023    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            10.103.1.234         /* default/my-nginx-cluster: */ tcp dpt:80 to:172.35.0.100:46635    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            10.97.229.148        /* default/my-nginx-nodeport: */ tcp dpt:80 to:172.35.0.100:32847
复制代码


用户空间模式下的 KUBE-NODEPORT-HOST:


Chain KUBE-NODEPORT-HOST (1 references) pkts bytes target     prot opt in     out     source               destination    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-loadbalancer: */ tcp dpt:30781 to:172.35.0.100:38023    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/my-nginx-nodeport: */ tcp dpt:30915 to:172.35.0.100:44257
复制代码


Service Proxy 的 iptables 模式是一种运行在用户空间的 kube-proxy 扮演 Service Proxy 角色的模式。这是 Kubernetes 提供的第一个代理模式。目前使用的不是很好,因为与 iptables 模式相比性能较差。上图中展示了 Userspace 模式下 Service 请求包的路径。


由于大多数 Pod 传输的请求包是通过 Podveth 传递到 HostNetwork 命名空间,因此请求包通过 PREROUTING 表传递到KUBE-PORTALS-CONTAINER 表。如果 KUBE-PORTALS-CONTAINER 标准中请求包的 目标 IP 和目标 PortClusterIP 服务的 IPPort 匹配,则请求包被重定向到kube-proxy 。如果请求数据包的目标 IP是节点自己的IP,则将数据包投递到KUBE-NODEPORT-CONTAINER表。如果 KUBE-NODEPORT-CONTAINER 表中请求包的 目标 PortNodePort Service 的端口匹配,则请求包被重定向到 kube-proxy。如果请求包的目标 IP和目标 PortLoadBalancer ServiceExternal IPPort匹配,请求包也会被重定向到 kube-proxy。


PodHost 进程使用 HostNetwork Namespace 传输的请求数据包由 OUTPUT 表 传递到 KUBE-PORTALS-HOST 表。KUBE-PORTALS-HOSTKUBE-NODEPORT-HOST 表中的后续请求包处理类似于 KUBE-PORTALS-CONTAINERKUBE-NODEPORT-CONTAINER 表中的请求包处理。不同之处在于,DNAT 是在不重定向请求包的情况下执行的。


通过 RedirectDNAT 发送到 Service 的所有请求数据包都被传递到 kube-proxykube-proxy 收到的请求数据包的每个目标 Port 映射一个服务。因此,kube-proxy 可以通过重定向和 NAT 请求数据包的 目标 Port 确定请求数据包应该传递到哪个服务。kube-proxy 通过将接收到的请求数据包均匀地负载均衡到属于请求数据包要传输到的服务的多个 Pod 来重新传输接收到的请求数据包。


由于 kube-proxy 运行在主机的 Network Namespace 中,因此 kube-proxy 发送的请求包也会经过 Service NAT 表。但是由于kube-proxy发送的请求包的目标 IPPodIP,所以请求包不会被Service NAT 表改变,而是通过CNI Plugin搭建的Container Network传递给Pod


参考


用户头像

绅鱼片

关注

还未添加个人签名 2018.11.05 加入

还未添加个人简介

评论

发布
暂无评论
Kubernetes Service Proxy 无秘密