k8s

kube-proxy总结

背景

下面我将以这个思维导图来总结一下kube-proxy。
file

简介

  • 每台机器上都运行一个 kube-proxy 服务,它监听 API server 中 service 和 endpoint 的变化情况,并通过内核的iptables等来为服务配置负载均衡(仅支持TCP 和 UDP)。因为内核有一定的nat能力,内核只解析tcp或者udp的包头,不会解析用户数据,这是用户态去干的事情。
  • kube-proxy 可以直接运行在物理机上,也可以以 static pod 或者 DaemonSet 的方式运行。
    file

实现方式

kube-proxy 当前支持一下几种实现:

  • userspace:最早的负载均衡方案,它在用户空间监听一个端口,所有服务通过 iptables 转发到这个端口,然后在其内部负载均衡到实际的 Pod。该方式最主要的问题是效率低,有明显的性能瓶颈。
  • iptables:目前推荐的方案,完全以iptables 规则的方式来实现 service 负载均衡。该方式最主要的问题是在服务多的时候产生太多的 iptables 规则,非增量式更新会引入一定的时延,大规模情况下有明显的性能问题。
  • ipvs:为解决 iptables 模式的性能问题,v1.8 新增了 ipvs 模式,采用增量式更新,并可以保证 service更
    新期间连接保持不断开。
  • winuserspace:同 userspace,但仅工作在 windows上。

kube-proxy工作原理

  • 首先kube-proxy会watch apiserver。监听到svc后,如果工作在iptables模式,就可以通过iptables配置dnat规则。
  • 用户访问serviceip也就是clusterip,数据包会转发到目标pod。

file

Netfilter

当一个数据包被操作系统接收到后,内核在处理这个数据包会经过哪些流转,这个流转的框架叫做Netfilter。

  • 网卡在链路层接收到数据包后,如果是本机的有效数据包,它会把包发送到Netfilter框架。也就是SKBuffer,在linux中代表数据包的数据结构。
  • SKBuffer会被网络层处理,在处理中,Netfilter提供了很多hook点。即在用户态配置规则,Netfilter解析这些规则,来实现对应的行为。比如转换地址,防火墙规则等。图中绿色框就是hook点。
  • 网络层首先是routing decison。它会看数据包的五元组(源IP地址,源端口,目的IP地址,目的端口和传输层协议),如果目标地址是本机地址,它就会把包转发到local process进行处理。
  • 如果不是本机地址,那么就会把包转发forward。
  • 经过nat转换地址后把数据包发送出去output。

file

Netfilter 和 iptables

通过配置用户态规则,实现访问service的clusterip。用户访问clusterip,就是通过kube-proxy配置的nat规则转发到了后端pod中。

  • 内核态中网卡接收到数据包,会发起一个硬件中断,告诉cpu我这边接收到数据包了。cpu响应硬件中断后,会发起一个软中断。ksoftirqd就是用来处理软中断的。
    file
  • cpu调用SoftIRQ Handler处理数据包。网卡驱动会把数据包存到内存中,SoftIRQ从内存中读取数据包,构造SKB,SKBuffer包含了用户数据和header,header就是数据包的五元组信息。
  • 然后SoftIRQ会把SKBuffer交给Netfilter来处理。
  • Netfilter会去用户态读取配置的iptables规则,如果数据包匹配,那么执行对应的action。一般是修改目标地址。

file

iptables

  • PREROUTING:数据包在经过路由判断之前的操作。支持raw,magle,dnat表。
  • LOCAL_IN:经过路由判断,如果是本机,就会转发到LOCAL_IN的hook点,接着被本地进程处理。支持mangle,filter,snat表。
  • FORWARD:如果不是本机,就会转发到FORWARD。支持mangle,filter表。
  • LOCAL OUT:本地进程处理完后,转发到LOCAL OUT。支持raw,mangle,dnat,filter,snat表。
  • POSTROUTING:再经过路由判断后,转发到POSTROUTING链,数据包就转发出去了。支持mangle,snat表。

针对kube-proxy,要实现的是修改目标地址,也就是dnat,在PREROUTING和LOCAL OUT可以实现。

file

hook点

raw:优先级最高,可以对数据包在路由前进行处理。决定数据包是否被状态跟踪机制处理。
mangle:修改数据包的服务类型、TTL。
nat:负载均衡规则。转换数据包地址。包括sant和dnat。
filter:防火墙规则。过滤数据包。
file

iptables实践

我这里有3个nginx的pod。pod,svc,ep的ip如下:

file

iptables-save -t nat
或者 iptables -L -t nat

找nginx svc的ip 10.96.180.103的iptables规则。

-A KUBE-SVC-P4Q3KNUAWJVP4ILH ! -s 10.100.0.0/16 -d 10.96.180.103/32 -p tcp -m comment --comment "default/nginx:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
# KUBE-SERVICES链,如果数据包目标地址是10.96.180.103/32,协议是tcp,目标端口是80,那么执行KUBE-SVC-P4Q3KNUAWJVP4ILH这个动作。
-A KUBE-SERVICES -d 10.96.180.103/32 -p tcp -m comment --comment "default/nginx:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-P4Q3KNUAWJVP4ILH

看KUBE-SVC-P4Q3KNUAWJVP4ILH具体实现。

# 是一个chain。
:KUBE-SVC-P4Q3KNUAWJVP4ILH - [0:0] 
# 标记
-A KUBE-SVC-P4Q3KNUAWJVP4ILH ! -s 10.100.0.0/16 -d 10.96.180.103/32 -p tcp -m comment --comment "default/nginx:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
# 以33%的几率执行KUBE-SEP-646EWZKVGRBBVGL3动作。
-A KUBE-SVC-P4Q3KNUAWJVP4ILH -m comment --comment "default/nginx:http" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-646EWZKVGRBBVGL3
# 如果上面的规则不符合,则以50%的几率执行KUBE-SEP-CMLKHPEE3WJCPCDF动作。
-A KUBE-SVC-P4Q3KNUAWJVP4ILH -m comment --comment "default/nginx:http" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CMLKHPEE3WJCPCDF
# 如果上面的规则不符合,则以100%的几率执行KUBE-SEP-WDHV5LTXWGDX4S67动作。
-A KUBE-SVC-P4Q3KNUAWJVP4ILH -m comment --comment "default/nginx:http" -j KUBE-SEP-WDHV5LTXWGDX4S67

分别查看具体动作。

# KUBE-SEP-646EWZKVGRBBVGL3
-A KUBE-SEP-646EWZKVGRBBVGL3 -s 10.100.104.49/32 -m comment --comment "default/nginx:http" -j KUBE-MARK-MASQ
# 执行dnat动作,修改目标地址为10.100.104.49,即node2。
-A KUBE-SEP-646EWZKVGRBBVGL3 -p tcp -m comment --comment "default/nginx:http" -m tcp -j DNAT --to-destination 10.100.104.49:8080

# KUBE-SEP-CMLKHPEE3WJCPCDF
-A KUBE-SEP-CMLKHPEE3WJCPCDF -s 10.100.166.189/32 -m comment --comment "default/nginx:http" -j KUBE-MARK-MASQ
# 如果node2不符合,修改目标地址为10.100.166.189,即node1。
-A KUBE-SEP-CMLKHPEE3WJCPCDF -p tcp -m comment --comment "default/nginx:http" -m tcp -j DNAT --to-destination 10.100.166.189:8080

# KUBE-SEP-WDHV5LTXWGDX4S67
-A KUBE-SEP-WDHV5LTXWGDX4S67 -s 10.100.219.102/32 -m comment --comment "default/nginx:http" -j KUBE-MARK-MASQ
# 如果node2也不符合,修改目标地址为10.100.219.102,即master。
-A KUBE-SEP-WDHV5LTXWGDX4S67 -p tcp -m comment --comment "default/nginx:http" -m tcp -j DNAT --to-destination 10.100.219.102:8080

由于iptables规则是从上到下执行的,所以到nginx的请求,会依次从33%,50%,100%的几率去转发到目标pod。

查看KUBE-SERVICES链

:KUBE-SERVICES - [0:0]
# 把KUBE-SERVICES链加到了PREROUTING和OUTPUT链的hook点里。也就是说所有进来的和出去的数据包都要经过KUBE-SERVICES处理。
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES

k8s iptables数据转发

  • 外部请求或者本地pod访问nginx服务,首先都要经过KUBE-SERVICES链。
  • -d:目标clusterip地址,–dport:目标端口。
    -A KUBE-SERVICES -d 10.96.180.103/32 -p tcp -m comment --comment "default/nginx:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-P4Q3KNUAWJVP4ILH
    # KUBE-SVC-P4Q3KNUAWJVP4ILH,SVC后面的P4Q3KNUAWJVP4ILH是由port,protocol经过hash所得。
  • 然后先经过KUBE-MARK-MASQ链标记。
    -A KUBE-SVC-P4Q3KNUAWJVP4ILH ! -s 10.100.0.0/16 -d 10.96.180.103/32 -p tcp -m comment --comment "default/nginx:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
    # 给数据包打上0x4000/0x4000的标记,如果数据包标记是0x8000/0x8000则丢弃。
    -A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
    -A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
  • 再根据后端pod的数量,根据负载均衡算法选择pod。(–mode random –probability )
    -A KUBE-SVC-P4Q3KNUAWJVP4ILH -m comment --comment "default/nginx:http" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-646EWZKVGRBBVGL3
  • 根据DNAT规则,转发到目标pod。(DNAT –to-destination)
    -A KUBE-SEP-646EWZKVGRBBVGL3 -p tcp -m comment --comment "default/nginx:http" -m tcp -j DNAT --to-destination 10.100.104.49:8080
  • 数据转发出去,经过POSTROUTING,再到KUBE-POSTROUTING。
    -A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
  • 最后经过MASQUERADE链。是用发送数据包的网卡IP来替换源IP。
    -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE
  • 再由CNI转发出去。
    # 源地址类型是local,伪装源地址为vxlan.calico的地址
    -A cali-POSTROUTING -o vxlan.calico -m comment --comment "cali:B61PPpOLVc6B1IiX" -m addrtype ! --src-type LOCAL --limit-iface-out -m addrtype --src-type LOCAL -j MASQUERADE
    -A cali-nat-outgoing -m comment --comment "cali:Dw4T8UWPnCLxRJiI" -m set --match-set cali40masq-ipam-pools src -m set ! --match-set cali40all-ipam-pools dst -j MASQUERADE

    file

file

svc的ip只是在iptables判断用,只是一条规则。

file

ipvs

iptables的缺点

  • iptables对于任何负载均衡配置,都需要很多规则去堆叠。
  • iptables转发数据包时根据rr,weight等,在后端有非常多pod时效率不高。
  • 当更新iptables规则时,kube-proxy会把原来的iptables删除,再重新刷,开销非常大,可能导致有的进程饿死。

ipvs的特点

  • 不支持PREROUTING的hook点。
  • 在经过路由判断后,如果是本机的话,访问的地址还是clusterip地址,这就需要把clusterip地址绑定到dummy设备上,这样才会把这个ip当成一个本地有效的ip。

file

iptables转换到ipvs

ks edit cm kube-proxy
mode: "ipvs"
ks delete po kube-proxy-7qr4k
yum -y install ipvsadm
ip a
ipvsadm -L -n

file

file

file

查看nginx服务

file

分类: k8s
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x