共计 3354 个字符,预计需要花费 9 分钟才能阅读完成。
Overview
目前围绕着 docker 的网络,目前有两种比较主流的声音,docker 主导的 Container network model(CNM)和社区主导的 Container network interface(CNI)。本文就针对两者模型进行分别介绍。
Container Networking Interface
概述
Container Networking Interface(CNI)提供了一种 linux 的应用容器的插件化网络解决方案。最初是由 rkt Networking Proposal 发展而来。也就是说,CNI 本身并不完全针对 docker 的容器,而是提供一种普适的容器网络解决方案。因此他的模型只涉及两个概念:
- 容器(container) : 容器是拥有独立 linux 网络命名空间的独立单元。比如 rkt/docker 创建出来的容器。
这里很关键的是容器需要拥有自己的 linux 网络命名空间。这也是加入网络的必要条件。
- 网络 (network): 网络指代了可以相互联系的一组实体。这些实体拥有各自独立唯一的 ip。这些实体可以是容器,是物理机,或者其他网络设备(比如路由器) 等。
接口及实现
CNI 的接口设计的非常简洁,只有两个接口 ADD/DELETE。
以 ADD 接口为例
Add container to network
参数主要包括:
- Version. CNI 版本号
- Container ID. 这是一个可选的参数,提供容器的 id
- Network namespace path. 容器的命名空间的路径,比如 /proc/[pid]/ns/net。
- Network configuration. 这是一个 json 的文档,具体可以参看 network-configuration
- Extra arguments. 其他参数
- Name of the interface inside the container. 容器内的网卡名
返回值:
- IPs assigned to the interface. ipv4 或者 ipv6 地址
- DNS information. DNS 相关信息
调用实现
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
。因为注册的type
是calico
,所以 k8s 会从 /opt/cni/bin
中搜索一个 calico
的可执行文件,然后进行执行。
执行的时候传递参数有两种方式,一种是通过环境变量进行传递,比如上文中的 Version、Container ID 等;另外一种是通过执行 calico
作为执行的参数传进去,这个主要就是 Network configuration 的部分,通过 json 将其打包传入。
同样判断是否执行成功,是通过执行文件的返回值获取的。0 为成功,1 为版本版本不匹配,2 为存在不符合的字段。如果执行成功,返回值将通过 stdout 返回。
Container Network Model
概述
相较于 CNI,CNM 是 docker 公司力推的网络模型。其主要模型如下图:
Sandbox
Sandbox 包含了一个容器的网络栈。包括了管理容器的网卡,路由表以及 DNS 设置。一种 Sandbox 的实现是通过 linux 的网络命名空间,一个 FreeBSD Jail 或者其他类似的概念。一个 Sandbox 可以包含多个 endpoints。
Endpoint
一个 endpoint 将 Sandbox 连接到 network 上。一个 endpoint 的实现可以通过 veth pair,Open vSwitch internal port 或者其他的方式。一个 endpoint 只能属于一个 network,也只能属于一个 sandbox。
Network
一个 network 是一组可以相互通信的 endpoints 组成。一个 network 的实现可以是 linux bridge,vlan 或者其他方式。一个网络中可以包含很多个 endpoints。
接口
CNM 的接口相较于 CNI 模型,较为复杂。其提供了 remote plugin 的方式,进行插件化开发。remote plugin 相较与 CNI 的命令行,更加友好一些,是通过 http 请求进行的。remote plugin 监听一个指定的端口,docker daemon 直接通过这个端口与 remote plugin 进行交互。
鉴于 CNM 的接口较多,这里就不一一展开解释了。这里主要介绍下在进行 docker 的操作中,docker daemon 是如何同 CNM 插件繁盛交互。
调用过程
Create Network
这一系列调用发生在使用 docker network create
的过程中。
- /IpamDriver.RequestPool: 创建 subnetpool 用于分配 IP
- /IpamDriver.RequestAddress: 为 gateway 获取 IP
- /NetworkDriver.CreateNetwork: 创建 neutron network 和 subnet
Create Container
这一系列调用发生在使用 docker run
,创建一个 contain 的过程中。当然,也可以通过docker network connect
触发。
- /IpamDriver.RequestAddress: 为容器获取 IP
- /NetworkDriver.CreateEndpoint: 创建 neutron port
- /NetworkDriver.Join: 为容器和 port 绑定
- /NetworkDriver.ProgramExternalConnectivity:
- /NetworkDriver.EndpointOperInfo
Delete Container
这一系列调用发生在使用 docker delete
,删除一个 contain 的过程中。当然,也可以通过docker network disconnect
触发。
- /NetworkDriver.RevokeExternalConnectivity
- /NetworkDriver.Leave: 容器和 port 解绑
- /NetworkDriver.DeleteEndpoint
- /IpamDriver.ReleaseAddress: 删除 port 并释放 IP
Delete Network
这一系列调用发生在使用 docker network delete
的过程中。
- /NetworkDriver.DeleteNetwork: 删除 network
- /IpamDriver.ReleaseAddress: 释放 gateway 的 IP
- /IpamDriver.ReleasePool: 删除 subnetpool
CNI 与 CNM 的转化
CNI 和 CNM 并非是完全不可调和的两个模型。二者可以进行转化。比如 calico 项目就是直接支持两种接口模型。
从模型中来看,CNI 中的 container 应与 CNM 的 sandbox 概念一致,CNI 中的 network 与 CNM 中的 network 一致。在 CNI 中,CNM 中的 endpoint 被隐含在了 ADD/DELETE 的操作中。CNI 接口更加简洁,把更多的工作托管给了容器的管理者和网络的管理者。从这个角度来说,CNI 的 ADD/DELETE 接口其实只是实现了 docker network connect
和docker network disconnect
两个命令。
kubernetes/contrib 项目提供了一种从 CNI 向 CNM 转化的过程。其中原理很简单,就是直接通过 shell 脚本执行了 docker network connect
和docker network disconnect
命令,来实现从 CNI 到 CNM 的转化。
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-10/147496.htm