k8s(kubernetes)的Service的底层网络转发实现

642 阅读3分钟

1. 前言

k8s的Service转发依赖于kube-proxy组件,虽然是使用了底层的Netfilter作为数据转发面,但是也是kube-proxy负责监控k8s集群的配置,然后动态地配置这些规则(iptables的规则)。

k8s支持的Service的四种类型:

  • clusterIP
  • NodePort
  • LoadBalancer(需要云上服务商实现)
  • Headless

本文着重介绍ClusterIPNodePort的底层转发的设置。

2. 部署一个模拟业务

部署一个后端和ClusterIP(Service的默认类型)、NodePort,分别检查其底层设置的iptables规则是什么。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: debian-deployment
  labels:
    app: debian
spec:
  replicas: 3
  selector:
    matchLabels:
      app: debian
  template:
    metadata:
      labels:
        app: debian
    spec:
      containers:
      - name: debian
        image: debian
        ports:
          - containerPort: 80
        command: ["tail"]
        args: ["-f", "/dev/null"]
---
apiVersion: v1
kind: Service
metadata:
  name: my-debian
  labels:
    run: my-debian
spec:
  ports:
  - port: 8081
    targetPort: 80
    protocol: TCP
  selector:
    app: debian

---
apiVersion: v1
kind: Service
metadata:
  name: my-debian-nodeport
  labels:
    run: my-debian-nodeport
spec:
  type: NodePort
  ports:
  - nodePort: 32767
    port: 80
    protocol: TCP
  selector:
    app: debian

部署好两个Serice后,检查其CLUSTER-IP(vip)是什么。

kubectl -n lijiancai get service
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
my-debian            ClusterIP   11.1.246.253   <none>        8081/TCP       1d
my-debian-nodeport   NodePort    11.1.255.25    <none>        80:32767/TCP   1d

可以看出,ClusterIP和NodePort两种Service都部署好了。

2.1 检查NODEPORT的转发规则

首先看一下NodePort的转发规则,登陆其中一个k8s的Node上查看即可。 查看相关的规则: iptables-save |egrep "11.1.255.25|KUBE-SVC-LNV7GAXDUQDNSVVY|KUBE-SEP-J3E47UJWOXYCTXZO|KUBE-SEP-YG5NCD43FEYFCPSO|KUBE-SEP-P5NKJKBG5L2BFHIC" --color

20210227000521.png

对于NodePort这个服务,我们设置的外部端口是32767和80端口,其中32767是通过kube-proxy这个进程转发的。80端口则是通过iptables的规则进行转发的。这里可以得出一个结论:其实可以在Node节点上访问ClusterIP:80,也是可以访问到真实的业务的。如果是Node外部的客户端访问,就需要访问Node:32767了,这个时候,kube-proxy就会参与转发。

  apiVersion: v1
   kind: Service
   metadata:
     name: my-debian-nodeport
     labels:
       run: my-debian-nodeport
   spec:
     type: NodePort
     ports:
     - nodePort: 32767
       port: 80
       protocol: TCP
     selector:
       app: debian

2.2检查CLUSTER-IP的路由转发规则

查看CLUSTER-IP的转发规则,登陆其中一个Node上查看:iptables-save |egrep "11.1.246.253|KUBE-SVC-AE7Z2ITCKH72L4S6|KUBE-SEP-ITNKZ7TJM6CNT6XR|KUBE-SEP-4A3YQTBEZOS5YQXI|KUBE-SEP-GMGRS7VNE5IDYII6" --color

image.png

可以看出,CLUSTER-IP与NodePort的规则相似,只不过CLUSTER-IP不需要kube-proxy的参与转发。

2.3 关于SESSIONAFFINITY 粘性会话

iptables底层也是提供粘性会话的功能的。(支持k8s的Service的sessionAffinity: ClientIP)。

在Service的配置中,添加一个配置项sessionAffinity: ClientIP,就可以让某个客户端的ip一定会转发到同一个Pod上,对于缓存要求较高的业务可能需要这个功能。(顺便说一下,粘性会话这个功能与云原生的理念有点不一样,云原生强调的是环境是随时可以迁移的)

设置粘性会话前后iptables的规则对比:

image.png

设置粘性会话后,新增的规则有:

-A KUBE-SEP-4A3YQTBEZOS5YQXI -p tcp -m recent --set --name KUBE-SEP-4A3YQTBEZOS5YQXI --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 172.16.44.10:80

-A KUBE-SEP-GMGRS7VNE5IDYII6 -s 172.16.47.15/32 -j KUBE-MARK-MASQ

-A KUBE-SEP-GMGRS7VNE5IDYII6 -p tcp -m recent --set --name KUBE-SEP-GMGRS7VNE5IDYII6 --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 172.16.47.15:80

-A KUBE-SEP-ITNKZ7TJM6CNT6XR -s 172.16.34.3/32 -j KUBE-MARK-MASQ

-A KUBE-SEP-ITNKZ7TJM6CNT6XR -p tcp -m recent --set --name KUBE-SEP-ITNKZ7TJM6CNT6XR --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 172.16.34.3:80