1. 前言
k8s的Service转发依赖于kube-proxy组件,虽然是使用了底层的Netfilter作为数据转发面,但是也是kube-proxy负责监控k8s集群的配置,然后动态地配置这些规则(iptables的规则)。
k8s支持的Service的四种类型:
- clusterIP
- NodePort
- LoadBalancer(需要云上服务商实现)
- Headless
本文着重介绍ClusterIP 和 NodePort的底层转发的设置。
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
对于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
可以看出,CLUSTER-IP与NodePort的规则相似,只不过CLUSTER-IP不需要kube-proxy的参与转发。
2.3 关于SESSIONAFFINITY 粘性会话
iptables底层也是提供粘性会话的功能的。(支持k8s的Service的sessionAffinity: ClientIP)。
在Service的配置中,添加一个配置项sessionAffinity: ClientIP,就可以让某个客户端的ip一定会转发到同一个Pod上,对于缓存要求较高的业务可能需要这个功能。(顺便说一下,粘性会话这个功能与云原生的理念有点不一样,云原生强调的是环境是随时可以迁移的)
设置粘性会话前后iptables的规则对比:
设置粘性会话后,新增的规则有:
-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