【云原生 | 从零开始学Kubernetes】二十、Service代理kube-proxy组件详解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

该篇文章已经被专栏《从零开始学k8s》收录
上一篇文章Kubernetes核心技术Service实战 点击跳转

在这里插入图片描述

kube-proxy组件详解

kube-proxy 组件介绍

Kubernetes service 只是把应用对外提供服务的方式做了抽象真正的应用跑在 Pod 中的 container 里我们的请求转到 kubernetes nodes 对应的 nodePort 上那么 nodePort 上的请求是如何进一步转到提供后台服务的 Pod 的呢 就是通过 kube-proxy 实现的

kube-proxy 部署在 k8s 的每一个 Node 节点上是 Kubernetes 的核心组件我们创建一个 service 的时候kube-proxy 会在 iptables 中追加一些规则为我们实现路由与负载均衡的功能。在 k8s1.8 之前kube-proxy 默认使用的是 iptables 模式通过各个 node 节点上的 iptables 规则来实现 service 的负载均衡但是随着 service 数量的增大iptables 模式由于线性查找匹配、全量更新等特点其性能 会显著下降。从 k8s 的 1.8 版本开始kube-proxy 引入了 IPVS 模式IPVS 模式与 iptables 同样基于 Netfilter但是采用的 hash 表因此当 service 数量达到一定规模时hash 查表的速度优势就会显现出来从而提高 service 的服务性能。

kubectl get pods -n kube-system -o wide

service 是一组 pod 的服务抽象相当于一组 pod 的 LB负责将请求分发给对应的 pod。service 会为这个 LB 提供一个 IP一般称为 cluster IP。kube-proxy 的作用主要是负责 service 的实现具体来说就是实现了内部从 pod 到 service 和外部的从 node port 向 service 的访问。

1、kube-proxy 其实就是管理 service 的访问入口包括集群内 Pod 到 Service 的访问和集群外访问 service。

2、kube-proxy 管理 sevice 的 Endpoints该 service 对外暴露一个 Virtual IP也可以称为是 Cluster IP, 集群内通过访问这个 Cluster IP:Port 就能访问到集群内对应的 serivce 下的 Pod。

kube-proxy 三种工作模式

1、Userspace 方式

在这里插入图片描述

Client Pod 要访问 Server Pod 时它先将请求发给内核空间中的 service iptables 规则由它再将请求转给监听在指定套接字上的 kube-proxy 的端口kube-proxy 处理完请求并分发请求到指定Server Pod 后,再将请求转发给内核空间中的 service ip由 service iptables 将请求转给各个节点中 的 Server Pod。

这个模式有很大的问题客户端请求先进入内核空间的又进去用户空间访问 kube-proxy由 kube-proxy 封装完成后再进去内核空间的 iptables再根据 iptables 的规则分发给各节点的用户空间的 pod。由于其需要来回在用户空间和内核空间交互通信因此效率很差。在 Kubernetes 1.1 版本之前userspace 是默认的代理模型。

2、iptables 方式

在这里插入图片描述

客户端 IP 请求时直接请求本地内核 service ip根据 iptables 的规则直接将请求转发到到各 pod 上因为使用 iptable NAT 来完成转发也存在不可忽视的性能损耗。另外如果集群中存上万的 Service/Endpoint那么 Node 上的 iptables rules 将会非常庞大性能还会再打折 iptables 代理模式由 Kubernetes 1.1 版本引入自 1.2 版本开始成为默认类型。

3、ipvs 方式

在这里插入图片描述

Kubernetes 自 1.9-alpha 版本引入了 ipvs 代理模式自 1.11 版本开始成为默认设置。客户端请求时到达内核空间时根据 ipvs 的规则直接分发到各 pod 上。kube-proxy 会监视 Kubernetes Service 对象和 Endpoints调用 netlink 接口以相应地创建 ipvs 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则以确保 ipvs 状态与期望一致。访问服务时流量将被重定向到其中一个后端 Pod。与 iptables 类似ipvs 基于 netfilter 的 hook 功能但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量并且在同步代理规则时具有更好的性能。此外ipvs 为负载均衡算法提供了更多选项例如

rr轮询调度  

lc最小连接数  

dh目标哈希  

sh源哈希  

sed最短期望延迟  

nq不排队调度 

如果某个服务后端 pod 发生变化标签选择器适应的 pod 又多一个适应的信息会立即反映到 apiserver 上而 kube-proxy 一定可以 watch 到 etc 中的信息变化而将它立即转为 ipvs 或者 iptables 中的规则这一切都是动态和实时的删除一个 pod 也是同样的原理。

在这里插入图片描述

以上不论哪种kube-proxy 都通过 watch 的方式监控着 apiserver 写入 etcd 中关于 Pod 的最新状态信息,它一旦检查到一个 Pod 资源被删除了或新建了它将立即将这些变化反应在 iptables 或 ipvs 规则中以便 iptables 和 ipvs 在调度 Clinet Pod 请求到 Server Pod时不会出现 Server Pod 不存在的情况。自 k8s1.11 以后,service 默认使用 ipvs 规则若 ipvs 没有被激活则降级使用 iptables 规则.

kube-proxy 生成的 iptables 规则分析

1、service 的 type 类型是 ClusterIpiptables 规则分析

在 k8s 创建的 service虽然有 ip 地址但是 service 的 ip 是虚拟的不存在物理机上的是在 iptables 或者 ipvs 规则里的。

[root@k8smaster service]# kubectl apply -f pod_test.yaml 
[root@k8smaster service]# kubectl apply -f service_test.yaml 
[root@k8smaster node]# kubectl get svc -l run=my-nginx
NAME       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
my-nginx   ClusterIP   10.105.254.244   <none>        80/TCP    15s
[root@k8smaster node]# kubectl get pods -l run=my-nginx -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE  
my-nginx-5898cf8d98-5trvw   1/1     Running   0          40s   10.244.1.5   k8snode2   <none>          
my-nginx-5898cf8d98-phfqr   1/1     Running   0          40s   10.244.1.4   k8snode2   <none>          
[root@k8smaster node]# iptables -t nat -L | grep 10.105.254.244
KUBE-MARK-MASQ  tcp  -- !10.244.0.0/16        10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http
KUBE-SVC-BEPXDJBUHFCSYIC3  tcp  --  anywhere             10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http

[root@k8smaster node]# iptables -t nat -L | grep KUBE-SVC-BEPXDJBUHFCSYIC3
KUBE-SVC-BEPXDJBUHFCSYIC3  tcp  --  anywhere             10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http			#把service关联的pod做了转发
Chain KUBE-SVC-BEPXDJBUHFCSYIC3 (1 references)		

[root@k8smaster node]# iptables -t nat -L | grep 10.244.1.5
KUBE-MARK-MASQ  all  --  10.244.1.5           anywhere             /* default/my-nginx: */
DNAT       tcp  --  anywhere             anywhere             /* default/my-nginx: */ tcp to:10.244.1.5:80
#DNAT转发 kubesvc接收请求在过滤podip的时候有个mark也会标记ip然后做了一个dnat转发到10.244.1.5:80这个pod上

#通过上面可以看到之前创建的 service会通过 kube-proxy 在 iptables 中生成一个规则来实现流量路由有一系列目标为 KUBE-SVC-xxx 链的规则每条规则都会匹配某个目标 ip 与端口。也就是说访问某个 serivce的ip和端口请求会由 KUBE-SVC-xxx 链来通过DNAT转发到对应的podip和端口上。

2、service 的 type 类型是 nodePortiptables 规则分析

[root@k8smaster node]# kubectl apply -f pod_nodeport.yaml 
deployment.apps/my-nginx-nodeport created
[root@k8smaster node]# kubectl apply -f service_nodeport.yaml 
service/my-nginx-nodeport created

[root@k8smaster node]# kubectl get pods -l run=my-nginx-nodeport -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED
my-nginx-nodeport-5fccbb754b-m4csx   1/1     Running   0          34s   10.244.1.7   k8snode2   <none>      
my-nginx-nodeport-5fccbb754b-rg48l   1/1     Running   0          34s   10.244.1.6   k8snode2   <none>
[root@k8smaster node]# kubectl get svc -l run=my-nginx-nodeport 
NAME                TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
my-nginx-nodeport   NodePort   10.105.58.82   <none>        80:30380/TCP   39s
 
[root@k8smaster node]# iptables -t nat -S | grep 30380 
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-SVC-6JXEEPSEELXY3JZG
#一个是mark链一个是svc 在访问物理机ip和端口访问会先经过这两个链

[root@k8smaster node]# iptables -t nat -S | grep KUBE-SVC-6JXEEPSEELXY3JZG
-N KUBE-SVC-6JXEEPSEELXY3JZG
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-SVC-6JXEEPSEELXY3JZG
-A KUBE-SERVICES -d 10.105.58.82/32 -p tcp -m comment --comment "default/my-nginx-nodeport: cluster IP" -m tcp --dport 80 -j KUBE-SVC-6JXEEPSEELXY3JZG
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-36FBCF7ZW3VDH33Q
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -j KUBE-SEP-K2MGI3AJIGBK3IJ5
#会通过iptables的probability机制有0.50的概率进入KUBE-SEP-36FBCF7ZW3VDH33Q这个链剩下50%还是最后那个GBK3IJ5这个链

[root@k8smaster node]# iptables -t nat -S | grep KUBE-SEP-36FBCF7ZW3VDH33
-N KUBE-SEP-36FBCF7ZW3VDH33Q
-A KUBE-SEP-36FBCF7ZW3VDH33Q -s 10.244.1.6/32 -m comment --comment "default/my-nginx-nodeport:" -j KUBE-MARK-MASQ
-A KUBE-SEP-36FBCF7ZW3VDH33Q -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.6:80
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-36FBCF7ZW3VDH33Q

#-A KUBE-SEP-36FBCF7ZW3VDH33Q -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.6:80 是做了一个dnat把请求给10.244.1.6这个pod的80端口了 下面可以看到ip是相同的
[root@k8smaster node]# kubectl get pods -l run=my-nginx-nodeport -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED
my-nginx-nodeport-5fccbb754b-m4csx   1/1     Running   0          8m24s   10.244.1.7   k8snode2   <none>    
my-nginx-nodeport-5fccbb754b-rg48l   1/1     Running   0          8m24s   10.244.1.6   k8snode2   <none>    

 
[root@k8smaster node]# iptables -t nat -S | grep KUBE-SEP-K2MGI3AJIGBK3IJ5
-N KUBE-SEP-K2MGI3AJIGBK3IJ5
-A KUBE-SEP-K2MGI3AJIGBK3IJ5 -s 10.244.1.7/32 -m comment --comment "default/my-nginx-nodeport:" -j KUBE-MARK-MASQ
-A KUBE-SEP-K2MGI3AJIGBK3IJ5 -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.7:80
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -j KUBE-SEP-K2MGI3AJIGBK3IJ5
#也是一个dnat把请求分给另外一个pod通过这两个链50%的概率来转发到两个pod上

写在最后

创作不易如果觉得内容对你有帮助麻烦给个三连关注支持一下我如果有错误请在评论区指出我会及时更改
目前正在更新的系列从零开始学k8s
感谢各位的观看文章掺杂个人理解如有错误请联系我指出~
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: k8s