Kubernetes CNI 分类/运行机制

CNI


网络的连通性由CNI去处理,也就是在pod启动了之后,由CNI插件各个插件去实现网络的配置,来达到彼此的网络联通。

它不仅仅要拉通当前节点容器之间的网络,还需要去打通跨节点之间的网络。

kubernetes网络的模型的基础原则是什么,是一个集群所有pod的网络都可以互通,不经过NAT,所有的节点也不需要不经过NAT可以互相连通。

就是我的节点必须是互相连通的,他们的网络是可以直达的,在这基础之上有我的CNI接口的一些plugin来实现具体的对pod容器网络的配置,让这些容器之间也能够直接互通。

容器内部看到的地址和容器外部看到的地址是唯一确定的。

CNI插件分类和常见插件


 IPAM:负责IP地址分配,一个pod要运行,你得先给我一个IP,然后我才能够配置网络。所以在kubernetes里面都有一类cni插件叫做IPAM的插件,这个IPAM插件主要职责就是给pod分配IP。

还有就是主插件,主插件就是IPAM插件为pod分配IP以后,那么我的这个IP要配置到这个容器上面对吧,我要给容器的做配置,这里就有几种模式。

比如通过网桥的模式,把主机和容器之间的网络打通,这个在说docker的时候已经讲了。

还有ipvlan的模式,以ipvlan的形式将主机和容器的网卡打通。

还有lookback回环地址如何配置。

上面这些都是主插件需要去考虑的。

还有一些附加功能叫metaplugin,这个很多插件都会去支持。

比如说希望为你的pod的网络限流,可能pod自身不支持网络带宽的限制,但是你可以通过一些annotation来所你入栈流量的带宽和出站流量的带宽是多少,然后由metaplugin去帮你做限流。

所以这就是附加能力。

CNI插件运行机制


 CNI和CRI又不一样了,CRI是一个GRPC服务,由kubelet发起GRPC到CRI的runtime,然后由CRI的runtime将请求下发发下去,而CNI是由container runtime发起的,这个请求会发送到CNI插件,CNI是一个一个的可执行文件,它就放在主机的某个目录,container runtime在需要配置网络的时候,它要先去读取,扫描,读取主机上的CNI的配置文件,这个配置文件里面会说明用什么插件来配置网络,然后它就会去对应的可执行文件,因为CNI的插件都是一个一个的可执行文件,容器运行时就会去可执行文件的目录找到对应的plugin的可执行文件,然后去运行相应的命令,来完成整个的网络配置。

CNI和CRI不一样,它是通过可执行文件直接调用,相当于os的exec命令去执行的。

它会有个默认的路径,它在这个目录下面就存放着当前节点上有效的网络插件的配置文件。

[root@k8s-master ~]# cd /etc/cni/net.d/
[root@k8s-master net.d]# ls
10-flannel.conflist


[root@k8s-master net.d]# cat 10-flannel.conflist 
{
  "name": "cbr0",
  "cniVersion": "0.3.1",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}

 在插件配置文件里面他去定义,第一个我的CNI的version是什么,第二个plugin包含哪些,所谓的包含哪些就是一系列的配置了。

type就定义了plugin是flannel,你需要使用flannel的plugin去帮我配置网络。

这里还有metadata plugin,是说我要开启portmap的plugin,就比如calico要开启限流的plugin,

    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }

第三个就是IPAM,calico是主plugin,在主plugin的基础上面,我的ipam用啥,是calico-ipam这个plugin,所有这里面填的type其实对应的都是一个一个的可执行文件。也就是当前节点用了calico的cni,当要分配ip的时候就会去调用calico的ipam的可执行文件,分配完ip之后,然后就调用calico这个可执行文件,然后去为我的容器配置网络。 

 当我要去做限流的时候就需要去调用bandwidth,这个就是默认cni的配置路径。

可以看到可执行文件的位置,可以看到所说的calico-ipam,包括bandwidth都在这。

[root@master ~]# cd /opt/cni/bin/
[root@master bin]# ls
bandwidth  calico       dhcp      flannel      host-local  ipvlan    macvlan  ptp  static  vlan
bridge     calico-ipam  firewall  host-device  install     loopback  portmap  sbr  tuning

如果你的运行时切换到containerd,那么containerd需要为pod去配置网络,就会去默认的配置文件目录去查看当前节点用的是什么plugin,cni的plugin发现是calico,然后它就会去解析这个calico的配置文件,在calico的配置文件里面,会去定义主的plugin是calico,ipam的plugin是calico-ipam,然后meta plugin是bandwith。

接下来containerd就会默认的可执行文件的路径调用calico-ipam命令去为这个pod配置网络。

上面就是cni的工作原理,它更加直接,不是通过什么interface去调用完成的。而是通过直接的调用,对可执行文件的调用。

 可以看到默认打印出的是version,它是一个可执行文件,可以通过告诉calico这个plugin说,你要为哪个容器创建网络,为哪个容器删除网络,那么这个CNI的plugin就需要去做具体的执行动作。

[root@master bin]# ./calico
Calico CNI plugin v3.16.3

下面就是对上面cni运行机制的描述。

CNI插件的设计和考量


通过上面来了解一下cni插件到底是如何工作的,首先第一个就是容器运行时,必须在调用插件之前,为这个容器创建新的网络namespace,每个容器有自己的不同的网络namespace,针对这些网络那些插件要被执行,这些插件的配置是用json的格式,由containerd去读取这些配置文件,然后按照顺序的去执行相应的插件。 

 当pod要删除的时候,容器运行时要按照相反的顺序去删除网络。有些场景下会配置多个网络插件,这些网络插件可能会有不同,按照它的既定顺序一个一个去执行。

在删除网络的时候,你要按照相反的顺序去删除。

当cni插件去为容器配置网络的时候,它必须是顺序执行的,不能在前一个请求还没处理完之后,又来了一个新的请求为这个容器去做配置。那么这样的话很可能因为中间状态批次不同步,这个时候IP就有可能会配置错了。第一个配置还没完成,ip刚在分配,然后第二个就过来了,然后又分了一个新的ip,那么最后就会出现各种各样的问题,所以必须是顺序的。

add和delete操作也是有顺序的,add后面总是跟着delete,delete可以有额外的delete,那么插件应该遵循这么样的原则。

 打通主机层网络


 跨主机的网络打通就需要cni插件的支持。

 cni插件就包含了一些通用能力,比如loopback口如何配置,比如ipvlan,bridge这些设备的创建。这些接口的创建都是cni标准插件去配置好了。

这个eth0的device就是我们calico的plugin去做配置的,这个loopback的地址就是就是cni的loopback

这个二进制文件是由标准的cni接口实现的。 

 所以,标准的cni接口,有些能力也就是通用能力,不管到哪,这些loopback的网络配置都需要配置,这些通用能力就需要cni的组织所提供的标准插件去实现。所以它提供了具体通用能力的配置。

猜你喜欢

转载自blog.csdn.net/qq_34556414/article/details/126005437
cni