kubernetes的cni插件就是通过某些方法把宿主机上的特殊设备连通,比如vtep设备,它维护的网桥用tunl0代替了docker0
k8s在启动infa初始化容器之后就可以调用cni网络插件为这个infa容器的网络命名空间配置需要的网络,包括网卡,回环设备,路由表和iptables规则,在安详好k8s后,在/opt/cni/bin目录下看到他们
第一类叫做main插件,它是用来创建具体网络设备的二进制文件,比如bridge,第二类是ipam负责分配ip地址的二进制文件,比如dhcp,第三类是cni插件,比如calico,tuning是一个通过sysctl调整网络设备参数的二进制文件,portmap是一个通过iptables配置端口映射的二进制文件,bandwidth是用来限流的,我们在安装好比如calico之后会生成对应的cni配置文件,它其实也是一个configmap
{
"name": "k8s-pod-network",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "calico",
"log_level": "info",
"log_file_path": "/var/log/calico/cni/cni.log",
"datastore_type": "kubernetes",
"nodename": "k8s-master1",
"mtu": 0,
"ipam": {
"type": "calico-ipam"
},
"policy": {
"type": "k8s"
},
"kubernetes": {
"kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
}
},
{
"type": "portmap",
"snat": true,
"capabilities": {"portMappings": true}
},
{
"type": "bandwidth",
"capabilities": {"bandwidth": true}
}
]
在k8s中处理容器网络的相关逻辑并不会出现在kubelet的主干代码里,而是会在具体的cri实现里完成,k8s不允许使用多个网络插件,但是可以在cni配置文件里通过pkugins字段定义多个插件,创建好infa容器后,会执行一个setuppod方法,为cni准备参数,为infa容器配置网络,参数中有一个cni_command,它取值有add和del,add参数包括,容器网卡名字,pod网络命名空间的文件路径,容器的id,Flannel 的 CNI 配置文件( /etc/cni/net.d/10-flannel.conflist)里有这么一个字段,叫作 delegate:Delegate 字段的意思是,这个 CNI 插件并不会自己做事儿,而是会调用 Delegate 指定的某种 CNI 内置插件来完成。对于 Flannel 来说,它调用的 Delegate 插件,就是前面介绍到的 CNI bridge 插件。所以说,dockershim 对 Flannel CNI 插件的调用,其实就是走了个过场。Flannel CNI 插件唯一需要做的,就是对 dockershim 传来的 Network Configuration 进行补充。比如,将 Delegate 的 Type 字段设置为 bridge,将 Delegate 的 IPAM 字段设置为 host-local 等。然后根据ipam分配ip地址,调用cni bridge配置网络,具体操作是,创建cni网桥,通过infa容器的网络命名空间文件进入network namespace里面创建veth pair ,把一段连接到宿主机上,另一端连接容器的eth0,相当于执行下面命令
# 在宿主机上
$ ip link add cni0 type bridge
$ ip link set cni0 up
#在容器里
# 创建一对Veth Pair设备。其中一个叫作eth0,另一个叫作vethb4963f3
$ ip link add eth0 type veth peer name vethb4963f3
# 启动eth0设备
$ ip link set eth0 up
# 将Veth Pair设备的另一端(也就是vethb4963f3设备)放到宿主机(也就是Host Namespace)里
$ ip link set vethb4963f3 netns $HOST_NS
# 通过Host Namespace,启动宿主机上的vethb4963f3设备
$ ip netns exec $HOST_NS ip link set vethb4963f3 up
接着吧设备连接到cni网桥上
# 在宿主机上
$ ip link set vethb4963f3 master cni0
为它设置 Hairpin Mode,用于自己访问自己,CNI bridge 插件会调用 CNI ipam 插件,从 ipam.subnet 字段规定的网段里为容器分配一个可用的 IP 地址。然后,CNI bridge 插件就会把这个 IP 地址添加在容器的 eth0 网卡上,同时为容器设置默认路由。这相当于在容器里执行
# 在容器里
$ ip addr add 10.244.0.2/24 dev eth0
$ ip route add default via 10.244.0.1 dev eth0
最后,CNI bridge 插件会为 CNI 网桥添加 IP 地址。这相当于在宿主机上执行:
# 在宿主机上
$ ip addr add 10.244.0.1/24 dev cni0
在执行完上述操作之后,CNI 插件会把容器的 IP 地址等信息返回给 dockershim,然后被 kubelet 添加到 Pod 的 Status 字段。