【理解云容器网络】4-kube-proxy的ipvs和iptables转发原理介绍
kube-proxy介绍
kube-proxy 是 kubernetes 工作节点上的一个网络代理组件,运行在每个节点上。主要维护节点上的网络规则,实现了Kubernetes Service 资源的转发功能 。kube-proxy与kube-apiserver交互,通过watch机制会根据 service 和 endpoints ,node资源对象的改变来实时刷新iptables或者ipvs规则。使发往 Service 的流量(通过ClusterIP和NodePort)负载均衡到正确的后端Pod。
kube-proxy包含2种模式:iptables(现在集群默认模式),ipvs模式。
kube-proxy的工作流程图:
kube-proxy的iptables模式解析
在 iptables 模式下,kube-proxy 使用了 iptables 的 filter 表和 nat 表,并对 iptables 的链进行了扩充,自定义了 KUBE-SERVICES、KUBE-EXTERNAL-SERVICES、KUBE-NODEPORTS、KUBE-POSTROUTING、KUBE-MARK-MASQ、KUBE-MARK-DROP、KUBE-FORWARD 七条链,另外还新增了以“KUBE-SVC-xxx”和“KUBE-SEP-xxx”开头的数个链,除了创建自定义的链以外还将自定义链插入到已有链的后面以便劫持数据包。kubernetes 自定义链中数据包的详细流转可以参考:
iptables规则分析
-
创建一个nodePort模式的服务,编辑nginx.yaml文件
apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx:latest name: nginx --- apiVersion: v1 kind: Service metadata: labels: app: nginx name: nginx-clusterip spec: ports: - name: service0 port: 8080 # 访问Service的端口 protocol: TCP # 访问Service的协议,支持TCP和UDP targetPort: 80 # Service访问目标容器的端口, selector: # 标签选择器,Service通过标签选择Pod app: nginx type: ClusterIP # Service的类型,ClusterIP表示在集群内访问
-
创建资源
kubectl apply -f nginx.yaml
-
分析规则
- 当外部访问流量到达nat表的PREROUTING之后,会直接转发到KUBE-SERVICES链
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
- 当访问为nodeport模式,会先转发到KUBE-NODEPORTS链路。 如果是clusterip模式,访问端口为8080时,KUBE-SERVICES链会直接将流量转发到KUBE-SVC-T2QWCYCETO7AA6KW链路
-A KUBE-SERVICES -d 10.247.113.122/32 -p tcp -m comment --comment "default/nginx-nodeport:service0 cluster IP" -m tcp --dport 8080 -j KUBE-SVC-T2QWCYCETO7AA6KW
- 当访问为nodeport的模式的访问端口为30000时,会转发到KUBE-SVC-T2QWCYCETO7AA6KW
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-nodeport:service0" -m tcp --dport 30000 -j KUBE-SVC-T2QWCYCETO7AA6KW
- 为KUBE-SVC-T2QWCYCETO7AA6KW设置mark标记并转发到KUBE-SEP-3VVHC7Z7YJ3BXNLY和KUBE-SEP-3PMMNXVLLGRL5AFT链路。(mark标记可以用于后续的路由、过滤等操作)
-A KUBE-SVC-T2QWCYCETO7AA6KW -d 10.247.113.122/32 -p tcp -m comment --comment "default/nginx-nodeport:service0 cluster IP" -m tcp --dport 8080 -j KUBE-MARK-MASQ -A KUBE-SVC-T2QWCYCETO7AA6KW -p tcp -m comment --comment "default/nginx-nodeport:service0" -m tcp --dport 30000 -j KUBE-MARK-MASQ -A KUBE-SVC-T2QWCYCETO7AA6KW -m comment --comment "default/nginx-nodeport:service0" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-3VVHC7Z7YJ3BXNLY -A KUBE-SVC-T2QWCYCETO7AA6KW -m comment --comment "default/nginx-nodeport:service0" -j KUBE-SEP-3PMMNXVLLGRL5AFT
- 最后,会给KUBE-SEP链路打上mark标签并随机选择一条规则将流量转发到pod的ip地址和pod的端口。
-A KUBE-SEP-3PMMNXVLLGRL5AFT -s 10.10.80.74/32 -m comment --comment "default/nginx-nodeport:service0" -j KUBE-MARK-MASQ -A KUBE-SEP-3PMMNXVLLGRL5AFT -p tcp -m comment --comment "default/nginx-nodeport:service0" -m tcp -j DNAT --to-destination 10.10.80.74:80 -A KUBE-SEP-3VVHC7Z7YJ3BXNLY -s 10.10.186.67/32 -m comment --comment "default/nginx-nodeport:service0" -j KUBE-MARK-MASQ -A KUBE-SEP-3VVHC7Z7YJ3BXNLY -p tcp -m comment --comment "default/nginx-nodeport:service0" -m tcp -j DNAT --to-destination 10.10.186.67:80
在节点关闭ip_forward对clusterip访问影响
- 开源k8s:节点与Podip无法互通,容器ip之间无法互通,容器内无法访问clusterip和nodeport
- CCE:节点与Podip可以互通,容器之间可以互通,容器内无法访问clusterip和nodeport
容器内访问其他ip时链表走向
- 开源k8s:容器内访问podip、其他节点和clusterip时,从容器网络命名空间进入宿主机网络命名空间后,先进入宿主机的PREROUTING链
- CCE:容器内访问其他节点pod ip、其他节点和clusterip时,从容器网络命名空间进入宿主机网络命名空间后,先进入宿主机的OUTPUT链,访问本节点pod不经过链表,访问本节点链路走线是:OUTPUT->POSTROUTING->PREROUTING->INPUT
kube-proxy的ipvs模式解析
ipvs大致原理说明
kube-proxy ipvs 模式的原理与实现:ipvs (IP Virtual Server) 是基于 Netfilter 的,作为 linux 内核的一部分实现了传输层负载均衡,ipvs 集成在LVS(Linux Virtual Server)中,它在主机中运行,并在真实服务器集群前充当负载均衡器。ipvs 可以将对 TCP/UDP 服务的请求转发给后端的真实服务器。Netfilter为包过滤提供了5个Hook点,IPVS用到的Hook是LOCAL_IN、FORWARD和LOCAL_OUT。
ipvs大致工作流程如下:
- 当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间,经过PREROUTING链;
- PREROUTING链首先会接收到用户请求,判断目标IP确定是本机IP,将数据包发往INPUT链;
- ipvs工作于内核空间的INPUT链上,当用户请求到达INPUT时,IPVS会将用户请求和自己已定义好的集群服务进行比对,如果用户请求的就是定义的集群服务,那么此时IPVS会强行修改数据包里的目标IP地址及端口,并将新的数据包发往FORWORD链;
- FORWORD链将数据将数据包发给POSTROUTING链,POSTROUTING链接收数据包后发现目标IP地址刚好是自己的后端服务器,那么此时通过选路,将数据包最终发送给后端的服务器
使用kube-proxy的ipvs模式
- 首先要加载 IPVS 所需要的 kernel module
modprobe -- ip_vs modprobe -- ip_vs_rr modprobe -- ip_vs_wrr modprobe -- ip_vs_sh modprobe -- nf_conntrack_ipv4 cut -f1 -d " " /proc/modules | grep -e ip_vs -e nf_conntrack_ipv4
- 在启动 kube-proxy 时,指定 proxy-mode 参数–proxy-mode=ipvs
- 如果要使用其他负载均衡算法,可以指定 --ipvs-scheduler= 参数,默认为 rr
kube-proxy ipvs模式大致流程说明
kube-proxy 在 ipvs 模式下自定义了八条链,分别为 KUBE-SERVICES、KUBE-FIREWALL、KUBE-POSTROUTING、KUBE-MARK-MASQ、KUBE-NODE-PORT、KUBE-MARK-DROP、KUBE-FORWARD、KUBE-LOAD-BALANCER ,由于 linux 内核原生的 ipvs 模式只支持 DNAT不支持 SNAT,所以kube-proxy的ipvs模式仍需要依赖iptables 规则。
- 数据包首先进入 PREROUTING或者OUTPUT链(取决于客户端位置)转到 KUBE-SERVICES 链
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
- 在 KUBE-SERVICES 链打标记
-A KUBE-SERVICES -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose" \ -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ -A KUBE-SERVICES -m set --match-set KUBE-CLUSTER-IP dst,dst -j ACCEPT # 其中 KUBE-CLUSTER-IP是一个clusteip ipset集合,使用ipset list KUBE-CLUSTER-IP 查看,里面存放所有服务clusterip -A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000 -A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
- 然后被ipvs的LOCAL_IN或者LOCAL_OUT钩住,在ipvs中处理转发关系,转发关系可以通过ipvsadm -ln查看
iptables和ipvs的对比
CCE当前支持iptables和IPVS两种服务转发模式,各有优缺点。
特性差异 | iptables | ipvs |
---|---|---|
定位 | 成熟稳定的kube-proxy代理模式,但性能一般,适用于Service数量较少(小于1000)或客户端会出现大量并发短连接的场景。 | 高性能的kube-proxy代理模式,适用于集群规模较大或Service数量较多的场景。 |
吞吐量 | 较小 | 较大 |
复杂度 | O(n) ,其中n随集群中服务和后端Pod的数量同步增长 | O(1),多数情况下IPVS的连接处理效率和集群规模无关 |
负载均衡算法 | 随机平等的选择算法 | 包含多种不同的负载均衡算法,例如轮询、最短期望延迟、最少连接以及各种哈希方法等 |
ClusterIP连通性 | 集群内部ClusterIP地址无法ping通 | 集群内部ClusterIP地址可以正常ping通 |
额外限制 | 当集群中超过1000个Service时,可能会出现网络延迟的情况 | Ingress和Service使用相同ELB实例时,无法在集群内的节点和容器中访问Ingress,因为kube-proxy会在ipvs-0的网桥上挂载LB类型的Service地址,Ingress对接的ELB的流量会被ipvs-0网桥劫持。建议Ingress和Service使用不同ELB实例 |
- 点赞
- 收藏
- 关注作者
评论(0)