Understanding CNI (Container Networking Interface)

 

Understanding CNI (Container Networking Interface)

 https://github.com/containernetworking/cni

 

 执行 kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml
在宿主机的 /opt/cni/bin 目录下看到它们,如下所示:
root@ubuntu:~# ls /opt/cni/bin 
antrea  bandwidth  bridge  dhcp  firewall  flannel  host-device  host-local  ipvlan  loopback  macvlan  portmap  ptp  sbr  static  tuning  vlan  whereabouts
root@ubuntu:~# 

 

这些 CNI 的基础可执行文件,按照功能可以分为三类:

  1. 第一类,叫作 Main 插件,它是用来创建具体网络设备的二进制文件。比如,bridge(网桥设备)、ipvlan、loopback(lo 设备)、macvlan、ptp(Veth Pair 设备),以及 vlan。

    Flannel、Weave 等项目,都属于“网桥”类型的 CNI 插件。所以在具体的实现中,它们往往会调用 bridge 这个二进制文件

  2. 第二类,叫作 IPAM(IP Address Management)插件,它是负责分配 IP 地址的二进制文件。比如,dhcp,这个文件会向 DHCP 服务器发起请求;host-local,则会使用预先配置的 IP 地址段来进行分配。

  3. 第三类,是由 CNI 社区维护的内置 CNI 插件。比如:flannel,就是专门为 Flannel 项目提供的 CNI 插件;tuning,是一个通过 sysctl 调整网络设备参数的二进制文件;portmap,是一个通过 iptables 配置端口映射的二进制文件;bandwidth,是一个使用 Token Bucket Filter (TBF) 来进行限流的二进制文件。

从这些二进制文件中,我们可以看到,如果要实现一个给 Kubernetes 用的容器网络方案,其实需要做两部分工作,以 Flannel 项目为例:

首先,实现这个网络方案本身。这一部分需要编写的,其实就是 flanneld 进程里的主要逻辑。比如,创建和配置 flannel.1 设备、配置宿主机路由、配置 ARP 和 FDB 表里的信息等等。

然后,实现该网络方案对应的 CNI 插件。这一部分主要需要做的,就是配置 Infra 容器里面的网络栈,并把它连接在 CNI 网桥上。

 

调用实现

在每台宿主机上生成对应的CNI配置文件/etc/cni/net.d/10-flannel.conflist,kubernetes集群会使用这个配置文件来作为容器网络配置方案

root@ubuntu:~# ls /etc/cni/net.d/
10-antrea.conflist  10-flannel.conflist
root@ubuntu:~# 

 

 

root@ubuntu:~# 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
      }
    }
  ]
}
root@ubuntu:~# ip a sh cbr0
Device "cbr0" does not exist.
root@ubuntu:~# cat /etc/cni/net.d/10-antrea.conflist
{
    "cniVersion":"0.3.0",
    "name": "antrea",
    "plugins": [
        {
            "type": "antrea",
            "ipam": {
                "type": "host-local"
            }
        },
        {
            "type": "portmap",
            "capabilities": {"portMappings": true}
        },
        {
            "type": "bandwidth",
            "capabilities": {"bandwidth": true}
        }
    ]
}

 

CNI的调用方式是通过一个可执行文件进行的。这里以calico为例,说明CNI插件的调用方式。

首先,calico进行插件注册

mkdir -p /etc/cni/net.d
cat >/etc/cni/net.d/10-calico.conf <<EOF { "name": "calico-k8s-network", "type": "calico", "etcd_authority": "<ETCD_IP>:<ETCD_PORT>", "log_level": "info", "ipam": { "type": "calico-ipam" }, "policy": { "type": "k8s" } } EOF

 

k8s的DefaultCNIDir/opt/cni/bin。因为注册的typecalico,所以k8s会从/opt/cni/bin中搜索一个calico的可执行文件,然后进行执行。

执行的时候传递参数有两种方式,一种是通过环境变量进行传递,比如上文中的Version、Container ID等;另外一种是通过执行calico作为执行的参数传进去,这个主要就是Network configuration的部分,通过json将其打包传入。

同样判断是否执行成功,是通过执行文件的返回值获取的。0为成功,1为版本版本不匹配,2为存在不符合的字段。如果执行成功,返回值将通过stdout返回。

 

 CNI与dockershim

CRI(Container Runtime Interface,容器运行时接口)实现容器网络相关的逻辑,对应docker项目为dockershim来实现

dockershim处理过程
  1. dockershim在处理容器网络时,加载/etc/cni/net.d内的文件,并且把plugins字段中的第一个插件作为默认插件
  2. 后面的执行过程中,flannel和portmap会按照定义顺序被调用,从而依次完成“配置容器网络”和“配置端口映射”这两步操作
CNI插件的工作原理
  1. kubelet创建pod时,首先通过dockershim会先调用docker api创建并启动Infra容器,然后执行SetUpPod方法,作用为:为CNI插件准备参数,然后调用CNI插件为Infra容器配置网络
    • 将容器添加到CNI网络中,即通过容器以Veth Pair方式插到CNI网桥上
    • /run/flannel/subnet.env为宿主机生成的flannel配置文件
    • /var/lib/cni/flannel 为flannel cni插件把delegate字段以json文件的方式保存下来
  2. CNI bridge插件调用CNI ipam插件,为容器分配可用ip地址,同时为容器设置默认路由
  3. CNI插件会把容器的ip地址等信息返回给dockershim,然后被kubelet添加到Pod的Status字段中

 

 

 

 

 

 Flannel CNI

CNI——容器网络是如何打通的

posted on 2021-06-01 20:16  tycoon3  阅读(116)  评论(0编辑  收藏  举报

导航