【kubernetes系列】kubernetes之kube-proxy的工作模式

概述

从kubernetes最早开始,kube-proxy到现在总共支持三种模式,在v1.8之前我们使用的是iptables 以及 userspace两种模式,iptables 模式从 v1.2 版本开始引入并作为kube-proxy 默认的操作模式。在kubernetes 1.8之后引入了ipvs模式,并且在v1.11中正式使用,其中iptables和ipvs都是内核态也就是基于netfilter,只有userspace模式是用户态。下面详细介绍下各个模式:

userspace

在k8s v1.2后就已经被淘汰了,该模式下kube-proxy会为每一个Service创建一个监听端口。发向Cluster IP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB算法选择一个提供服务的Pod并和其建立连接,以将请求转发到Pod上。该模式下,Kube-proxy充当了一个四层Load balancer的角色,proxy会为每个svc随机监听一个端口,并增加一个iptables规则,从客户端到 ClusterIP:Port 的报文都会被重定向到 proxy port,kube-proxy 收到报文后,通过 Round Robin (轮询) 或者 Session Affinity分发给对应的 Pod。然而由于kube-proxy运行在userspace中,在进行转发处理时会增加两次内核和用户空间之间的数据拷贝,效率较另外两种模式低一些。如下图为userspace的工作流程。
在这里插入图片描述

iptables

iptables模式是从kubernetes1.2开始引入并在v1.12之前使用的默认模式。该模式避免了增加内核和用户空间的数据拷贝操作,提高了转发效率。在这种模式下proxy监控kubernetes对svc和ep对象的改变,直接为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。并且这种模式使用iptables来做用户态的入口,而真正提供服务的是内核的Netilter,Netfilter采用模块化设计,具有良好的可扩充性。其重要工具模块IPTables从用户态的iptables连接到内核态的Netfilter的架构中,Netfilter与IP协议栈是无缝契合的,并允许使用者对数据报进行过滤、地址转换、处理等操作。该模式下iptables由kube-proxy动态的管理,kube-proxy不再负责转发,只负责创建iptables规则。数据包的走向完全由iptables规则决定,这样的过程不存在内核态到用户态的切换,效率明显会高很多。流量的转发都是在内核态进行的,所以性能更高更加可靠。

但是随着service的增加,iptables规则会不断增加,导致内核十分繁忙。并且iptables修改了规则后必须得全部刷新才可以生效。如下图为iptables的工作流程。

在这里插入图片描述

ipvs

参考文档https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md#prerequisit
IPVS(IP Virtual Server,IP虚拟服务器)实现了传输层的负载平衡,通常称为4 LAN(四层局域网)交换,是Linux内核的一部分。IPVS在主机上运行,在真实服务器集群前面充当负载平衡器。IPVS可以将基于 TCP 和 UDP 的服务请求定向到真实服务器上。

kubernetes从1.8开始增加了IPVS支持,它也是基于netfilter实现的,但定位不同:iptables是为防火墙设计的,IPVS则专门用于高性能,IPVS相对于iptables来说效率会更加高,使用ipvs模式需要在允许proxy的节点上安装ipvsadm,ipset工具包加载ipvs的内核模块。
负载均衡,并使用高效的数据结构Hash表,允许几乎无限的规模扩张。一句话说明:ipvs使用ipset存储iptables规则,在查找时类似hash表查找,时间复杂度为O(1),而iptables时间复杂度则为O(n),使得ipvs可以轻松处理每秒 10 万次以上的转发请求。

当proxy启动的时候,proxy将验证节点上是否安装了ipvs模块。如果未安装的话将回退到iptables模式。在Kubernetes 1.12成为kube-proxy的默认代理模式。对比iptables模式在大规模Kubernetes集群有更好的扩展性和性能,支持更加复杂的负载均衡算法(如:最小负载、最少连接、加权等),支持Server的健康检查和连接重试等功能。ipvs依赖于iptables,由于ipvs 无法提供包过滤、SNAT、masquared(伪装)等功能。因此在某些场景(如Nodeport的实现)下还是要与iptables搭配使用,ipvs 将使用ipset来存储需要DROP或masquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的。假设要禁止上万个IP访问我们的服务器,则用iptables的话,就需要一条一条地添加规则,会在iptables中生成大量的规则;但是使用ipset的话,只需要将相关的IP地址(网段)加入到ipset集合中即可,这样只需要设置少量的iptables规则即可实现目标。
在这里插入图片描述

这种模式,Kube-Proxy 会监视 Kubernetes Service 对象 和 Endpoints,调用 Netlink 接口以相应地创建 IPVS 规则并定期与 Kubernetes Service 对象 和 Endpoints 对象同步 IPVS 规则,以确保 IPVS 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod上。

那么 ipvs 模式和 iptables 模式之间有哪些差异呢?

  • ipvs 为大型集群提供了更好的可扩展性和性能
  • ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
  • ipvs 支持服务器健康检查和连接重试等功能
  • 可以动态修改ipset集合。即使iptables的规则正在使用这个集合。

kube-proxy使用ipvs模式

在每台机器上安装依赖包:

[root@k8s-m1 ~]# yum install ipvsadm ipset sysstat conntrack libseccomp -y

##所有机器选择需要开机加载的内核模块,以下是 ipvs 模式需要加载的模块并设置开机自动加载
[root@k8s-m1 ~]#  > /etc/modules-load.d/ipvs.conf   #先清空
module=(
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
br_netfilter
  )  
for kernel_module in ${module[@]};do
    /sbin/modinfo -F filename $kernel_module |& grep -qv ERROR && echo $kernel_module >> /etc/modules-load.d/ipvs.conf 
done
systemctl enable --now systemd-modules-load.service

上面用systemctl enable命令如果报错可以用systemctl status -l systemd-modules-load.service看看哪个内核模块加载不了,在/etc/modules-load.d/ipvs.conf里注释掉它再enable试试

所有机器需要设定/etc/sysctl.d/k8s.conf的系统参数。

[root@k8s-m1 ~]# cat > /etc/sysctl.d/k8s.conf  <<EOF 
# https://github.com/moby/moby/issues/31208 
# ipvsadm -l --timout
# 修复ipvs模式下长连接timeout问题 小于900即可
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.ip_forward = 1
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
# 要求iptables不对bridge的数据进行处理
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-arptables = 1
net.netfilter.nf_conntrack_max = 2310720
fs.inotify.max_user_watches=89100
fs.may_detach_mounts = 1
fs.file-max = 52706963
fs.nr_open = 52706963
vm.swappiness = 0
vm.overcommit_memory=1
vm.panic_on_oom=0
EOF

[root@k8s-m1 ~]# sysctl --system

修改Kube-proxy配置文件将mode设置为ipvs

使用kubeadm部署的k8s集群中,kube-proxy的配置文件是用configmap存放的,可以通过edit更改后重启kube-proxy的pod。

[root@k8s-m1 ~]# kubectl edit cm kube-proxy -n kube-system
 ......
    iptables:
      masqueradeAll: true
      masqueradeBit: 14
      minSyncPeriod: 0s
      syncPeriod: 30s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: rr
      strictARP: false
      syncPeriod: 15s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: ipvs
    nodePortAddresses: null
    oomScoreAdj: null
......
#修改mode模式为ipvs即可

创建 ClusterIP 类型服务时,IPVS proxier 将执行以下三项操作:

  • 确保节点中存在虚拟接口,默认为 kube-ipvs0
  • 将Service IP 地址绑定到虚拟接口
  • 分别为每个Service IP 地址创建 IPVS virtual servers
## pod的yml文件
[root@k8s-m1 k8s-total]# cat nginx-deployment.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      tier: frontend
  replicas: 1
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
        - name: nginx-gateway
          image: nginx
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
          ports:
            - containerPort: 80
#svc的yml文件
[root@k8s-m1 k8s-total]# cat nginx-svc.yml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 80
  selector:
    tier: frontend
#创建
[root@k8s-m1 k8s-total]#kubectl apply -f nginx-deployment.yml -f nginx-svc.yml
#查看svc
[root@k8s-m1 k8s-total]# kubectl get svc nginx-service
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
nginx-service   ClusterIP   10.111.157.115   <none>        80/TCP    2d12h
#查看pod
[root@k8s-m1 k8s-total]# kubectl get pod -o wide
NAME                        READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
configmap-subpath           1/1     Running   43         43h     10.244.42.136   k8s-m1   <none>           <none>
my-nginx-7ff446c4f4-2d9gz   1/1     Running   0          9m42s   10.244.42.143   k8s-m1   <none>           <none>
my-nginx-7ff446c4f4-tbtpc   1/1     Running   0          8m8s    10.244.11.12    k8s-m3   <none>           <none>

#查看ipvs转发表
[root@k8s-m1 k8s-total]# ipvsadm -Ln
TCP  10.111.157.115:80 rr
  -> 10.244.11.12:80              Masq    1      0          0         
  -> 10.244.42.143:80             Masq    1      0          0         
TCP  10.244.42.151:30080 rr
  -> 10.244.11.12:80              Masq    1      0          0         
  -> 10.244.42.143:80             Masq    1      0          0         
TCP  10.244.42.151:30119 rr
TCP  10.244.42.151:30404 rr

通过查看ipvs的转发表,发现是按照我们预想的转发。
删除 Kubernetes Service将触发删除相应的 IPVS 虚拟服务器,IPVS 物理服务器及其绑定到虚拟接口的 IP 地址。

端口映射:

IPVS 中有三种代理模式:NAT(masq),IPIP 和 DR。 只有 NAT 模式支持端口映射。 Kube-proxy 利用 NAT 模式进行端口映射。 以下示例显示 IPVS 服务端口80到Pod端口80的映射。

[root@k8s-m1 k8s-total]# ipvsadm -Ln
TCP  10.111.157.115:80 rr
  -> 10.244.11.12:80              Masq    1      0          0         
  -> 10.244.42.143:80             Masq    1      0          0       

会话关系:

IPVS 支持客户端 IP 会话关联(持久连接)。 当服务指定会话关系时,IPVS 代理将在 IPVS 虚拟服务器中设置超时值(默认为180分钟= 10800秒)。

ipvs proxier 将在以下5种情况下依赖于 iptables:

  • kube-proxy 设置 --masquerade-all = true
  • kube-proxy 设置 --cluster-cidr=<cidr>
  • Load Balancer 类型的 Service
  • NodePort 类型的 Service
  • 指定 externalIPs 的 Service

kube-proxy 配置参数 –masquerade-all=true

如果 kube-proxy 配置了–masquerade-all=true参数,则 ipvs 将伪装所有访问 Service 的 Cluster IP 的流量,此时的行为和 iptables 是一致的,由 ipvs 添加的 iptables 规则如下:

[root@k8s-m1 ~]# iptables -t nat -nL

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */

Chain KUBE-MARK-MASQ (2 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst

在 kube-proxy 启动时指定集群 CIDR

如果 kube-proxy 配置了–cluster-cidr=参数,则 ipvs 会伪装所有访问 Service Cluster IP 的外部流量,其行为和 iptables 相同,假设 kube-proxy 提供的集群 CIDR 值为:10.244.16.0/24,那么 ipvs 添加的 iptables 规则应该如下所示:

# iptables -t nat -nL

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */

Chain KUBE-MARK-MASQ (3 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  -- !10.244.16.0/24       0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst

Load Balancer 类型的 Service

对于loadBalancer类型的服务,ipvs 将安装匹配 KUBE-LOAD-BALANCER 的 ipset 的 iptables 规则。特别当服务的 LoadBalancerSourceRanges 被指定或指定 externalTrafficPolicy=local 的时候,ipvs 将创建 ipset 集合KUBE-LOAD-BALANCER-LOCAL/KUBE-LOAD-BALANCER-FW/KUBE-LOAD-BALANCER-SOURCE-CIDR,并添加相应的 iptables 规则,如下所示规则:

# iptables -t nat -nL

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */

Chain KUBE-FIREWALL (1 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER-SOURCE-CIDR dst,dst,src
KUBE-MARK-DROP  all  --  0.0.0.0/0            0.0.0.0/0

Chain KUBE-LOAD-BALANCER (1 references)
target     prot opt source               destination
KUBE-FIREWALL  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER-FW dst,dst
RETURN     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER-LOCAL dst,dst
KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0

Chain KUBE-MARK-DROP (1 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x8000

Chain KUBE-MARK-MASQ (2 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-LOAD-BALANCER  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER dst,dst
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER dst,dst

NodePort 类型的 Service

对于 NodePort 类型的服务,ipvs 将添加匹配KUBE-NODE-PORT-TCP/KUBE-NODE-PORT-UDP的 ipset 的iptables 规则。当指定externalTrafficPolicy=local时,ipvs 将创建 ipset 集KUBE-NODE-PORT-LOCAL-TC/KUBE-NODE-PORT-LOCAL-UDP并安装相应的 iptables 规则,如下所示:(假设服务使用 TCP 类型 nodePort)

|

# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */

Chain KUBE-MARK-MASQ (2 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

Chain KUBE-NODE-PORT (1 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-NODE-PORT-LOCAL-TCP dst
KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-NODE-PORT  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-NODE-PORT-TCP dst

指定 externalIPs 的 Service

对于指定了externalIPs的 Service,ipvs 会安装匹配KUBE-EXTERNAL-IP ipset 集的 iptables 规则,假设我们有指定了 externalIPs 的 Service,则 iptables 规则应该如下所示:

# iptables -t nat -nL

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */

Chain KUBE-MARK-MASQ (2 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-EXTERNAL-IP dst,dst
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-EXTERNAL-IP dst,dst PHYSDEV match ! --physdev-is-in ADDRTYPE match src-type !LOCAL
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-EXTERNAL-IP dst,dst ADDRTYPE match dst-type LOCAL

IPVS 模式

入流量

入流量是指由集群外部访问 service 的流量。
Iptables 入流量的 chain 路径是 PREROUTING@nat -> INPUT@nat。

ClusterIP

Iptables 入流量的 chain 路径是 PREROUTING@nat -> INPUT@nat。
在 PREROUTING 阶段,流量跳转到 KUBE-SERVICES target chain:

[root@k8s-m1 ~]# iptables -L -n -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
cali-PREROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* cali:6gwbT8clXdHdC1b1 */
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

KUBE-SERVICES chain 如下:


Chain KUBE-SERVICES (2 references)
target     prot opt source               destination         
KUBE-LOAD-BALANCER  all  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes service lb portal */ match-set KUBE-LOAD-BALANCER dst,dst
KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes service cluster ip + port for masquerade purpose */ match-set KUBE-CLUSTER-IP dst,dst
KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes service external ip + port for masquerade and filter purpose */ match-set KUBE-EXTERNAL-IP dst,dst
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes service external ip + port for masquerade and filter purpose */ match-set KUBE-EXTERNAL-IP dst,dst PHYSDEV match ! --physdev-is-in ADDRTYPE match src-type !LOCAL
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes service external ip + port for masquerade and filter purpose */ match-set KUBE-EXTERNAL-IP dst,dst ADDRTYPE match dst-type LOCAL
KUBE-NODE-PORT  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER dst,dst

ClusterIP service 的访问流量会交由 KUBE-MARK-MASQ处理,其匹配规则是匹配内核中名为 KUBE-CLUSTER-IP 的 ipset(将源地址不是10.244.0.0/16的IP交由KUBE-MARK-MASQ)。

下一步就是为这些包打上标记:

Chain KUBE-MARK-MASQ (4 references)
target     prot opt source               destination         
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

此时封包在 iptables 的路径已经走完,并没有后续的 DNAT 到后端 endpoint 的流程,这一步的工作交由 IPVS 来完成。(这步是仅仅给ipset list中的KUBE-CLUSTER-IP 添加了一个标签0x4000,有此标记的数据包会在KUBE-POSTROUTING chain中统一做MASQUERADE)

检查 ipvs 代理规则

用户可以使用ipvsadm工具检查 kube-proxy 是否维护正确的 ipvs 规则,比如,我们在集群中有以下一些服务:

[root@k8s-m1 k8s-total]# kubectl get svc -A
NAMESPACE                       NAME                        TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                                                                      AGE
default                         kubernetes                  ClusterIP      10.96.0.1        <none>          443/TCP                                                                      412d
kube-system                     kube-dns                    ClusterIP      10.96.0.10       <none>          53/UDP,53/TCP,9153/TCP                                                       412d

我们可以得到如下的一些 ipvs 代理规则:

[root@k8s-m1 k8s-total]# ipvsadm -Ln
TCP  10.96.0.1:443 rr
  -> 192.168.2.140:6443           Masq    1      0          0         
  -> 192.168.2.141:6443           Masq    1      1          0         
  -> 192.168.2.142:6443           Masq    1      1          0         
TCP  10.96.0.10:53 rr
  -> 10.244.11.58:53              Masq    1      0          0         
  -> 10.244.81.166:53             Masq    1      0          0   

出流量
出流量是指由集群内的 pod 访问 service 的流量。
Iptables 出流量的 chain 路径是 OUTPUT@nat -> POSTROUTING@nat。
OUTPUT chain 如下,与入流量情形一样,也是所有流量跳转到 KUBE-SERVICES chain:

[root@k8s-m1 k8s-total]#  iptables -L -n -t nat
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
cali-OUTPUT  all  --  0.0.0.0/0            0.0.0.0/0            /* cali:tVnHkvAo15HuiPy0 */
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

而后的动作与入流量一致,不论 ClusterIP service 还是 NodePort service,都是为封包打上 0x4000 的标记。区别是至此入流量的 iptables 流程走完,而出流量还需要经过 nat 表的 POSTROUTING chain,其定义如下:

[root@k8s-m1 k8s-total]#  iptables -L -n -t nat
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
cali-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* cali:O3lYWMrLQYEMJtB5 */
KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
MASQUERADE  all  --  172.16.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.19.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0                  

进一步跳转到 KUBE-POSTROUTING chain:Chain KUBE-POSTROUTING (1 references)

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination         
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes endpoints dst ip:port, source ip for solving hairpin purpose */ match-set KUBE-LOOP-BACK dst,dst,src
RETURN     all  --  0.0.0.0/0            0.0.0.0/0            mark match ! 0x4000/0x4000
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK xor 0x4000
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */

在这里,会为之前打上 0x4000 标记的出流量封包执行 MASQUERADE target,即类似于 SNAT 的一种操作,将其来源 IP 变更为 ClusterIP 或 Node ip。

被打了标记的流量处理方式

[root@k8s-m1 ~]#  iptables -L -n

Chain KUBE-FIREWALL (2 references)
target     prot opt source               destination         
DROP       all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes firewall for dropping marked packets */ mark match 0x8000/0x8000
DROP       all  -- !127.0.0.0/8          127.0.0.0/8          /* block incoming localnet connections */ ! ctstate RELATED,ESTABLISHED,DNAT

Chain KUBE-FORWARD (1 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes forwarding rules */ mark match 0x4000/0x4000
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes forwarding conntrack pod source rule */ ctstate RELATED,ESTABLISHED
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes forwarding conntrack pod destination rule */ ctstate RELATED,ESTABLISHED

ipset命令使用(iptables 中 match-set 匹配的就是就这里的地址 )

[root@k8s-m1 ~]# ipset list
Name: KUBE-CLUSTER-IP
Type: hash:ip,port
Revision: 5
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 3192
References: 2
Number of entries: 48
Members:
10.110.139.178,tcp:15443
10.108.18.160,tcp:8443
10.110.240.216,tcp:80
10.96.246.188,tcp:80
10.110.139.178,tcp:80
10.99.232.160,tcp:9411
10.100.7.245,tcp:14250
10.103.189.79,tcp:8000
10.96.0.10,tcp:9153
10.99.242.17,tcp:80
10.98.180.236,tcp:80
10.101.138.128,tcp:16686
10.97.144.128,tcp:853
10.101.230.40,tcp:9080
10.100.7.245,tcp:14268
10.110.57.244,tcp:9080
10.111.157.115,tcp:80
10.108.18.160,tcp:8080
10.101.101.153,tcp:8000
10.96.0.1,tcp:443
10.106.45.53,tcp:15443
10.97.144.128,udp:53
10.106.45.53,tcp:443
10.106.45.53,tcp:80
10.99.172.101,tcp:5000
10.98.90.254,tcp:443
10.97.144.128,tcp:443
10.98.189.216,tcp:20001
10.110.139.178,tcp:443
10.97.144.128,tcp:15012
10.100.7.245,tcp:14267
10.96.0.10,tcp:53
10.97.144.128,tcp:15010
10.104.103.99,tcp:9090
10.111.82.238,tcp:443
10.97.144.128,tcp:15014
10.97.164.0,tcp:80
10.106.150.183,tcp:9090
10.97.154.242,tcp:8080
10.104.131.196,tcp:9411
10.99.22.164,tcp:3306
10.104.193.235,tcp:443
10.110.33.30,tcp:9080
10.110.139.178,tcp:15020
10.110.139.178,tcp:31400
10.96.0.10,udp:53
10.97.172.70,tcp:3000
10.106.73.215,tcp:443

官方文档:https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md

更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

margu_168

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值