Bootstrap

Kubernetes Service 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 wide
NAME                              READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE
my-nginx-756f645cd7-gh7sq         1/1     Running   14         15d   192.167.2.231   kube03   
my-nginx-756f645cd7-hm7rg         1/1     Running   17         20d   192.167.2.206   kube03   
my-nginx-756f645cd7-qfqbp         1/1     Running   16         20d   192.167.1.123   kube02   

$ kubectl get pod -o wide
NAME                    TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                           AGE     SELECTOR
my-nginx-cluster        ClusterIP      10.103.1.234              80/TCP                            15d     run=my-nginx
my-nginx-loadbalancer   LoadBalancer   10.96.98.173     172.35.0.200   80:30781/TCP                      15d    run=my-nginx
my-nginx-nodeport       NodePort       10.97.229.148             80:30915/TCP 

这里展示了 的 和 信息。可以从上面的信息看出部署了三个 Pod。并添加了 类型的 、 类型的 和 的 。

Iptables 模式

模式下的 :

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

模式下的 :

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 

模式下的 :

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 */

模式下的 :

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      

模式下的 :

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 

模式下的 :

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 match
0x4000/0x4000 

模式下的 :

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 

模式下的 :

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

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

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

如果 表中请求包的目标和目标与的和匹配,则请求的包被转发到 表,即的表.

如果 表中请求包的目标 是节点自己的 ,则将请求包转发到 表。如果 表中请求报文的目标 与 的 匹配,则将请求报文传送到 表,即 的 表。

如果 表中请求包的目标 和目标 与 的和匹配,则将请求包转发到 表,的表,然后再将 传送到 表,也就是 表

在 表中,请求包通过的统计功能,在构成的之间起到随机均匀负载均衡的作用。在 中,由于由三个组成,可以看出请求包设置为随机均衡负载均衡,使用三个表。在 表中,请求包使用 的 和 中设置的 进行 。由的发出的请求包通过构建的容器网络传递给该。

由于传递给的请求包是通过的传递给的,所以发出的响应包的应该到,而不是 。 中未指定 的 规则。但是,根据 的(连接跟踪)的 连接信息对从 收到的响应数据包进行 。

Source IP

请求包的将被留存,或通过作为的进行。 是一个表,将使用 对请求包进行标记。的在 表中成为,作为的成为。在 表中,你会发现 表会检测出被标记过的包。

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

图中左侧为值为,执行 的 和 的 。如果值设置为,则请求包的通过 被 到的。在 表中,可以通过 表检查所有以 和 作为 的数据包。

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

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

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

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

用户空间

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 请求包的路径。

由于大多数 传输的请求包是通过 的 传递到 的 命名空间,因此请求包通过 PREROUTING 表传递到 表。如果 标准中请求包的 目标 和目标 与 服务的 和 匹配,则请求包被重定向到 。如果请求数据包的目标 是节点自己的,则将数据包投递到表。如果 表中请求包的 目标 与 的端口匹配,则请求包被重定向到 。如果请求包的目标 和目标 与的和匹配,请求包也会被重定向到kube-proxy。

或 进程使用 的 传输的请求数据包由 表 传递到 表。 和 表中的后续请求包处理类似于 和 表中的请求包处理。不同之处在于,DNAT是在不重定向请求包的情况下执行的。

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

由于 运行在主机的 中,因此 发送的请求包也会经过 表。但是由于发送的请求包的目标 是的,所以请求包不会被 表改变,而是通过搭建的传递给。

参考