docker 的出现是革命性的,改变了咱们开发以及部署项目的方式。社区一直致力于让容器技术标准化,这篇文章主要讨论的是其中的一个方面:网络。docker
在开始探讨不一样的容器网络标准模型以前,先来从网络角度对比一下虚拟机和 docker。json
虚拟机是一整套操做系统层级的虚拟化,它还会虚拟出虚拟网卡(virtual network interface cards (NIC)),这些虚拟网卡会和真正的物理机网卡相链接。api
docker 实质上就是一个进程,被 container runtime 统一管理,还会共享一个 Linux kernel。因此,容器有更灵活的网络解决方案:网络
早期的容器网络设计把重点放在了如何链接一个宿主机上的容器,让他们能够和外界进行交互。分布式
在"host"模式中,运行在一个宿主机上的容器使用 host 的network namespace,和宿主机一个ip。为了暴露容器,容器会占用宿主机上的一个端口,经过这个端口和外界通讯。因此,你须要手动维护端口的分配,不要使不一样的容器服务运行在一个端口上。性能
"bridge"模式,在"host"模式的基础上作了些改进。在该模式里面,容器被分配到了一个虚拟的局域网里,在这个network namespace 得到分配到的 ip 地址,因为 ip 地址是独立的,就解决了"host"模式中不一样容器服务不能运行在同一端口的问题。不过仍是有一个问题,若是容器想要和外界通讯的话,仍是须要使用 host 的 ip 地址。这时候须要用到 NAT 将 host-ip:port 转换成 private-ip:port。这一部分的 NAT 规则表示用Linux Iptables 维护的,这会在必定程度上影响性能(虽然不大)。spa
上述的两种模式都没有解决一个问题:多 host 网络解决方案。操作系统
Kubernetes 在处理网络上,没有选择本身再独立创造一个,而是选择了其中的 CNI做为了本身的网络插件。(至于为何不选择 CNM,能够看看这篇官方的解释:Why Kubernetes doesn’t use libnetwork)。不使用 CNM 最关键的一点,是 k8s 考虑到CNM 在必定程度上和 container runtime 联系相对比较紧密,很差解耦。 有了 k8s 这种巨无霸的选择以后,后来的不少项目都在 CNM 和 CNI 之间选择了 CNI。插件
CNM 的 api 包含了两部分:IPAM 插件和网络插件。IPAM 插件负责建立/删除 address pools、分配网络地址,network 插件负责建立/删除 networks、以及分配或收回容器的 ip 地址。事实上,这两种插件均可以实现全部的 API,你能够选择用 IPAM,也能够选择用 network,或者 BOTH。可是,container runtime 会在不一样状况下使用到不一样的插件,这带来了复杂性。还有就是,CNM 须要使用分布式存储系统来保存网络配置信息,例如 etcd。设计
CNI 对外暴露了从一个网络里面添加和剔除容器的接口。CNI 使用一个 json 配置文件保存网络配置信息。和 CNM 不同,CNI 不须要一个额外的分布式存储引擎。
CNI目前已经得到了众多开源项目的青睐,好比 K8S、Memos、Cloud Foundry。同时被Cloud Native Computing Foundation所承认。CNCF 背后有众多的科技大亨,因此能够预见,CNI 将会成为将来容器网络的标准。