hualinux 进阶 1.19: k8s Service服务工作原理概述
目录一、Service知识回顾二、k8s service工作原理三、k8s serice其它模式前章《k8s容器网络概述》讲了从docker讲起,讲到k8s怎样网络互通的。我们在讲Service服务的时候,讲了服务的使用,但是没有讲服务的工作原理,所以在这里简单讲一下。一、Service知识回顾Service 这个 Kubernetes 里重要的服务对象。而 Kubernetes 之所以需要 Se
目录
前章《k8s容器网络概述》讲了从docker讲起,讲到k8s怎样网络互通的。
我们在讲Service服务的时候,讲了服务的使用,但是没有讲服务的工作原理,所以在这里简单讲一下。
一、Service知识回顾
Service 这个 Kubernetes 里重要的服务对象。而 Kubernetes 之所以需要 Service,一方面是因为 Pod 的 IP 不是固定的,另一方面则是因为一组 Pod 实例之间总会有负载均衡的需求。
我们就用之前讲的《hualinux 进阶 1.14:Services服务及种类》1.2 建立service服务的例子,只不能我在deployment把pod节点改为2,下面是service实现代码
#1.建立群集,这里设置2台
mkdir -pv /disk1/myk8s
cd /disk1/myk8s/
#建立deployment群集,我设置2个pod,因为我这里只有一个节点
cat>nginx-deployment.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
web: nginx18
spec:
replicas: 2
selector:
matchLabels:
web: nginx18
template:
metadata:
labels:
web: nginx18
spec:
containers:
- name: nginx
image: nginx:1.18
ports:
- containerPort: 80
EOF
cat nginx-deployment.yaml
kubectl apply -f nginx-deployment.yaml
#2.创建一个服务
cat>nginx-ser.yaml<<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
#查找匹配的标签的pod
web: nginx18
ports:
- protocol: TCP
#services对外端口
port: 80
#这个是容器端口
targetPort: 80
EOF
kubectl apply -f nginx-ser.yaml
selector 选中的 Pod,就称为 Service 的 Endpoints,你可以使用 kubectl get ep 命令看到它们,
[root@vm82 myk8s]# kubectl get ep -o wide
NAME ENDPOINTS AGE
kubernetes 192.168.128.82:6443 15d
nginx 10.44.0.1:80,10.44.0.2:80 81m
需要注意的是,只有处于 Running 状态,且 readinessProbe 检查通过的 Pod,才会出现在 Service 的 Endpoints 列表里。并且,当某一个 Pod 出现问题时,Kubernetes 会自动把它从 Service 里摘除掉。
此时,通过该 Service 的 VIP 地址 10.102.199.132,你就可以访问到它所代理的 Pod 了
#svc是service的简写,如果不懂可以使用 kubectl api-resources -o wide 命令查看
[root@vm82 myk8s]# kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.102.199.132 <none> 80/TCP 87m
二、k8s service工作原理
实际上,Service 是由 kube-proxy 组件,加上 iptables 来共同实现的。
在用kubeadm安装k8s的时候 (可以见我的文章《hualinux 进阶 1.7:kubeadm1.18搭建k8s群集》),如发现没有iptables,默认自动安装上了iptables
[root@vm82 myk8s]# rpm -qa|grep iptables
iptables-libs-1.8.4-10.el8.x86_64
iptables-1.8.4-10.el8.x86_64
iptables-ebtables-1.8.4-10.el8.x86_64
我们可以 iptables-save 查看一下 上面nginx serice的iptables情况
#以nginx service IP地址形式查看iptables情况
[root@vm82 myk8s]# iptables-save |grep 10.102.199.132
-A KUBE-SERVICES ! -s 172.168.0.0/16 -d 10.102.199.132/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.102.199.132/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 80 -j KUBE-SVC-4N57TFCL4MD7ZTDA
发现了上面2条,一进一出,我们知道路径是有去有往的,所以2条,172.168.0.0是之前我kubeadm init初始化指定的cidr地址
#我这里指定网络段,如果不指定中可以省略--pod,可以加 “--dry-run”试运行,不会有改动
kubeadm init --pod-network-cidr=172.168.6.0/16
2条我就随便拿 最后一条查看吧,
可以看到,这条 iptables 规则的含义是:凡是目的地址是 10.102.199.132、目的端口是 80 的 IP 包,都应该跳转到另外一条名叫 KUBE-SVC-4N57TFCL4MD7ZTDA 的 iptables 链进行处理。
随便说一下第1条,KUBE-MARK-MASQ就是非172.168.0.0/16网段的,进入10.102.199.132前要进行伪装,即NAT
而我们前面已经看到,10.102.199.132正是这个 Service 的 VIP。所以这一条规则,就为这个 Service 设置了一个固定的入口地址。并且,由于10.102.199.132 只是一条 iptables 规则上的配置,并没有真正的网络设备,所以你 ping 这个地址,是不会有任何响应的。
现在再看一下 KUBE-SVC-4N57TFCL4MD7ZTDA 链的情况
[root@vm82 myk8s]# iptables-save |grep ' KUBE-SVC-4N57TFCL4MD7ZTDA'
-A KUBE-SERVICES -d 10.102.199.132/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 80 -j KUBE-SVC-4N57TFCL4MD7ZTDA
-A KUBE-SVC-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-RNUA2WF32F4IZIFK
-A KUBE-SVC-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx:" -j KUBE-SEP-ZZWMMMZWIOYPPLV7
最上面第1条讲了。
第2条:--mode random 是随便模式的,--probability 0.50000000000 即为1/2机率被选中,因为2个pod。可以看出使用的是rr算法,而随机模式发向的是 KUBE-SEP-RNUA2WF32F4IZIFK
第3条:就是转到KUBE-SEP-ZZWMMMZWIOYPPLV7链处理,指向的最终目的地,其实就是这个 Service 代理的2个 Pod
所以这一组规则,就是 Service 实现负载均衡的功能。
再分别查看 KUBE-SEP-RNUA2WF32F4IZIFK 和 KUBE-SEP-ZZWMMMZWIOYPPLV7 这2个链表,如下所示:
[root@vm82 myk8s]# iptables-save |egrep ' KUBE-SEP-RNUA2WF32F4IZIFK'
-A KUBE-SVC-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-RNUA2WF32F4IZIFK
-A KUBE-SEP-RNUA2WF32F4IZIFK -s 10.44.0.1/32 -m comment --comment "default/nginx:" -j KUBE-MARK-MASQ
-A KUBE-SEP-RNUA2WF32F4IZIFK -p tcp -m comment --comment "default/nginx:" -m tcp -j DNAT --to-destination 10.44.0.1:80
[root@vm82 myk8s]#
[root@vm82 myk8s]# iptables-save |egrep ' KUBE-SEP-ZZWMMMZWIOYPPLV7'
-A KUBE-SVC-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx:" -j KUBE-SEP-ZZWMMMZWIOYPPLV7
-A KUBE-SEP-ZZWMMMZWIOYPPLV7 -s 10.44.0.2/32 -m comment --comment "default/nginx:" -j KUBE-MARK-MASQ
-A KUBE-SEP-ZZWMMMZWIOYPPLV7 -p tcp -m comment --comment "default/nginx:" -m tcp -j DNAT --to-destination 10.44.0.2:80
这个很清晰了吧,就是2个pod的IP地址
DNAT 规则的作用,就是在 PREROUTING 检查点之前,也就是在路由之前,将流入 IP 包的目的地址和端口,改成–to-destination 所指定的新的目的地址和端口。可以看到,这个目的地址和端口,正是被代理 Pod 的 IP 地址和端口。
访问 Service VIP 的 IP 包经过上述 iptables 处理之后,就已经变成了访问具体某一个后端 Pod 的 IP 包了。不难理解,这些 Endpoints 对应的 iptables 规则,正是 kube-proxy 通过监听 Pod 的变化事件,在宿主机上生成并维护的。
以上,就是 Service 最基本的工作原理。
上面使用的是 iptables 代理模式
三、k8s serice其它模式
k8s service除了iptables 代理模式 ,还有 IPVS 代理模式,还有一种比较旧的 userspace 代理模式,我这里就不讲了,主要讲一下IPVS 代理模式
其实,通过上面的讲解,你可以看到,kube-proxy 通过 iptables 处理 Service 的过程,其实需要在宿主机上设置相当多的 iptables 规则。而且,kube-proxy 还需要在控制循环里不断地刷新这些规则来确保它们始终是正确的。
不难想到,当你的宿主机上有大量 Pod 的时候,成百上千条 iptables 规则不断地被刷新,会大量占用该宿主机的 CPU 资源,甚至会让宿主机“卡”在这个过程中。所以说,一直以来,基于 iptables 的 Service 实现,都是制约 Kubernetes 项目承载更多量级的 Pod 的主要障碍。
而 IPVS 模式的 Service,就是解决这个问题的一个行之有效的方法。
IPVS 模式的工作原理,其实跟 iptables 模式类似。当我们创建了前面的 Service 之后,kube-proxy 首先会在宿主机上创建一个虚拟网卡(叫作:kube-ipvs0),并为它分配 Service VIP 作为 IP 地址。
而接下来,kube-proxy 就会通过 Linux 的 IPVS 模块,为这个 IP 地址设置三个 IPVS 虚拟主机,并设置这三个虚拟主机之间使用轮询模式 (rr) 来作为负载均衡策略。我们可以通过 ipvsadm 查看到这个设置
比于 iptables,IPVS 在内核中的实现其实也是基于 Netfilter 的 NAT 模式,所以在转发这一层上,理论上 IPVS 并没有显著的性能提升。但是,IPVS 并不需要在宿主机上为每个 Pod 设置 iptables 规则,而是把对这些“规则”的处理放到了内核态,从而极大地降低了维护这些规则的代价。“将重要操作放入内核态”是提高性能的重要手段。
不过需要注意的是,IPVS 模块只负责上述的负载均衡和代理功能。而一个完整的 Service 流程正常工作所需要的包过滤、SNAT 等操作,还是要靠 iptables 来实现。只不过,这些辅助性的 iptables 规则数量有限,也不会随着 Pod 数量的增加而增加。
所以,在大规模集群里,我非常建议你为 kube-proxy 设置–proxy-mode=ipvs 来开启这个功能。它为 Kubernetes 集群规模带来的提升,还是非常巨大的。
PS:
kubeadm 配置中有关 kube-proxy 的说明请查看:
使用 kubeadm 启用 IPVS 模式的说明请查看:
更多推荐
所有评论(0)