Erda 开源地址: https://github.com/erda-project/erda
Erda cloud 官网:Erda Cloud
kube-proxy概述
在kubernetes出现之前,我们通常会使用nginx,haproxy,甚至是lvs这些负载均衡技术来实现业务的服务均衡,需要专门的工程师去维护这些组件,当有业务节点上下线时,也需要人工的去进行相应的配置或者写一些自动化的脚本来处理这些变动。
kube-proxy是kubernetes提供的集群内的标准负载均衡方案,我们知道在kubernetes中pod是作为承载业务的小单元,并且pod的IP是动态分配的并且经常变化,需要在前面需要一个叫做service的东西,通过标签选择器和pod进行关联,实现pod的负载均衡。
kube-proxy部署在每个node节点上,它是实现service的通信与负载均衡机制的重要组件,kube-proxy负责为Pod创建代理服务,从apiserver获取所有server信息,并根据server信息创建代理服务,实现server到Pod的请求路由和转发,从而实现K8S层级的虚拟转发网络。
工作原理
从功能上看kube-proxy的工作模式很简单,从kubernetes-apiserver去获取service的信息,然后部署在每个node节点上的kube-proxy组件来创建对应的负载均衡策略,实现pod的负载均衡。
kube-proxy主流支持iptables和ipvs两种方式来创建负载均衡均衡策略,关于这两种方式的优缺点在其他文档应该都会介绍,这里稍作总结下:
- iptables模式不用额外安装任何组件,但是再service量大到一定量级的时候,会出现性能的严重损耗,主要以为随着iptables规则数的增加,其匹配规则的效率也会随之增加,因此适合小规模集群,Service数量在100以内。
- ipvs模式需要安装ipvsadm工具,利用ipvs内核模块实现DNAT,利用nf_conntrack/iptables实现SNAT,其查询效率不会随着serviec的数量的增加而降低。
这里也稍微蹭一个热点--eBPF, linux提供的内核虚拟机,为用户程序访问内核空间提供了可能,腾讯的TKE基于eBPF提供了ipvs-bpf的模式进一步优化了k8s service的性能。
cilium也出了一个"kubernetes without kube-proxy"的方案将eBPF技术用在了service上,相信在不久会出现很多eBPF的实现方案,甚至是成为kubernetes的默认行为。
iptables模式
先来看一个service的yaml文件,该svc创建了一个26880的端口映射,对应的后端服务的端口也是26880,我看看一下这个iptables的流量走向。
apiVersion: v1
kind: Service
metadata:
name: services-prod-6059-oms-api
namespace: default
spec:
clusterIP: 10.21.7.223
ports:
- name: http-0
port: 26880
protocol: TCP
targetPort: 26880
selector:
appid: 5d891e37-0ba3-42de-8495-c8c256734e05
sessionAffinity: None
type: ClusterIP
对应的pod IP如下:
比如我们要从某台节点通过ClusterIP:10.21.7.223访问对应的pod,那么它的数据包会在iptables中经过如下流转:
1, filter表通过OUTPUT链规定所有的出报文都要经过KUBE-SERVICES
2,数据包会交给nat表的KUBE-SERVICES链来处理,在KUBE-SERVICE链中我们可以找到对目的IP10.21.7.223的处理,会继续交由给KUBE-SVC-KLU3DS3WRPTYAOLU来处理
3,再来看看KUBE-SVC-KLU3DS3WRPTYAOLU的处理逻辑,会通过权重交由给如下两个链来处理,这里就是使用iptables来实现了负载均衡。
4,再看看KUBE-SEP链的内容,在该链中完成了终的DNAT,将目的地址转换成了POD的IP和端口
ipvs模式
跟iptables模式一样的是,kube-proxy依然监听service以及endpoint对象的变化,不一样的是这里不是创建大量的iptables规则,而是通过ipvsadm来创建ipvs规则。
这里我们一这个nexus的svc为例,该svc分别映射了3个端口,那么对应的也会创建三条不同的ipvs规则
apiVersion: v1
kind: Service
metadata:
name: addon-nexus
namespace: default
spec:
clusterIP: 10.99.100.18
ports:
- name: addon-nexus-tcp-8081
port: 8081
protocol: TCP
targetPort: 8081
- name: addon-nexus-tcp-5000
port: 5000
protocol: TCP
targetPort: 5000
- name: addon-nexus-tcp-5500
port: 5500
protocol: TCP
targetPort: 5500
selector:
dice/addon: addon-nexus
sessionAffinity: None
type: ClusterIP
在平时的故障排查过程中,比如遇到svc不通的时候,我们可以先查看对应的ipvs是不是被正确创建了,如果对应的IP不对,那应该就是kube-proxy没有在正常工作了,可以去查看下对应的kube-proxy日志,如果规则都是被正确创建了,那么应该就是容器网络的问题了,可以继续再去查看对应节点上的网络组件是否健康,以及对应的组件日志。