[TOC]
本节我们主要介绍一下Kube-proxy在IPVS模式下,数据包的转发流程。
### **IPVS的模式**
在kube-proxy中,实际上使用的是IPVS的NAT模式。
### **ClusterIP的转发**
我们知道,IPVS模块其实是在netfilter框架的NF_INET_LOCAL_IN钩子处注册了一个钩子函数,而且这个函数的优先级是最高的,也就是每一个到达该钩子处的数据包,最先都是由IPVS的钩子函数进行处理。如果IPVS对数据包做了DNAT,那么就会把数据包发送到NF_INET_POST_ROUTING去。
当我们在容器里通过`ClusterIP:Port`访问Service时,那么数据包在K8S主机上的流程应该是:`NF_INET_PRE_ROUTING -> 路由选择 -> NF_INET_LOCAL_IN`。在NF_INET_LOCAL_IN处,由IPVS模块注册的钩子函数进行DNAT的处理。
数据包要到达NF_INET_LOCAL_IN,那么在路由选择的时候,这个数据包的目的地址要是本机IP。我们知道,这个数据包从容器里出来的时候,目的IP就是Service的ClusterIP,在NF_INET_PRE_ROUTING处由于不再做DNAT,所以目的地址是不会变的。那么如何识别ClusterIP为本机IP呢?
其实,当启用IPVS模式时,kube-proxy会在本机上创建一个名为`kube-ipvs0`的网卡,每创建一个Service,kube-proxy都会把Service的ClusterIP设置在这个网卡上。
如下,集群中有两个Service,ClusterIP分别为10.96.0.1和10.96.0.10,然后我们查看ipvs0网卡的信息,发现刚好有这两个IP
```
$ kubectl get service --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 86m
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 86m
$ ip addr show kube-ipvs0
11: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
link/ether 3e:11:b4:33:0d:a8 brd ff:ff:ff:ff:ff:ff
inet 10.96.0.1/32 brd 10.96.0.1 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.96.0.10/32 brd 10.96.0.10 scope global kube-ipvs0
valid_lft forever preferred_lft forever
```
### **NodePort的转发**
我们在K8S集群中发布一个Deployment,它有两个Pod,然后为其创建一个NodePort的Service,如下:
```
$ kubectl get node
NAME STATUS ROLES AGE VERSION
192.168.2.102 Ready master 108m v1.17.3
192.168.2.103 Ready <none> 108m v1.17.3
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tomcat-565cd88dc7-ddvk4 1/1 Running 0 4m31s 172.26.190.194 192.168.2.103 <none> <none>
tomcat-565cd88dc7-v542c 1/1 Running 0 4m31s 172.26.190.193 192.168.2.103 <none> <none>
$ kubectl get service tomcat
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
tomcat NodePort 10.105.6.182 <none> 8080:30230/TCP 98s
```
两个Pod在103主机上。接下来我们来分析一下,当我们从外部通过主机IP+NodePort(192.168.2.102:30230)来访问时,数据包在102主机上的流程。
数据包在102主机上的流程如下:
```
NF_INET_PRE_ROUTING -> 路由选择 -> NF_INET_LOCAL_IN(IPVS做DNAT) -> NF_INET_POST_ROUTING(SNAT)
```
数据包首先到达NF_INET_PRE_ROUTING处,在nat表的PREROUTING链中的KUBE-SERVICES链下有如下规则:
```
$ iptables -t nat -nL KUBE-SERVICES
Chain KUBE-SERVICES (2 references)
target prot opt source destination
...
KUBE-NODE-PORT all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
...
$ iptables -t nat -nL KUBE-NODE-PORT
Chain KUBE-NODE-PORT (1 references)
target prot opt source destination
KUBE-MARK-MASQ tcp -- 0.0.0.0/0 0.0.0.0/0 /* Kubernetes nodeport TCP port for masquerade purpose */ match-set KUBE-NODE-PORT-TCP dst
$ iptables -t nat -nL KUBE-MARK-MASQ
Chain KUBE-MARK-MASQ (10 references)
target prot opt source destination
MARK all -- 0.0.0.0/0 0.0.0.0/0 MARK or 0x4000
$ ipset list KUBE-NODE-PORT-TCP
Name: KUBE-NODE-PORT-TCP
Type: bitmap:port
Revision: 3
Header: range 0-65535
Size in memory: 8268
References: 1
Number of entries: 1
Members:
30230
```
从上面可以看出,当访问102主机的NodePort时,在NF_INET_PRE_ROUTING处,数据包会被打上一个标记(0x4000),然后经过路由选择进入到NF_INET_LOCAL_IN处,在这里IPVS模块的钩子函数对数据包进行DNAT操作,然后再把数据包投递到NF_INET_POST_ROUTING处。
我们来看一下nat表的POSTROUTING链中的规则,如下:
```
$ iptables -t nat -nL POSTROUTING
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
...
KUBE-POSTROUTING all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes postrouting rules */
...
$ iptables -t nat -nL KUBE-POSTROUTING
Chain KUBE-POSTROUTING (1 references)
target prot opt source destination
MASQUERADE all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
...
```
从上面的iptables规则可以看出,在NF_INET_POST_ROUTING钩子处,数据包由于有标记0x4000,所以它会做一个Masqurade源地址转换。
### **IPVS的优点**
相对于iptables,IPVS具有如下的优点:
* 支持多种负载均衡策略
iptables只支持随机策略,而ipvs支持轮询、加权等多种策略
* 支持虚拟服务器的健康检测与重试机制
how?
* 对于大规模集群,性能更好
iptables的规则在内核中是链表的形式存在,kube-proxy更新iptables规则都是做全量更新。如果Service和Pod数量过大,更新时间会过长,导致iptables锁住。
ipvs规则在内核中是以哈希表的形式存在, kube-proxy更新规则为增量更新,更新的时间复杂度为O(1)。
可参考以下文章
https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md
https://zhuanlan.zhihu.com/p/37230013
### **FAQ**
**Q:什么时候应该选择iptables模式,什么时候应该选择ipvs模式?**
A:参考 https://docs.ucloud.cn/uk8s/introduction/kubeproxy_mode
**Q: IPVS如何支持健康检测与重试机制?**
### **参考**
* https://docs.ucloud.cn/uk8s/introduction/kubeproxy\_mode
- 应用层
- HTTP
- Cookie
- Session
- HTTP报文格式
- HTTP的Header字段
- HTTPS
- 简介
- 原理
- RSA加密与解密
- 证书签名与验证
- TLS双向认证
- openssl命令汇总
- DNS
- DNS的记录类型
- DNS的报文格式
- FAQ
- 传输层
- TCP
- CloseWait
- 网络层
- IPv6
- 链路层
- 链接层基础知识
- VLAN
- FAQ
- Linux网络收发包
- 网卡收包
- 网卡发包
- 收发包FAQ
- LVS
- 安装-DR模式
- 基本原理
- Ipvsadm命令
- Netfilter
- Netfilter简介
- 注册钩子函数
- Netfilter中数据包流向
- Iptables的数据结构
- 连接跟踪
- 初识连接跟踪
- 连接跟踪详解
- 连接跟踪数据结构
- 数据包与连接的状态
- NAT
- IPVS
- KubeProxy的IPVS模式
- Linux虚拟网络设备
- 虚拟网络设备简介
- Tap
- VethPair
- Vlan
- Vxlan
- Flannel的VXLAN原理
- Openstack的VXLAN原理
- VXLAN总结
- Bridge
- 给容器设置主机网段IP
- Macvlan
- Ipvlan
- IPIP
- IPIP使用介绍
- IPIP源码分析
- Limdiag网络
- 详细设计
- kubeovn
- IP命令
- Calico
- Calico常见问题
- ARP无响应
- 其他