Kubernetes CNI网络插件 (3)

Main插件:这就是具体创建网络设备的二进制程序文件,比如birdge就是创建Linux网桥的程序、ptp就是创建Veth Pair设备的程序、loopback就是创建lo设备的程序,等等。

IPAM插件:负责分配IP地址的程序文件,比如dhcp就是会向DHCP服务器发起地址申请、host-local就是会使用预先设置的IP地址段来进行分配,就像在dockerd中设置--bip一样。

Meta其他插件:这个是由CNI社区维护的,比如flannel就是为Flannel项目提供的CNI插件,不过这种插件不能独立使用,必须调用Main插件使用。

所以要用这些东西就要解决2个问题,我们以flannel为例,一个是网络方案本身如何解决跨主机通信;另外一个就是如何配置Infra网络栈并连接到CNI网桥上。

下面我们以flannel为例的网桥模式为例说一下流程

结合使用docker容器引擎以及flannel插件来说就是,kubelet通过CRI接口创建POD,它会第一个创建Infra容器,这一步是调用Dokcer对CRI的实现(dockershim),dockershim调用docker api来完成,然后就会设置网络,首选需要准备CNI插件参数、其次就是传递参数并调用这个CNI插件去设置Infra网络。对于flannel插件所需要的参数包含2个部分:

kubelet通过CRI调用dockershim时候传递的一组信息,也就是具体动作比如ADD或者DEL以及这些动作所需要的参数,如果是ADD的话则包括容器网卡名称、POD的Network namespace路径、容器的ID等。

dockershim从CNI配置文件中加载到的(在CNI中叫做Network Configuration),也就是从--cni-conf-dir目录中加载的默认配置信息。

有了上面2部分信息之后,dockershim就会把这个信息给flannel插件,插件会对第二部分信息做补充,然后这个插件来做ADD操作,而这个操作是由CNI bridge这个插件来完成的。这个bridge使用全部的参数信息来执行把容器加入到CNI网络的操作了。它会做如下内容:

检查是否有CNI网桥,如果没有就创建并UP这个网桥,相当于在宿主机上执行ip link add cni0 type bridge、ip link set cni0 up命令

接下来bridge会通过传递过来的Infra容器的网络名称空间文件进入这个网络名称空间中,然后创建Veth Pair设备,然后UP容器的这一端eth0,然后将另外一端放到宿主机名称空间里并UP这个设备。

bridge把宿主机的一端连接到网桥cni0上

bridge会调用IPAM插件为容器的eht0分配IP地址,并设置默认路由。

bridge会为CNI网桥添加IP地址,如果是第一次的话。

最后CNI插件会把容器的IP地址等信息返回给dockershim,然后被kubelet添加到POD的status字段中。

现在我们再来回顾一下之前那个问题,我的环境是kubernetes、flannel、docker都是二进制程序安装通过系统服务形式启动。我没有/opt/cni/bin目录,也就是没有任何CNI插件,所以也就没有设置--network-plugin。那通过kubernetes部署的POD是如何被设置网络的呢?

通过之前的介绍我们知道了kubelet通过CRI与容器引擎打交道来操作容器,那么kubelet默认是用容器运行时就是docker,因为kubelet启动参数--container-runtime就是docker,而docker又提供了符合CRI规范的接口那么kubelet就自然可以让容器运行在docker引擎上。接下来说网络,--network-plugin没有设置,那kubelet到底用的什么网络插件呢?而CNI插件里面也没有docker插件这个东西。我们看一下这个参数说明如下:

The name of the network plugin to be invoked for various events in kubelet/pod lifecycle. This docker-specific flag only works when container-runtime is set to docker.

前半句意思是说这个参数定义POD使用的网络插件名称,但是后面半句的意思是如果使用的容器运行时是docker,那么默认网络插件就是docker。

二进制安装环境下如何使用CNI

我的环境所有组件都是二进制安装,以系统服务形式运行。最初是使用docker0网桥。这里说一下过程:

你需要向etcd写入子网信息{"Network":"'${CLUSTER_CIDR}'", "SubnetLen": 24, "Backend": {"Type": "vxlan"}}。

flanneld服务启动后会去etcd中申请本机使用的子网网段,然后就会写入到/run/flannel/subnet.env文件中

然后flanneld的service文件中有一条ExecStartPost=指令,就是在flanneld启动后执行的,作用就是调用一个脚本去修改dockerd的--bip参数把获取的子网信息写入

启动docker服务,然后dockerd会根据--bip的信息设置docker0网桥

在上面这个过程中部署的POD容器的网络协议栈都是docker来设置的,当然是kubelet通过调用CRI接口来去和docker交互的,跨主机通信是由flannel来完成的。

现在我们要在某一台主机上切换成CNI,需要做如下修改:

建立目录mkdir -p /opt/cni/{bin,net.d}

下载CNI插件到上面的bin目录中,然后解压。

在上面的net.d目录中建立10-flannel.conflist文件,内容后面再说。

停止该主机的docker、kubelet服务,这样该主机的容器就会被master调度到其他可用主机,不过DaemonSet类型的则不行。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgffx.html