Kubernetes中的网络通信
华子目录
- k8s通信整体架构
- 容器间通信
- `flannel`网络插件组成
- `flannel`跨`node主机`通信原理
- 什么是`fdb`
- `arp -n`
- `ip r`
- `flannel`支持的`后端模式`
- 更改`flannel`的默认模式
- `calico`网络插件
- `calico`简介
- `calico`网络架构
- 部署`calico`
k8s通信整体架构
k8s
通过cni
接口接入其他插件
来实现网络通讯
。目前比较流行的插件有flannel
,calico
等cni
插件存放位置:/etc/cni/net.d/10-flannel.conflist
插件
使用的解决方案
如下虚拟网桥
,虚拟网卡
,多个容器
共用一个虚拟网卡
进行通信
。多路复用
:MacVLAN
,多个容器
共用一个物理网卡
进行通信。硬件交换
:SR-LOV
,一个物理网卡
可以虚拟出多个接口
,这个性能最好
。
容器间通信
:- 同一个
pod
内的多个容器间
的通信
,通过lo
即可实现pod
之间的通信
同一node节点
的pod
之间通过cni
网桥转发数据包
不同node节点
的pod
之间的通信
需要网络插件支持
- 同一个
pod
和service
通信:通过iptables
或ipvs
实现通信
,ipvs
取代不了iptables
,因为ipvs
只能做负载均衡
,而做不了nat
转换pod
和外网通信
:iptables
的MASQUERADE
Service
与集群外部用户
的通信
;(ingress
、nodeport
、loadbalancer
)
[root@k8s-master net.d]# cat /etc/cni/net.d/10-flannel.conflist
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
容器间通信
- 同一个
pod
内的多个容器间
的通信
,通过lo
即可实现pod
之间的通信
同一node节点
的pod
之间通过cni
网桥转发数据包
不同node节点
的pod
之间的通信
需要网络插件支持
flannel
网络插件组成
插件 | 功能 |
---|---|
vxlan | 即Virtual Extensible LAN (虚拟可扩展局域网 ),是Linux 本身支持的一网络虚拟化技术 。VXLAN 可以完全在内核态 实现封装 和解封装 工作,从而通过“隧道 ”机制,构建出覆盖网络 (Overlay Network ) |
vtep | VXLAN Tunnel End Point (虚拟隧道端点 ),在Flannel 中vni 的默认值是1 ,这也是为什么宿主机的VTEP 设备都叫flannel.1 的原因 |
cni0 | 网桥设备 ,每创建一个pod 都会创建一对veth pair 。其中一端 是pod 中的eth0 ,另一端是cni0 网桥中的端口 (网卡 ) |
flannel.1 | TUN 设备(虚拟网卡 ),用来进行vxlan报文 的处理 (封包 和解包 )。不同node主机 之间的pod 数据流量 都从overlay设备 以隧道 的形式 发送到对端 |
flanneld | flannel 在每个主机 中运行flanneld 作为agent ,它会为所在主机 从集群 的网络地址空间 中,获取一个小 的网段subnet ,本主机内 所有容器 的IP地址 都将从中分配。同时Flanneld 监听K8s 集群数据库 ,为flannel.1 设备提供封装数据 时必要的mac、ip 等网络数据信息 |
flannel
跨node主机
通信原理
- 当
容器
发送IP包
,通过veth pair
发往cni0网桥
,再路由
到本机
的flannel.1
设备进行处理
VTEP
设备之间通过二层数据帧
进行通信
,源VTEP
设备收到原始IP包
后,在上面加一个目的MAC地址
,封装
成一个内部数据帧
,发送给目的VTEP
设备内部数据桢
,并不能
在宿主机
的二层网络
传输,Linux内核
还需要把它进一步封装
成为宿主机
的一个普通
的数据帧
,承载着内部数据帧
通过宿主机
的eth0
进行传输
Linux
会在内部数据帧
前面,加上一个VXLAN头
,VXLAN头
里有一个重要的标志
叫VNI
,它是VTEP
识别某个数据桢
是不是应该归自己
处理的重要标识
flannel.1
设备只知道另一端flannel.1
设备的MAC地址
,却不知道
对应的宿主机地址
是什么。在linux内核
里面,网络
设备进行转发的依据
,来自FDB
的转发数据库
,这个flannel.1网桥
对应的FDB信息
,是由flanneld进程
维护的linux内核
在IP包
前面再加上二层数据帧头
,把目标节点的MAC地址
填进去,MAC地址
从宿主机
的ARP表
获取- 此时
flannel.1设备
就可以把这个数据帧
从eth0
发出去,再经过宿主机网络
来到目标节点
的eth0设备
。目标主机内核网络栈
会发现这个数据帧
有VXLAN Header
,并且VNI
为1
,Linux内核
会对它
进行拆包
,拿到内部数据帧
,根据VNI
的值
,交给本机flannel.1
设备处理,flannel.1
拆包,根据路由表
发往cni网桥
,最后到达目标容器
什么是fdb
[root@k8s-master ~]# bridge fdb
01:00:5e:00:00:01 dev eth0 self permanent
33:33:00:00:00:01 dev docker0 self permanent
02:42:5a:2b:82:e1 dev docker0 vlan 1 master docker0 permanent
02:42:5a:2b:82:e1 dev docker0 master docker0 permanent
33:33:00:00:00:01 dev kube-ipvs0 self permanent
da:59:8b:26:3e:05 dev flannel.1 dst 172.25.254.20 self permanent
33:33:00:00:00:01 dev cni0 self permanent
a6:dd:38:df:df:5c dev cni0 vlan 1 master cni0 permanent
a6:dd:38:df:df:5c dev cni0 master cni0 permanent
a6:29:c3:54:b9:fe dev veth7f0d7ac0 master cni0
6a:f2:b6:53:9b:59 dev veth7f0d7ac0 vlan 1 master cni0 permanent
6a:f2:b6:53:9b:59 dev veth7f0d7ac0 master cni0 permanent
33:33:00:00:00:01 dev veth7f0d7ac0 self permanent
5a:d1:57:a3:cf:de dev vethda65673e master cni0
66:e3:ad:de:12:17 dev vethda65673e vlan 1 master cni0 permanent
66:e3:ad:de:12:17 dev vethda65673e master cni0 permanent
33:33:00:00:00:01 dev vethda65673e self permanent
这段命令输出是关于Linux
网络桥接(bridge
)的转发数据库
(FDB
, Forwarding Database)的信息
。在Linux
中,桥接
是一种将多个网络接口
连接在一起,使它们能够像单个网络接口一样工作的技术。FDB
用于存储
关于哪些MAC地址
可以通过哪些端口
(或接口)到达的信息
arp -n
[root@k8s-master ~]# arp -n
Address HWtype HWaddress Flags Mask Iface
10.244.0.3 ether 5a:d1:57:a3:cf:de C cni0
10.244.0.2 ether a6:29:c3:54:b9:fe C cni0
10.244.2.0 ether da:59:8b:26:3e:05 CM flannel.1
172.25.254.10 ether 00:0c:29:db:48:d7 C eth0
172.25.254.1 ether 00:50:56:c0:00:08 C eth0
172.25.254.2 ether 00:50:56:e1:a6:ed C eth0
10.244.1.0 ether 86:d8:ba:15:b9:0f CM flannel.1
172.25.254.20 ether 00:0c:29:96:e7:67 C eth0
ip r
[root@k8s-master ~]# ip r
default via 172.25.254.2 dev eth0 proto static metric 100
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.25.254.0/24 dev eth0 proto kernel scope link src 172.25.254.100 metric 100
flannel
支持的后端模式
网络模式 | 功能 |
---|---|
vxlan | 报文封装 ,默认模式 |
Directrouting | 直接路由 ,跨网段 使用vxlan ,同网段 使用host-gw 模式 |
host-gw | 主机网关 ,性能好 ,但只能 在二层网络 中,不支持跨网络 ,如果有成千上万 的Pod ,容易产生广播风暴 ,不推荐 |
UDP | 性能差 ,不推荐 |
更改flannel
的默认模式
[root@k8s-master ~]# kubectl -n kube-flannel edit cm kube-flannel-cfg
如果是host-gw
模式,则cni
会直接接到宿主机的eth0
上
#删除之前模式的pod,它会重新自动创建新的pod
[root@k8s-master ~]# kubectl -n kube-flannel delete pods --all
pod "kube-flannel-ds-m7ksl" deleted
pod "kube-flannel-ds-q55gr" deleted
pod "kube-flannel-ds-twvv4" deleted
#我们发现接到`宿主机的eth0`上了
[root@k8s-master ~]# ip r
default via 172.25.254.2 dev eth0 proto static metric 100
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 172.25.254.10 dev eth0
10.244.2.0/24 via 172.25.254.20 dev eth0
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.25.254.0/24 dev eth0 proto kernel scope link src 172.25.254.100 metric 100
calico
网络插件
官网
:https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises
calico
简介
纯三层
的转发
,中间
没有任何的NAT
和overlay
,转发效率
最好Calico
仅依赖三层路由
可达。Calico
较少的依赖性
使它能适配
所有VM
、Container
、白盒
或者混合环境场景
calico
网络架构
Felix
:监听etcd
中心的存储获取
事件,用户创建pod
后,Felix
负责将其网卡
、IP
、MAC
都设置好
,然后在内核
的路由表
里面写一条
,注明
这个IP
应该到这张网卡
。同样如果用户
制定了隔离策略
,Felix
同样会将该策略
创建到ACL
中,以实现隔离
。BIRD
:一个标准
的路由程序
,它会从内核
里面获取哪一些IP
的路由
发生了变化
,然后通过标准BGP
的路由协议
扩散到整个
其他的宿主机
上,让外界
都知道这个IP
在这里,路由
的时候到这里
部署calico
- 删除
flannel
插件
[root@k8s-master ~]# kubectl delete -f kube-flannel.yml
namespace "kube-flannel" deleted
serviceaccount "flannel" deleted
clusterrole.rbac.authorization.k8s.io "flannel" deleted
clusterrolebinding.rbac.authorization.k8s.io "flannel" deleted
configmap "kube-flannel-cfg" deleted
daemonset.apps "kube-flannel-ds" deleted
- 删除
所有节点
上flannel配置文件
,避免冲突
[root@k8s-master ~]# rm -rf /etc/cni/net.d/10-flannel.conflist
[root@k8s-node1 ~]# rm -rf /etc/cni/net.d/10-flannel.conflist
[root@k8s-node2 ~]# rm -rf /etc/cni/net.d/10-flannel.conflist
- 上传
calico
相关的文件
[root@k8s-master ~]# mkdir network
[root@k8s-master ~]# cd network/
[root@k8s-master network]# ls
calico-3.28.1.tar calico.yaml
[root@k8s-master network]# docker load -i calico-3.28.1.tar
6b2e64a0b556: Loading layer 3.69MB/3.69MB
38ba74eb8103: Loading layer 205.4MB/205.4MB
5f70bf18a086: Loading layer 1.024kB/1.024kB
Loaded image: calico/cni:v3.28.1
3831744e3436: Loading layer 366.9MB/366.9MB
Loaded image: calico/node:v3.28.1
4f27db678727: Loading layer 75.59MB/75.59MB
Loaded image: calico/kube-controllers:v3.28.1
993f578a98d3: Loading layer 67.61MB/67.61MB
Loaded image: calico/typha:v3.28.1
[root@k8s-master network]# docker tag calico/typha:v3.28.1 harbor.huazi.org/calico/typha:v3.28.1
[root@k8s-master network]# docker tag calico/kube-controllers:v3.28.1 harbor.huazi.org/calico/kube-controllers:v3.28.1
[root@k8s-master network]# docker tag calico/cni:v3.28.1 harbor.huazi.org/calico/cni:v3.28.1
[root@k8s-master network]# docker tag calico/node:v3.28.1 harbor.huazi.org/calico/node:v3.28.1
[root@k8s-master network]# docker push harbor.huazi.org/calico/typha:v3.28.1
[root@k8s-master network]# docker push harbor.huazi.org/calico/kube-controllers:v3.28.1
[root@k8s-master network]# docker push harbor.huazi.org/calico/cni:v3.28.1
[root@k8s-master network]# docker push harbor.huazi.org/calico/node:v3.28.1
- 修改
calico.yaml
文件的所有
的image
的位置
[root@k8s-master network]# vim calico.yaml
- 修改
calico.yaml
文件中的部分配置
[root@k8s-master network]# vim calico.yaml
[root@k8s-master network]# kubectl apply -f calico.yaml
#我们发现calico已经运行成功
[root@k8s-master network]# kubectl -n kube-system get pods
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-6849cb478c-8q6vp 1/1 Running 0 65s
calico-node-77vwx 1/1 Running 0 65s
calico-node-mbxgp 1/1 Running 0 65s
calico-node-nbnr8 1/1 Running 0 65s
calico-typha-fff9df85f-q2679 1/1 Running 0 65s
coredns-6c7f6478d8-gplcq 1/1 Running 10 (19h ago) 34d
coredns-6c7f6478d8-vcqg9 1/1 Running 10 (19h ago) 34d
etcd-k8s-master.org 1/1 Running 10 (19h ago) 34d
kube-apiserver-k8s-master.org 1/1 Running 6 (19h ago) 16d
kube-controller-manager-k8s-master.org 1/1 Running 11 (19h ago) 34d
kube-proxy-5t25b 1/1 Running 7 (19h ago) 17d
kube-proxy-g4gsb 1/1 Running 7 (19h ago) 17d
kube-proxy-wsrvk 1/1 Running 7 (19h ago) 17d
kube-scheduler-k8s-master.org 1/1 Running 11 (19h ago) 34d
测试
[root@k8s-master network]# kubectl run testpod --image myapp:v1
pod/testpod created
[root@k8s-master network]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 1/1 Running 0 8s 10.224.114.128 k8s-node1.org <none> <none>
[root@k8s-master network]# curl 10.224.114.128
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-master network]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:69:89:08 brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 172.25.254.100/24 brd 172.25.254.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::4e21:e4b4:36e:6d14/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:28:10:42:60 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
4: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
link/ether ca:b5:36:8b:17:4b brd ff:ff:ff:ff:ff:ff
inet 10.109.194.34/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 172.25.254.50/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.103.58.149/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.96.0.10/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.97.129.250/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.96.0.1/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.103.130.163/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
5: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether ba:47:d2:9c:c3:c9 brd ff:ff:ff:ff:ff:ff
inet 10.244.0.1/24 brd 10.244.0.255 scope global cni0
valid_lft forever preferred_lft forever
inet6 fe80::b847:d2ff:fe9c:c3c9/64 scope link
valid_lft forever preferred_lft forever
6: veth92b05de3@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cni0 state UP group default
link/ether 8a:fb:29:9c:6b:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::88fb:29ff:fe9c:6b04/64 scope link
valid_lft forever preferred_lft forever
7: veth676b78d0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cni0 state UP group default
link/ether 62:f2:ff:c2:13:5a brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::60f2:ffff:fec2:135a/64 scope link
valid_lft forever preferred_lft forever