K8S学习总结-容器网络部分
flannel.1作为vtep设备,它开始检查这个二层数据包的头部,从中取出目的mac地址,通过查一个叫FDB的转发数据库(这个数据库也是flannel插件负责维护的)发现,发往这个目的mac地址(d2:9e:64:59:8e:b7)的二层包,应该再次封装起来并发送到这个IP地址上去(172.16.72.131)(这是我虚拟机的另一块网卡的地址,我也不知道为啥它没有用192.168.160.0/2
实验环境
三台机器:
k8s-node1(master) 192.168.160.100
k8s-node2 192.168.160.101
k8s-node3 192.168.160.102
使用flannel作为CNI插件
可以看到三台机器上均启动了flannel的pod,并且是underlay网络的IP
题外话:在node1上执行
docker network inspect host
执行结果如下(部分)
"Containers": {
"0442925333be250e582373b4dcc2ba8b4a1088b7fefb9e4f287b3c8e1cd80593": {
"Name": "k8s_POD_kube-proxy-s6p88_kube-system_4a0a0f63-55c8-43ae-bce4-a496b7259838_0",
"EndpointID": "40f544f35972a3687ae538a7fd5b123335772b602bafb4235ffb69f9035673b1",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"06b310fd523e2f9b49197abbf9639c43f677d29751da6c4d8079278a873390db": {
"Name": "k8s_POD_kube-apiserver-k8s-node1_kube-system_38bda722457b17ab2ebc654f82420f08_0",
"EndpointID": "bdbb4f449088f21ba32e32e88ec18ba4fe2cc63233a24471bfb534959df1feae",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"2ee0b69236ea678b762e8b5fb1f0278966252d03d96130fb02908ec7cb52ad2b": {
"Name": "k8s_POD_kube-flannel-ds-bpql8_kube-flannel_8dc98c07-372d-4781-b264-bcd4cdd63985_0",
"EndpointID": "67e2c2c334d05b6f38800e4ac747447e8f8ec4a44171faa42876c9021969d956",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"81d95cc95a74fa2a1cec067c70f622edc77a3067d08e876e963e6122d11e3e7e": {
"Name": "k8s_POD_kube-controller-manager-k8s-node1_kube-system_493b532aa92c7d1a56b6dca84c122114_0",
"EndpointID": "9d7ed44e54026e4ecc48929453e0d046ca3a8e40f5d02bab13371c42006ccdf0",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"a708e5e6724700a7ccfb9ef18c72cf9bc54d07fe576d25761fa9514dc9dc326c": {
"Name": "k8s_POD_kube-scheduler-k8s-node1_kube-system_ca407226d422080450a509199bd93321_0",
"EndpointID": "dc10f98b6e38a13a97370667a8efe98c167629782212432740aed0b167d4890f",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"a7cac47848f3c4feb5181a5a319d6a07e273a507f82312b2f9903de6e2742a0b": {
"Name": "k8s_POD_etcd-k8s-node1_kube-system_1c88d3224d351be3d744f64c84f93046_0",
"EndpointID": "67bce75b956c25b610a58219fc096524922fb73e33bc8658a7777cc55d798788",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
}
可以看到master节点上的kube-proxy、kube-apiserver、flannel、kube-controller-manager、kube-scheduler、etcd这些组件用的都是host网络,也就是说他们都共享了master节点的underlay网络栈
同一台宿主机上的Pod通信
使用以下yaml将两个测试pod部署到同一个主机上
apiVersion: v1
kind: Pod
metadata:
name: network-test-1
spec:
containers:
- name: net-tools
image: donch/net-tools
nodeSelector:
kubernetes.io/hostname: k8s-node2
---
apiVersion: v1
kind: Pod
metadata:
name: network-test-2
spec:
containers:
- name: net-tools
image: donch/net-tools
nodeSelector:
kubernetes.io/hostname: k8s-node2
可以看到node2上起了两个pod,overlay IP分别是10.244.1.9、10.244.1.10
进入其中的一个容器
查看网卡信息
查看宿主机(node2)上的网卡信息
解释一下,容器和宿主机之间的网络通信使用的是一条虚拟的“网线”,学名veth pair,它一头插在容器的网络namespace中,叫eth0,另一头插在宿主机的cni0网桥上,叫做vethxxxxxx(如上图,分别就是两个容器的另一头)
cni0网桥,可以理解为宿主机虚拟出来的一个二层交换机,所以,现在两个容器都插在这个交换机上,也处于同一个子网中(10.244.1.0/24),所以他们是二层互通的,ping一下试试
通过traceroute也可以看到,中间没有经过任何一个网关设备,直接就送达了
路由表也可以看到 scope link 代表是本地链路
总结,在flannel作为CNI的容器网络下,每个宿主机上都会分配一个自己的子网,通过把宿主机上的容器通过“网线”(veth pair)插到“交换机”上(cni0),实现二层互通。
不同宿主机上的Pod通信
保持上一步的环境不变,通过以下yaml在node3上再起一个pod
apiVersion: v1
kind: Pod
metadata:
name: network-test-3
spec:
containers:
- name: net-tools
image: donch/net-tools
nodeSelector:
kubernetes.io/hostname: k8s-node3
当然也是能ping通的
这里,通过计算机网络的相关知识,我们知道,跨网段的网络通信,我们需要借助于网关
参考上一节打印出来的容器内路由表这一项
10.244.0.0/16 via 10.244.1.1 dev eth0
意思是,所有发往10.244.0.0/16这个网络的数据包,下一跳是10.244.1.1(让10.244.1.1来为我们转发),并且想要让它为我们转发的话,需要从eth0这个网口发出去,因为10.244.1.1和容器是二层互通的,可以直接通过arp获取到mac地址后,封装成二层数据帧从eth0丢出去,10.244.1.1就能收到啦
那么问题来了,这个10.244.1.1是谁呢?
通过宿主机的网卡列表可以看出,它就是cni0网桥,不过我一直觉得这个东西不好理解,怎么一个二层交换机还能有IP地址呢?所以更好的理解方式是,cni0是主机的一个虚拟网卡,这个网卡也插在了这个二层交换机上,所以这样看的话,是我们的宿主机扮演了网关,或者说路由器
承接上文,当容器发出的跨网段报文来到了宿主机上的时候,宿主机就开始路由转发了,那么我们就可以看下宿主机的路由表,看下这个报文会被怎么处理
根据路由匹配原则,报文应该匹配上了这一项
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
这个路由项的意思是,发往10.244.2.0/24这个网段的报文,下一跳是10.244.2.0,需要从flannel.1这个网卡发出去,而onlink表示下一跳是在链路上的,或者说下一跳是二层互通的
这里就有两个很奇怪的地方,首先,flannel.1网卡的作用是什么?其次,flannel.1网卡的地址是10.244.1.0,而下一跳地址是10.244.2.0,很明显这两个地址不在同一个网段,按道理来说不应该是在同一个链路上(二层互通),为什么会标识有onlink字样呢?
这就引出了flannel的一种overlay通信方式-vxlan
flannel-vxlan
继续上面的例子,数据包首先会经过操作系统协议栈,去构建一个二层的数据帧出来,然后再从指定的网卡丢出去。而理论上来说,不属于同一个网段的IP报文应该会被协议栈直接丢弃,但是由于onlink字段存在,它相当于告诉你别管什么在不在同一个网段,他们两就是二层互通的,强制地让协议栈走了一遍arp查询的过程。但你还别说,arp里面还真能查到这一条记录
而这条arp记录并不是靠arp广播获得的,而是node2的flannel插件启动的时候,自动向其他node的arp表里添加的,并且永不过期
所以,有了目的网卡的mac地址,一个二层的数据帧就可以被构造出来了,到这里,onlink的作用解释清楚了,下面就是vxlan开始发挥作用了。
根据上面的路由项,我们构建好的这个二层数据帧,应该从flannel.1这个网卡丢出去,通过ethtool可以看到,flannel.1网卡是一个vxlan网络的设备,叫VTEP。vxlan的思想简单概括一下就是,让一些本来并不是二层互通的设备能够互通,并且无感知地互通。原理就是将二层的数据帧外面再次封装成一个新的网络报文,而这个报文中的源IP和目的IP是直接可达的(不管是二层可达还是三层可达),进而实现在underlay网络(物理可达)中传递overlay数据。
flannel.1作为vtep设备,它开始检查这个二层数据包的头部,从中取出目的mac地址,通过查一个叫FDB的转发数据库(这个数据库也是flannel插件负责维护的)发现,发往这个目的mac地址(d2:9e:64:59:8e:b7)的二层包,应该再次封装起来并发送到这个IP地址上去(172.16.72.131)(这是我虚拟机的另一块网卡的地址,我也不知道为啥它没有用192.168.160.0/24这个网段的网卡,不过都一样,没区别)
于是vtep设备根据以上信息,再次封装了一个二层数据帧,然后从ens160这个网卡丢了出去,而这个网卡就是underlay网络的网卡了,这个一层套着一层的数据帧,通过underlay网络,就来到了node3的ens160网卡上,也就是172.16.72.131这个IP对应的网卡。
node3的主机协议栈拆开了最外面的二层数据帧,发现里面是vxlan报文,也就是说这个数据帧还藏着一个二层数据帧,于是主机协议栈根据其中的vxlan标识信息(此文略)把里面藏着的二层数据帧交到了node3上的flannel.1网卡,也就是node3上面的vtep设备。
下面的过程就是,flannel.1再把这个二层数据帧给拆开,拿出了里面的IP报文,然后根据路由表信息,把这个报文送到了node3上的cni0网桥,最后来到了目标pod,完成的一次跨宿主机的单向通信,而反过来的通信过程是一模一样的,就不过多赘述了。
更多推荐
所有评论(0)