kube-proxy是kubernetes中网络核心组件,实现了服务暴露和转发等网络功能。kube-proxy支持userspace,ipvs和iptables三种代理模式。userspace性能问题较严重,基本不再使用,应用最多的是iptables和ipvs模式。
kube-proxy 以daemonset的方式运行在每个Node计算节点上,负责Pod网络代理, 它会定时通过apiserver从etcd服务获取到service和endpoint资源的变化,维护网络规则和四层负载均衡工作。在K8s集群中微服务的负载均衡是由Kube-proxy实现的,它是K8s集群内部的负载均衡器,也是一个分布式代理服务器,在K8s的每个节点上都有一个,这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的Kube-proxy就越多,高可用节点也随之增多。在k8s的网络模型中,实际就是一个反向代理。
在kubernetes网络中,还有其他网络插件实现了和kube-proxy相同的功能,若kube-router,cilium,他们都支持kube-proxy实现的功能,因此在使用上述网络插件时,集群里可以不部署kube-proxy。
service是一组pod的服务抽象,相当于一组pod的LB,负责将请求分发给对应的pod。service会为这个LB提供一个IP,一般称为cluster IP。kube-proxy的作用主要是负责service的实现,具体来说,就是实现了内部从pod到service和外部的从node port向service的访问。
小结:
kube-proxy其实就是管理service的访问入口,包括集群内Pod到Service的访问和集群外访问service。
kube-proxy管理sevice的Endpoints,该service对外暴露一个Virtual IP,也成为Cluster IP, 集群内通过访问这个Cluster IP:Port就能访问到集群内对应的serivce下的Pod。
service是通过Selector选择的一组Pods的服务抽象,其实就是一个微服务,提供了服务的LB和反向代理的能力,而kube-proxy的主要作用就是负责service的实现。
service另外一个重要作用是,一个服务后端的Pods可能会随着生存灭亡而发生IP的改变,service的出现,给服务提供了一个固定的IP,而无视后端Endpoint的变化。
Kubernetes Service定义了这样一种抽象: Service是一种可以访问 Pod逻辑分组的策略, Service通常是通过 Label Selector访问 Pod组。
service类型:
在k8s中定义了4中service类型
ClusterIP:通过 VIP 访问 Service,但该 VIP 只能在此集群内访问
NodePort:通过 NodeIP:NodePort 访问 Service,会在集群内的所有节点上开启端口
ExternalIP:与 ClusterIP 相同,但是这个 VIP 可以从这个集群之外访问
LoadBalancer:类似公网的负载均衡器
创建Service的同时,会自动创建跟Service同名的Endpoints。 Endpoint 是k8s集群中一个资源对象,存储在etcd里面,用来记录一个service 对应的所有pod的访问地址。service通过selector和pod建立关联。service配置selector endpoint controller 才会自动创建对应的endpoint 对 象,否则是不会生产endpoint 对象。
一个service由一组后端的pod组成,这些后端的pod通过service endpoint暴露 出来,如果有一个新的pod创建创建出来,且pod的标签名称(label:pod)跟 service里面的标签(label selector 的label)一致会自动加入到service的 endpoints 里面,如果pod对象终止后,pod 会自动从edpoints 中移除。在集群中任意节点可以使用curl请求service:port来访问后端pod业务。
Endpoint Controller
Endpoint Controller是k8s集群控制器的其中一个组件,其功能如下:
2 ############################################
3 负责生成和维护所有endpoint对象的控制器
4 负责监听service和对应pod的变化
5 监听到service被删除,则删除和该service同名的endpoint对象
6 监听到新的service被创建,则根据新建service信息获取相关pod列表,然后创建对应end
point对象
7 监听到service被更新,则根据更新后的service信息获取相关pod列表,然后更新对应end
point对象
8 监听到pod事件,则更新对应的service的endpoint对象,将podIp记录到endpoint中
在kubernetes 1.8以上的版本中,对于kube-proxy组件增加了除iptables模式和用户模式之外还支持ipvs模式。kube-proxy ipvs 是基于 NAT 实现的,通过ipvs的NAT模式,对访问k8s service的请求进行虚IP到POD IP的转发。当创建一个 service 后,kubernetes 会在每个节点上创建一个网卡,同时将 Service IP(VIP) 绑定上并根据service架构在每个节点创建ipvs规则。
可以参考此处链接https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md
#######查看主机的ipvs模块
[root@node1 ~]# lsmod | grep ip_vs
ip_vs_sh 12688 0
ip_vs_wrr 12697 0
ip_vs_rr 12600 27
ip_vs 145458 33 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack 139264 11 ip_vs,xt_CT,nf_nat,nf_nat_ipv4,nf_nat_ipv6,xt_conntrack,nf_nat_masquerade_ipv4,nf_nat_masquerade_ipv6,nf_conntrack_netlink,nf_conntrack_ipv4,nf_conntrack_ipv6
libcrc32c 12644 4 xfs,ip_vs,nf_nat,nf_conntrack
[root@node1 ~]#
#######查看kube-proxy的使用的模式
[root@node1 ~]# kubectl describe cm/kube-proxy -n kube-system
mode: ipvs ####k8s高版本默认为ipvs
IPVS 为大型集群提供更好的可扩展性和性能。采用 ipset 是为了减少 iptables 规则
IPVS 支持比 IPTABLES 更复杂的负载均衡算法(如果不配置,默认为rr)
rr:循环
lc:最少连接
dh:目标散列
sh:源散列
sed:最短的预期延迟
nq:从不排队
IPVS支持服务器健康检查和连接重试等。
#############################
也并不是说,有了ipvs就不需要iptables了,IPVS 用于负载平衡,但它无法处理 kube-proxy 中的其他变通方法,例如数据包过滤、发夹伪装技巧、SNAT 等。在此处几个场景中,ipvs将利用iptables来实现。
ipvs proxier 会在以下 4 种场景下回退到 iptables:
kube-proxy 以 --masquerade-all=true 开头
在 kube-proxy 启动时指定集群 CIDR
支持Loadbalancer类型的服务
支持NodePort类型服务
通过查看kube-proxy查看是否有以上几种模式
[root@node1 ~]# kubectl describe cm/kube-proxy -n kube-system
iptables:
masqueradeAll: false
masqueradeBit: 14
minSyncPeriod: 0s
syncPeriod: 30s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
确保节点中存在虚拟接口,默认为 kube-ipvs0
将服务 IP 地址绑定到虚拟接口
分别为每个Service IP地址创建IPVS虚拟服务器
1:创建svc
[root@node1 yaml]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-svc ClusterIP 10.233.3.41 80/TCP 33s
2:查看节点的kube-ipvs0网卡上是否会有svc的ip地址
[root@node1 yaml]# ip a| grep 10.233.3.41
inet 10.233.3.41/32 scope global kube-ipvs0
[root@node1 yaml]#
3:查看ipvs规则
[root@node1 yaml]# ipvsadm -Ln | grep 10.233.3.41 -A 5
TCP 10.233.3.41:80 rr
-> 10.233.90.8:80 Masq 1 0 0
-> 10.233.92.29:80 Masq 1 0 0
-> 10.233.92.30:80 Masq 1 0 0
-> 10.233.96.26:80 Masq 1 0 0
-> 10.233.96.27:80 Masq 1 0 0
[root@node1 yaml]#
[root@node1 yaml]# ipvsadm -Ln | grep 10.233.3.41 -A 5
TCP 10.233.3.41:80 rr ####默认为rr
-> 10.233.90.8:80 Masq 1 0 0
-> 10.233.92.29:80 Masq 1 0 0
-> 10.233.92.30:80 Masq 1 0 0
-> 10.233.96.26:80 Masq 1 0 0
-> 10.233.96.27:80 Masq 1 0 0
访问流程:
与iptables、userspace 模式一样,kube-proxy 依然监听Service以及Endpoints对象的变化, 不过它并不创建反向代理, 也不创建大量的 iptables 规则, 而是通过netlink 创建ipvs规则,并使用k8s Service与Endpoints信息,对所在节点的ipvs规则进行定期同步; netlink 与 iptables 底层都是基于 netfilter 钩子,但是 netlink 由于采用了 hash table 而且直接工作在内核态,在性能上比 iptables 更优。其工作流程大体如下:
原文参考此处链接https://juejin.cn/post/7110243618182397982#heading-24