不论是 docker 仍是 kubernetes,在网络方面目前都没有一个完美的、终极的、普适性的解决方案,不一样的用户和企业由于各类缘由会使用不一样的网络方案。目前存在网络方案 flannel、calico、openvswitch、weave、ipvlan等,并且之后必定会有其余的网络方案,这些方案接口和使用方法都不相同,而不一样的容器平台都须要网络功能,它们之间的适配若是没有统一的标准,会有很大的工做量和重复劳动。html
CNI 就是这样一个标准,它旨在为容器平台提供网络的标准化。不一样的容器平台(好比目前的 kubernetes、mesos 和 rkt)可以经过相同的接口调用不一样的网络组件。linux
CNI(Conteinre Network Interface) 是 google 和 CoreOS 主导制定的容器网络标准,它 自己并非实现或者代码,能够理解成一个协议。这个标准是在 rkt 网络提议 的基础上发展起来的,综合考虑了灵活性、扩展性、ip 分配、多网卡等因素。git
这个协议链接了两个组件:容器管理系统和网络插件。它们之间经过 JSON 格式的文件进行通讯,实现容器的网络功能。具体的事情都是插件来实现的,包括:建立容器网络空间(network namespace)、把网络接口(interface)放到对应的网络空间、给网络接口分配 IP 等等。github
关于网络,docker 也提出了 CNM 标准,它要解决的问题和 CNI 是重合的,也就是说目前二者是竞争关系。目前 CNM 只能使用在 docker 中,而 CNI 可使用在任何容器运行时。CNM 主要用来实现 docker 自身的网络问题,也就是 docker network
子命令提供的功能。docker
全部的标准和协议都要有具体的实现,才可以被你们使用。CNI 也不例外,目前官方在 github 上维护了同名的 CNI 代码库,里面已经有不少能够直接拿来使用的 CNI 插件。服务器
官方提供的插件目前分红三类:main、meta 和 ipam。main 是主要的实现了某种特定网络功能的插件;meta 自己并不会提供具体的网络功能,它会调用其余插件,或者单纯是为了测试;ipam 是分配 IP 地址的插件。网络
ipam 并不提供某种网络功能,只是为了灵活性把它单独抽象出来,这样不一样的网络插件能够根据需求选择 ipam,或者实现本身的 ipam。dom
这些插件的功能说明以下:oop
lo
网卡,并配置上 127.0.0.1/8
地址网络插件是独立的可执行文件,被上层的容器管理平台调用。网络插件只有两件事情要作:把容器加入到网络以及把容器从网络中删除。调用插件的数据经过两种方式传递:环境变量和标准输入。通常插件须要三种类型的数据:容器相关的信息,好比 ns 的文件、容器 id 等;网络配置的信息,包括网段、网关、DNS 以及插件额外的信息等;还有就是 CNI 自己的信息,好比 CNI 插件的位置、添加网络仍是删除网络。测试
咱们来看一下为容器添加网络是怎么工做的,删除网络和它过程同样。
把容器加入到网络
调用插件的时候,这些参数会经过环境变量进行传递:
CNI_COMMAND
:要执行的操做,能够是 ADD
(把容器加入到某个网络)、DEL
(把容器从某个网络中删除)CNI_CONTAINERID
:容器的 ID,好比 ipam 会把容器 ID 和分配的 IP 地址保存下来。可选的参数,可是推荐传递过去。须要保证在管理平台上是惟一的,若是容器被删除后能够循环使用CNI_NETNS
:容器的 network namespace 文件,访问这个文件能够在容器的网络 namespace 中操做CNI_IFNAME
:要配置的 interface 名字,好比 eth0
CNI_ARGS
:额外的参数,是由分号;
分割的键值对,好比 “FOO=BAR;hello=world”CNI_PATH
:CNI 二进制查找的路径列表,多个路径用分隔符 :
分隔网络信息主要经过标准输入,做为 JSON 字符串传递给插件,必须的参数包括:
cniVersion
:CNI 标准的版本号。由于 CNI 在演化过程当中,不一样的版本有不一样的要求name
:网络的名字,在集群中应该保持惟一type
:网络插件的类型,也就是 CNI 可执行文件的名称args
:额外的信息,类型为字典ipMasq
:是否在主机上为该网络配置 IP masqueradeipam
:IP 分配相关的信息,类型为字典dns
:DNS 相关的信息,类型为字典插件接到这些数据,从输入和环境变量解析到须要的信息,根据这些信息执行程序逻辑,而后把结果返回给调用者,返回的结果中通常包括这些参数:
CNI 协议的内容还在不断更新,请到官方文档获取当前的信息。
CNI 做为一个协议/标准,它有很强的扩展性和灵活性。若是用户对某个插件有额外的需求,能够经过输入中的 args
和环境变量 CNI_ARGS
传输,而后在插件中实现自定义的功能,这大大增长了它的扩展性;CNI 插件把 main 和 ipam 分开,用户能够自由组合它们,并且一个 CNI 插件也能够直接调用另一个 CNI 插件,使用起来很是灵活。
若是要实现一个继承性的 CNI 插件也不复杂,能够编写本身的 CNI 插件,根据传入的配置调用 main 中已经有的插件,就能让用户自由选择容器的网络。
CNI 目前已经在 kubernetes 中开始使用,也是目前官方推荐的网络方案,具体的配置方法能够参考kubernetes 官方文档。
kubernetes 使用了 CNI 网络插件以后,工做过程是这样的:
http://cizixs.com/2017/05/23/container-network-cni