暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kube Proxy 工作模式概述

Kubernetes 学习圈 2020-03-05
644

  点击上方蓝色字体关注我哟!

快来跟我一起学 Kubernetes!

kube-proxy 是 Kubernetes 的核心组件之一,主要负责处理访问 Service 的流量(包括通过 Cluster IP 以及 Node Port),智能地将 Client 对 Kubernetes Service 的请求代理到正确的 Endpoint 后端。截止 1.18 版本,kube-proxy 能够支持的运行模式有 4 种,其平台支持情况如下表:


ModeLinuxWindows
userspaceYY
iptablesYN
ipvsYN
kernelspaceNY


在 userspace 模式,kube-proxy 通过监听 k8s apiserver 获取关于 Service 和 Endpoint 的变化信息,在内存中维护一份从ClusterIP:Port
到后端 Endpoints
的映射关系,通过反向代理的形式,将收到的数据包转发给后端,并将后端返回的应答报文转发给客户端。该模式下,kube-proxy 会为每个 Service (每种协议,每个 Service IP,每个 Service Port)在宿主机上创建一个套接字(监听端口随机)用于接收和转发 client 的请求。默认条件下,kube-proxy 采用 round-robin 轮询算法从后端 Endpoint 列表中选择一个响应请求。

[root@machine ~]# kubectl get svc --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 8d
[root@machine ~]# netstat -apn | grep kube-proxy
tcp6 0 0 :::39748 :::* LISTEN 21092/kube-proxy
tcp6 0 0 :::46122 :::* LISTEN 21092/kube-proxy
tcp6 0 0 :::10256 :::* LISTEN 21092/kube-proxy
tcp6 0 0 :::43892 :::* LISTEN 21092/kube-proxy

正如上面命令行面板展示的,kube-proxy 会根据 Service IP(包括 CLUSTER-IP 和 EXTERNAL-IP)、协议以及端口号确定一个 Socket,在宿主机上打开一个监听端口。客户端访问 Service 的流量会被分别路由到对应的 Socket 监听端口得到处理。Service 到 Socket 的重定向路由,在 Linux 平台采用 iptables 实现,在 Windows 平台通过绑定 ClusterIP 到宿主机网卡实现。以下是 Linux iptables 对数据包重定向的规则示意,访问 10.96.0.1:443 的数据包被重定向到本机 Socket 监听端口 46122,而 46122 代理的后端就是 k8s apiserver 服务:

[root@machine ~]# iptables -t nat -S
-A KUBE-PORTALS-CONTAINER -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https" -m tcp --dport 443 -j REDIRECT --to-ports 46122
-A KUBE-PORTALS-HOST -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https" -m tcp --dport 443 -j DNAT --to-destination 192.168.137.139:46122

userspace 模式工作原理示意:


在 iptables 模式,kube-proxy 依然需要通过监听 k8s apiserver 获取关于 Service 和 Endpoint 的变化信息。不过与 userspace 模式不同的是,kube-proxy 不再为每个 Service 创建反向代理(也就是无需创建 Socket 监听),而是通过安装 iptables 规则,捕获访问 Service ClusterIP:Port 的流量,直接重定向到指定的 Endpoints 后端。默认条件下,kube-proxy 会随机从后端 Endpoint 列表中选择一个响应请求。ipatbles 模式与 userspace 模式不同之处在于,数据包的转发不再通过 kube-proxy 在用户空间通过反向代理来做,而是基于 iptables/netfilter 在内核空间直接转发,因此在性能上具有很大优势,而且也避免了大量宿主机端口被占用的问题。

但是将数据转发完全交给 iptables 来做也有个缺点,就是一旦选择的后端没有正确响应,连接就会直接失败了,而不会像 userspace 模式那样,反向代理可以支持自动重新选择其它后端进行重试,算是失去了一定的灵活性。不过,官方建议使用 Readiness 健康探针来解决这个问题,一旦检测到后端故障,就自动将其移出 Endpoint 负载均衡池,避免请求被代理到存在问题的后端。

[root@machine ~]# iptables -t nat -S
-A KUBE-SEP-XVJ25MO2MX75T34R -s 192.168.137.139/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-XVJ25MO2MX75T34R -p tcp -m tcp -j DNAT --to-destination 192.168.137.139:6443
-A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
-A KUBE-SVC-NPX46M4PTMTKRN6Y -j KUBE-SEP-XVJ25MO2MX75T34R

正如上面展示的 iptables 规则,访问 10.96.0.1 443 端口的流量会被交由 KUBE-SVC-NPX46M4PTMTKRN6Y 处理,KUBE-SVC-NPX46M4PTMTKRN6Y 继而跳转到 KUBE-SEP-XVJ25MO2MX75T34R,最终 DNAT 到目的 Node 的 6443 端口,这正是 k8s apiserver 的监听地址。因此,iptables 模式下,完全通过 iptables 自身就实现了流量转发。注意,这里最上边那条是 DNAT 的配对策略,DNAT 的回包需要做 UN-DNAT(即 SNAT/MASQ)。

iptables 模式工作原理示意:


在 ipvs 模式,kube-proxy 仍然通过监听 k8s apiserver 获取关于 Service 和 Endpoint 的变化信息,然后调用 netlink 接口创建 ipvs 规则,并周期性地同步 Service、Endpoint 与 ipvs 规则,保证状态匹配。当客户端请求 Service 时,ipvs 会将流量代理到指定的后端。

ipvs 相比 iptables 的优势在于通过 hash table 实现了 O(1) 时间复杂度的规则匹配。当 Service 和 Endpoint 的数量急剧增加时,iptables 的匹配表项会变得十分庞大,而其采用的顺序匹配模式会严重影响其性能。相反,ipvs 无论在小规模集群还是大规模集群,都拥有几乎相同的性能表现,因此相比其他代理模式,能提供更高的网络吞吐量。与此同时,ipvs 模式还为用户提供了更多的负载均衡策略以供选择,例如:

- rr: round-robin (轮询,默认采用)

- lc: least connection (最少连接数)

- dh: destination hashing (根据目的哈希)

- sh: source hashing (根据源哈希)

- sed: shortest expected delay (最小延迟)

- nq: never queue (不排队等待,有空闲后端直接分配,否则通过 sed 策略分配)


ipvs 仍然使用 iptables 实现对数据包的过滤、SNAT 或 MASQ,但使用 ipset 来存储需要执行 MASQ 或 DROP 的源地址和目的地址,从而保证在大量 Service 存在的情况下,iptables 表项数量仍能维持在常数级恒定。


[root@machine ~]# iptables -t nat -S
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A KUBE-SERVICES -m set --match-set KUBE-CLUSTER-IP dst,dst -j ACCEPT
[root@machine ~]# ip addr show dev kube-ipvs0
68: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
link/ether fe:04:6f:5a:01:3e brd ff:ff:ff:ff:ff:ff
inet 10.96.0.10/32 brd 10.96.0.10 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.96.0.1/32 brd 10.96.0.1 scope global kube-ipvs0
valid_lft forever preferred_lft forever
[root@machine ~]# ipset list
Name: KUBE-CLUSTER-IP
Type: hash:ip,port
Revision: 2
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16656
References: 2
Members:
10.96.0.10,tcp:53
10.96.0.10,tcp:9153
10.96.0.10,udp:53
10.96.0.1,tcp:443
[root@machine ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 192.168.137.139:6443 Masq 1 1 0
TCP 10.96.0.10:53 rr
-> 10.80.1.233:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 10.80.1.233:9153 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 10.80.1.233:53 Masq 1 0 0

如上所示,kube-proxy 通过 iptables 允许访问 KUBE-CLUSTER-IP 的流量,并通过在虚拟网卡 kube-ipvs0 上配置 ClusterIP 的方式,让内核以为 ClusterIP 为本机 IP,从而走 iptables 的 INPUT 链进入本机,继而通过 IP Virtual Server 找到 Real Server 提供服务。

ipvs 模式工作原理示意:


kernelspace 也可以说是 winkernel 模式,因为它只应用于 Windows 平台。在 kernelspace 模式下,kube-proxy 通过监听 k8s apiserver 获取关于 Service 和 Endpoint 的变化信息,然后通过 HNS (Host Network Service) 接口直接配置 Windows 内核的 LoadBalancer 以及 Endpoint ,实现基于 winkernel 的 Kubernetes Service 代理服务。

winkernel 模式相对 winuserspace 模式的改进与 iptables 模式相对 userspace 模式的改进类似,即避免了主动创建大量的 Socket 监听,也免去了频繁且低效的用户态-内核态数据拷贝,直接通过配置系统的 LoadBalancer 和 Endpoint 实现代理,性能上具有明显优势。

winkernel 模式工作原理示意:


本文介绍了 kube-proxy 网络代理组件的几种工作模式,其实也隐含了软件迭代进化的影子,userspace 模式目前已经几乎不再被使用,iptables 能满足常规场景下需求,是默认模式,ipvs 则更适合在大规模集群应用,未来发展可期。关于这些模式的更多实现细节,请看下回分解!


公众号『 Kubernetes 学习圈 』每天会发布一篇与 Kubernetes 相关的互动小问题!通过分析和解决小问题来驱动学习,逐步掌握 Kubernetes 容器编排技术,日拱一卒,每天进步一点


好的技术绝对不是一蹴而就,而在于日复一日的积累,相信坚持的力量!

PS:看完文章如果有收获,顺手花 1s 时间帮点下文末右下方的「在看」,感激!

如果我的文章对你有所帮助,点赞、转发都是一种支持!

文章转载自Kubernetes 学习圈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论