容器网络模型:CNI vs CNM

docker 的出现是革命性的,改变了我们开发以及部署项目的方式。社区一直致力于让容器技术标准化,这篇文章主要讨论的是其中的一个方面:网络。

网络层面:虚拟机 vs 容器技术

在开始探讨不同的容器网络标准模型之前,先来从网络角度对比一下虚拟机和 docker。

虚拟机是一整套操作系统层级的虚拟化,它还会虚拟出虚拟网卡(virtual network interface cards (NIC)),这些虚拟网卡会和真正的物理机网卡相连接。

docker 实质上就是一个进程,被 container runtime 统一管理,还会共享一个 Linux kernel。所以,容器有更灵活的网络解决方案:

  • 和宿主机是共享同一个network interface和 network namespace
  • 连接另外的虚拟网络,使用这个虚拟网络的network interface和 network namespace

容器网络设计

早期的容器网络设计把重点放在了如何连接一个宿主机上的容器,让他们可以和外界进行交互。

在"host"模式中,运行在一个宿主机上的容器使用 host 的network namespace,和宿主机一个ip。为了暴露容器,容器会占用宿主机上的一个端口,通过这个端口和外界通信。所以,你需要手动维护端口的分配,不要使不同的容器服务运行在一个端口上。

"bridge"模式,在"host"模式的基础上做了些改进。在该模式里面,容器被分配到了一个虚拟的局域网里,在这个network namespace 获得分配到的 ip 地址,由于 ip 地址是独立的,就解决了"host"模式中不同容器服务不能运行在同一端口的问题。不过还是有一个问题,如果容器想要和外界通信的话,还是需要使用 host 的 ip 地址。这时候需要用到 NAT 将 host-ip:port 转换成 private-ip:port。这一部分的 NAT 规则表示用Linux Iptables 维护的,这会在一定程度上影响性能(虽然不大)。

上述的两种模式都没有解决一个问题:多 host 网络解决方案。

CNI 和 CNM 的对比

  • CNM: Docker 公司(docker container runtime 背后的公司)提出。
  • CNI:CoreOS公司提出。

Kubernetes 在处理网络上,没有选择自己再独立创造一个,而是选择了其中的 CNI作为了自己的网络插件。(至于为什么不选择 CNM,可以看看这篇官方的解释:Why Kubernetes doesn’t use libnetwork)。不使用 CNM 最关键的一点,是 k8s 考虑到CNM 在一定程度上和 container runtime 联系相对比较紧密,不好解耦。 有了 k8s 这种巨无霸的选择之后,后来的很多项目都在 CNM 和 CNI 之间选择了 CNI。

下面是两种网络模型的详细对比:

  1. CNM

CNM 的 api 包含了两部分:IPAM 插件和网络插件。IPAM 插件负责创建/删除 address pools、分配网络地址,network 插件负责创建/删除 networks、以及分配或收回容器的 ip 地址。事实上,这两种插件都可以实现所有的 API,你可以选择用 IPAM,也可以选择用 network,或者 BOTH。但是,container runtime 会在不同情况下使用到不同的插件,这带来了复杂性。还有就是,CNM 需要使用分布式存储系统来保存网络配置信息,例如 etcd。

  1. CNI

CNI 对外暴露了从一个网络里面添加和剔除容器的接口。CNI 使用一个 json 配置文件保存网络配置信息。和 CNM 不一样,CNI 不需要一个额外的分布式存储引擎。

总结

CNI目前已经获得了众多开源项目的青睐,比如 K8S、Memos、Cloud Foundry。同时被Cloud Native Computing Foundation所认可。CNCF 背后有众多的科技大亨,所以可以预见,CNI 将会成为未来容器网络的标准。

猜你喜欢

转载自juejin.im/post/5c8fc0236fb9a070fc6232b1
cnm
VS