kubernetes里kube-proxy支持三种模式,在v1.8之前我们使用的是iptables 以及 userspace两种模式,在kubernetes 1.8之后引入了ipvs模式,并且在v1.11中正式使用,其中iptables和ipvs都是内核态也就是基于netfilter,只有userspace模式是用户态。下面详细介绍下各个模式:

kubernetes kube-proxy模式详解_第1张图片

userspace

在k8s v1.2后就已经被淘汰了,userspace的作用就是在proxy的用户空间监听一个端口,所有的svc都转到这个端口,然后proxy的内部应用层对其进行转发。proxy会为每个svc随机监听一个端口,并增加一个iptables规则,从客户端到 ClusterIP:Port 的报文都会被重定向到 Proxy Port,Kube-Proxy 收到报文后,通过 Round Robin (轮询) 或者 Session Affinity(会话亲和力,即同一 Client IP 都走同一链路给同一 Pod 服务)分发给对应的 Pod。所有流量都是在用户空间进行转发的,虽然比较稳定,但是效率不高。如下图为userspace的工作流程。

kubernetes kube-proxy模式详解_第2张图片

Iptables

iptables这种模式是从kubernetes1.2开始并在v1.12之前的默认模式。在这种模式下proxy监控kubernetes对svc和ep对象进行增删改查。并且这种模式使用iptables来做用户态的入口,而真正提供服务的是内核的Netilter,Netfilter采用模块化设计,具有良好的可扩充性。其重要工具模块IPTables从用户态的iptables连接到内核态的Netfilter的架构中,Netfilter与IP协议栈是无缝契合的,并允许使用者对数据报进行过滤、地址转换、处理等操作。这种情况下proxy只作为Controller。Kube-Proxy 监听 Kubernetes Master 增加和删除 Service 以及 Endpoint 的消息。对于每一个 Service,Kube Proxy 创建相应的 IPtables 规则,并将发送到 Service Cluster IP 的流量转发到 Service 后端提供服务的 Pod 的相应端口上。并且流量的转发都是在内核态进行的,所以性能更高更加可靠。

在这种模式下缺点就是在大规模的集群中,iptables添加规则会有很大的延迟。因为使用iptables,每增加一个svc都会增加一条iptables的chain。并且iptables修改了规则后必须得全部刷新才可以生效。

iptables 自定义几条链路:KUBE-SERVICES,KUBE-NODEPORTS,KUBE-POSTROUTING,KUBE-MARK-MASQ和KUBE-MARK-DROP五个链,并主要通过为 KUBE-SERVICES链(附着在PREROUTING和OUTPUT)增加rule来配制traffic routing 规则。


iptabels 模式下正常的通信链路:

在 PREROUTING的 chain里将 将经过PREROUTING里的数据包重定向到KUBE-SERVICES中

在自定义链kube-services里找到dst为目标地址的ip(ps:kube-services对于相同目标地址都有2给target,对于非pod之间的访问进入KUBE-MARK-MASQ,对于pod之间的访问进入KUBE-SVC-*里),找到对应的KUBE-SVC-*(ps:只有有对应endpoint信息的才有KUBE-SVC-*),并找到KUBE-SVC-*对应的KUBE-SEP-*。在SEP里会对source来自自身ip的打KUBE-MARK-MASQ,对于其他的做DNAT转换


IPVS

kubernetes从1.8开始增加了IPVS支持,IPVS相对于iptables来说效率会更加高,使用ipvs模式需要在允许proxy的节点上安装ipvsadm,ipset工具包加载ipvs的内核模块。并且ipvs可以轻松处理每秒 10 万次以上的转发请求。

当proxy启动的时候,proxy将验证节点上是否安装了ipvs模块。如果未安装的话将回退到iptables模式。

并在Kubernetes 1.12成为kube-proxy的默认代理模式。ipvs模式也是基于netfilter,对比iptables模式在大规模Kubernetes集群有更好的扩展性和性能,支持更加复杂的负载均衡算法(如:最小负载、最少连接、加权等),支持Server的健康检查和连接重试等功能。ipvs依赖于iptables,使用iptables进行包过滤、SNAT、masquared。ipvs将使用ipset需要被DROP或MASQUARED的源地址或目标地址,这样就能保证iptables规则数量的固定,我们不需要关心集群中有多少个Service了。


kubernetes kube-proxy模式详解_第3张图片

这种模式,Kube-Proxy 会监视 Kubernetes Service 对象 和 Endpoints,调用 Netlink 接口以相应地创建 IPVS 规则并定期与 Kubernetes Service 对象 和 Endpoints 对象同步 IPVS 规则,以确保 IPVS 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod。

以下情况下IPVS会使用iptables

IPVS proxier将使用iptables,在数据包过滤,SNAT和支持NodePort类型的服务这几个场景中。具体来说,ipvs proxier将在以下4个场景中回归iptables。

kube-proxy 启动项设置了 –masquerade-all=true

如果kube-proxy以--masquerade-all = true开头,则ipvs proxier将伪装访问服务群集IP的所有流量,其行为与iptables proxier相同


注:master节点上也需要进行kubelet配置。因为ipvs在有些情况下是依赖iptables的,iptables中KUBE-POSTROUTING,KUBE-MARK-MASQ, KUBE-MARK-DROP这三条链是被 kubelet创建和维护的, ipvs不会创建它们。

在kube-proxy启动中指定集群CIDR

如果kube-proxy以--cluster-cidr = 开头,则ipvs proxier将伪装访问服务群集IP的群集外流量,其行为与iptables proxier相同。

为LB类型服务指定Load Balancer Source Ranges

当服务的LoadBalancerStatus.ingress.IP不为空并且指定了服务的LoadBalancerSourceRanges时,ipvs proxier将安装iptables。

支持 NodePort type service

为了支持NodePort类型的服务,ipvs将在iptables proxier中继续现有的实现。

kubernetes中ipvs实现原理图:

kubernetes kube-proxy模式详解_第4张图片


为什么每个svc会在ipvs网卡增加vip地址:

由于 IPVS 的 DNAT 钩子挂在 INPUT 链上,因此必须要让内核识别 VIP 是本机的 IP。这样才会过INPUT 链,要不然就通过OUTPUT链出去了。k8s 通过设置将service cluster ip 绑定到虚拟网卡kube-ipvs0。

①因为service cluster ip 绑定到虚拟网卡kube-ipvs0上,内核可以识别访问的 VIP 是本机的 IP.

②数据包到达INPUT链.

③ipvs监听到达input链的数据包,比对数据包请求的服务是为集群服务,修改数据包的目标IP地址为对应pod的IP,然后将数据包发至POSTROUTING链.

④数据包经过POSTROUTING链选路,将数据包通过flannel网卡发送出去。从flannel虚拟网卡获得源IP.

⑤pod接收到请求之后,构建响应报文,改变源地址和目的地址,返回给客户端。


模拟ipvs模式:

新增DROP 链路 将svc地址即ipvs的vip地址为10.222.251.98的包丢弃

在指定的node节点执行

iptables -t filter -I INPUT -d 10.222.251.98 -j DROP

kubernetes kube-proxy模式详解_第5张图片

当该vip地址进入到这个input的链路的时候直接DROP 如下:

查看链路是否有包

watch -n 0.1 "iptables --line-number -nvxL INPUT"

kubernetes kube-proxy模式详解_第6张图片

因为当我们访问10.222.251.98这个地址的时候,ipvs会感知到这个ip是本机的vip地址,所以会线进入input的链路。所以我们在input增加了desc为10.222.251.98的DROP链路的话,会有限

之后恢复的话直接删除掉指定规则

iptables -D INPUT 1

ps: 1代表iptables -nL --line-number输出的行号

kubernetes kube-proxy模式详解_第7张图片