带你玩转kubernetes-k8s(第46篇:深入分析k8s网络原理[CNM、CNI]网络模型)
随着容器技术在企业生产系统中的逐步落地,用户对容器云的网络特性要求也越来越高。跨主机容器间的网络互通已经成为基本要求,更高的要求包括容器固定IP地址、一个容器多个IP地址、多个子网隔离、ACL控制策略、与SDN集成等。目前主流的容器网络模型主要有Docker公司提出的Container Network Model(CNM)模型和CoreOS公司提出的Container Network ...
随着容器技术在企业生产系统中的逐步落地,用户对容器云的网络特性要求也越来越高。跨主机容器间的网络互通已经成为基本要求,更高的要求包括容器固定IP地址、一个容器多个IP地址、多个子网隔离、ACL控制策略、与SDN集成等。目前主流的容器网络模型主要有Docker公司提出的Container Network Model(CNM)模型和CoreOS公司提出的Container Network Interface(CNI)模型。
1.CNM模型
CNM模型是由Docker公司提出的容器网络模型,现在已经被Cisco Contiv、Kuryr、Open Virtual Networking(OVN)、Project Calico、 VMware、Weave和Plumgrid等项目采纳。另外,Weave、Project Calico、Kuryr和Plumgrid等项目也为CNM提供了网络插件的具体实现。
CNM模型主要通过Network Sandbox、Endpoint和Network这3个组件进行实现,
◎ Network Sandbox:容器内部的网络栈,包括网络接口、路由表、DNS等配置的管理。Sandbox可用Linux网络命名空间、FreeBSD Jail等机制进行实现。一个Sandbox可以包含多个Endpoint。
◎ Endpoint:用于将容器内的Sandbox与外部网络相连的网络接口。可以使用veth对、Open vSwitch的内部port等技术进行实现。一个Endpoint仅能够加入一个Network。
◎ Network:可以直接互连的Endpoint的集合。可以通过Linux网桥、VLAN等技术进行实现。一个Network包含多个Endpoint。
2.CNI模型
CNI是由CoreOs公司公司提出的另一种容器网络规范,现在已经被Kubernetes、rkt、Apache Mesos、Cloud Foundry和Kurma等项目采纳。另外,Contiv Networking, Project Calico、Weave、SR-IOV、Cilium、Infoblox、Multus、Romana、Plumgrid和Midokura等项目也为CNI提供网络插件的具体实现。下图描述了容器运行环境与各种网络插件通过CNI进行连接的模型。
CNI定义的是容器运行环境与网络插件之间的简单接口规范,通过一个JSON Schema定义CNI插件提供的输入和输出参数。一个容器可以通过绑定多个网络插件加入多个网络中。
CNI规范概述
CNI提供了一种应用容器的插件化网络解决方案,定义对容器网络进行操作和配置的规范,通过插件的形式对CNI接口进行实现。CNI是由rkt Networking Proposal发展而来的,试图提供一种普适的容器网络解决方案。CNI仅关注在创建容器时分配网络资源,和在销毁容器时删除网络资源,这使得CNI规范非常轻巧、易于实现,得到了广泛的支持。
在CNI模型中只涉及两个概念: 容器和网络。
◎ 容器(Container):是拥有独立Linux网络命名空间的环境,例如使用Docker或rkt创建的容器。关键之处是容器需要拥有自己的Linux网络命名空间,这是加入网络的必要条件。
◎ 网络(Network):表示可以互连的一组实体,这些实体拥有各自独立、唯一的IP地址,可以是容器、物理机或者其他网络设备(比如路由器)等。
对容器网络的设置和操作都通过插件(Plugin)进行具体实现,CNI插件包括两种类型:CNI Plugin和IPAM(IP Address Management)Plugin。CNI Plugin负责为容器配置网络资源,IPAM Plugin负责对容器的IP地址进行分配和管理。IPAM Plugin作为CNI Plugin的一部分,与CNI Plugin一起工作。
CNI Plugin插件详解
CNI Plugin包括3个基本接口的定义:添加(ADD)、删除(DELETE)、检查(CHECK)和版本查询(VERSION)。这些接口的具体实现要求插件提供一个可执行的程序,在容器网络添加或删除时进行调用,以完成具体的操作。
(1)添加:将容器添加到某个网络。主要过程为在Container Runtime创建容器时,先创建好容器内的网络命名空间(Network Namespace),然后调用CNI插件为该netns进行网络配置,最后启动容器内的进程。
添加接口的参数如下:
◎ Version:CNI版本号。
◎ ContainerID: 容器ID。
◎ Network namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net。
◎ Network configuration:网络配置JSON文档,用于描述容器待加入的网络。
◎ Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制。
◎ Name of the interface inside the container:容器内的网卡名。
返回的信息如下。
◎ Interfaces list:网卡列表,根据Plugin的实现,可能包括Sandbox Interface名称、主机Interface名称、每个Interface的地址等信息。
◎ IPs assigned to the interface:IPv4或者IPv6地址、网关地址、路由信息等。
◎ DNS information:DNS相关的信息。
(2)删除:容器销毁时将容器从某个网络中删除。
删除接口的参数如下:
◎ Version:CNI版本号。
◎ ContainerID: 容器ID。
◎ Network namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net。
◎ Network configuration:网络配置JSON文档,用于描述容器待加入的网络。
◎ Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制。
◎ Name of the interface inside the container:容器内的网卡名。
(3)检查:检查容器网络是否正确设置。
检查接口的参数如下:
◎ ContainerID: 容器ID。
◎ Network namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net。
◎ Network configuration:网络配置JSON文档,用于描述容器待加入的网络。
◎ Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制。
◎ Name of the interface inside the container:容器内的网卡名。
(4)版本查询:查询网络插件支持的CNI规范版本号。
无参数,返回值为网络插件支持的CNI规范版本号。
CNI插件应能够支持通过环境变量和标准输入传入参数。可执行文件通过网络配置参数中的type字段标识的文件名在环境变量CNI_PATH设定的路径下进行查找。一旦找到,容器运行时将调用该可执行程序,并传入以下环境变量和网络配置参数,供该插件完成容器网络资源和参数的设置。
环境变量参数如下:
◎ CNI_COMMAND:接口方法,包括ADD、DEL和VERSION。
◎ CNI_CONTAINERID:容器ID。
◎ CNI_NETNS:容器的网络命名空间路径,例如/proc/[pid]/ns/net。
◎ CNI_IFNAME:待设置的网络接口名称。
◎ CNI_ARGS:其他参数,为key=value格式,多个参数之间用分号分隔,例如"FOO=BAR; ABC=123"。
◎ CNI_PATH:可执行文件的查找路径,可以设置多个。
网络配置参数则由一个JSON报文组成,以标准输入(stdin)的方式传递给可执行程序。
网络配置参数如下:
◎ name(string): 网络名称,应在一个管理域内唯一。
◎ type(string):CNI插件的可执行文件的名称。
◎ args(dictionary):其他参数。
◎ ipMasq(boolean):是否设置IP Masquerade(需插件支持),适用于主机可作为网关的环境中。
◎ ipam:IP地址管理的相关配置。
- type(string):IPAM可执行的文件名。
◎ dns:DNS服务的相关配置。
nameservers(list of strings):名字服务器列表,可以使用IPv4或IPv6地址。
- domain(string):本地域名,用于短主机名查询。
- search(list of strings):按优先级排序的域名查询列表。
- options(list of strings):传递给resolver的选项列表。
下面的例子定义了一个名为dbnet的网络配置参数,IPAM使用host-local进行设置:
{
"cniVersion": "0.4.0",
"name": "dbnet",
"type": "bridge",
"bridge": "cni0",
"ipam": {
"type": "host-local",
"subnet": "10.1.0.0/16",
"gateway": "10.1.0.1"
},
"dns": {
"nameservers": ["10.1.0.1"]
}
}
3.IPAM Plugin插件详解
为了减轻CNI Plugin对IP地址管理的负担,在CNI规范中设置了一个新的插件专门用于管理容器的IP地址(还包括网关、路由等信息),被称为IPAM Plugin。通常由CNI Plugin在运行时自动调用IPAM Plugin完成容器IP地址的分配。
IPAM Plugin负责为容器分配IP地址、网关、路由和DNS,典型的实现包括host-local和dhcp。与CNI Plugin类似,IPAM插件也通过可执行程序完成IP地址分配的具体操作。IPAM可执行程序也处理传递给CNI插件的环境变量和标准输入(stdin)传入的网络配置参数。
如果成功完成了容器IP地址的分配,则IPAM插件应该通过标准输出(stdout)返回以下JSON报文:
{
"cniVersion": "0.4.0",
"ips":[
{
"version": "<4-or-6>",
"address": "<ip-and-prefix-in-CIDR>",
"gateway": "<ip-address-of-the-gateway>" (optional)
},
..........
],
"routes":[
{
"dst": "<ip-and-prefix-in-cidr>",
"gw": "<ip-of-next-hop>"
},
........
]
"dns":{
"nameservers": <list-of-nameservers> (optional)
"domain": <name-of-local-domain> (optional)
"search": <list-of-options> (optional)
}
}
其中包括ips、routes和dns三段内容。
◎ ips段:分配给容器的IP地址(也可能包括网关)。
◎ routes段:路由规则记录。
◎ dns段:DNS相关的信息。
4.多网络插件
在很多情况下,一个容器需要连接多个网络,CNI规范支持为一个容器运行多个CNI Plugin来实现这个目标。多个网络插件将按照网络配置列表中的顺序执行,并将前一个网络配置的执行结果传递给后面的网络配置。多网络配置用JSON报文进行配置,包括如下信息。
◎ cniVersion(string):CNI版本号。
◎ name(string):网络名称,应在一个管理域内唯一,将用于下面的所有Plugin。
◎ plugins(list):网络配置列表。
下面的例子定义了两个网络配置参数,分别作用于两个插件,第1个为bridge,第2个为tuning。CNI将首先执行第1个bridge插件设置容器的网络,然后执行第2个tuning插件:
{
"cniVersion": "0.4.1",
"name": "dbnet",
"plugins": [
{
"type": "bridge",
// type (plugin) specific
"bridge": "cni0",
// args may be ignored by plugins
"args": {
"labels": {
"appVersion": "1.0"
}
},
"ipam": {
"type": "host-local",
// ipam specific
"subnet": "10.1.0.0/16",
"gateway": "10.1.0.1"
},
"dns": {
"nameserver": [ "10.1.0.1" ]
}
},
{
"type": "tuning",
"sysctl": {
"net.core.somaxconn": "500"
}
}
]
}
在容器运行且执行第1个bridge插件时,网络配置参数将被设置为:
{
"cniVersion": "0.4.1",
"name": "dbnet",
"type": "bridge",
"bridge": "cni0",
"args": {
"labels": {
"appVersion": "1.0"
}
},
"ipam": {
"type": "host-local",
"subnet": "10.1.0.0/16",
"gateway": "10.1.0.1"
},
"dns": {
"nameservers": [ "10.1.0.1" ]
}
}
接下来执行第2个tuning插件,网络配置参数将被设置为:
{
"cniVersion": "0.4.1",
"name": "dbnet",
"type": "tuning",
"sysctl": {
"net.core.somaxconn": "500"
},
"prevResult": {
"ips": [
{
"version": "4",
"address": "10.0.0.5/32"
"interface": 2
}
] ,
"interfaces": [
{"name": "cni0","mac": :"xxxx",},
{"name": "veth3243","nac":"xxxx",},
{"name": "eth0","mac":"xxxx","sandbox":"/var/ryb/netns/blue",}
],
"dbs":{
"baneservers": ["10.1.0.1"]
}
}
}
其中,prevResult字段包含的信息为上一个bridge插件执行的结果。
在删除多个CNI Plugin时,则以逆序执行删除操作,以上例为例,将先删除tuning插件的网络配置,其中prevResult字段包含的信息为新增操作(ADD)时补充的信息:
{
"cniVersion": "0.4.0",
"name": "dbnet",
"type": "tuning",
"sysctl": {
"net.core.somaxconn": "500"
},
"prevResult":{
"ips":[
"version": "4",
"address": "10.0.0.5/32"
"interface": 2
],
"interfaces": [
{"name": "cni0","mac": :"xxxx",},
{"name": "veth3243","nac":"xxxx",},
{"name": "eth0","mac":"xxxx","sandbox":"/var/ryb/netns/blue",}
],
"dbs":{
"baneservers": ["10.1.0.1"]
}
}
}
然后删除bridge插件的网络配置,其中prevResult字段包含的信息也是在新增操作(ADD)时补充的信息:
{
"cniVersion": "0.4.1",
"name": "dbnet",
"type": "bridge",
"vridge": "cni0"
"agrs" :{
"appVersion": "1.0"
},
"ipam": {
"type": "host-local",
// ipam specific
"subnet": "10.1.0.0/16",
"gateway": "10.1.0.1"
},
"dns": {
"nameserver": [ "10.1.0.1" ]
},
"prevResult":{
"ips":[
"version": "4",
"address": "10.0.0.5/32"
"interface": 2
],
"interfaces": [
{"name": "cni0","mac": :"xxxx",},
{"name": "veth3243","nac":"xxxx",},
{"name": "eth0","mac":"xxxx","sandbox":"/var/ryb/netns/blue",}
],
"dbs":{
"baneservers": ["10.1.0.1"]
}
]
}
命令返回信息说明
对于ADD或DELETE操作,返回码为0表示执行成功,非0表示失败,并以JSON报文的格式通过标准输出(stdout)返回操作的结果。
以ADD操作为例,成功将容器添加到网络的结果将返回以下JSON报文。其中ips、routes和dns段的信息应该与IPAM Plugin(IPAM Plugin的说明详见下节)返回的结果相同,重要的是interfaces段,应通过CNI Plugin进行设置并返回。
{
"cniVersion": "0.4.0",
"interfaces": [ (this key omitted by IPAM plugins)
{
"name": "<name>",
"mac": "<MAC address>", (required if L2 addresses are meaningfull)
"sandbox": "<netns path or hypervisor identifier>" (required for container/hypervisor interfaces, empty/omitted for host interfaces)
}
],
"ips": [
{
"version": "<4-or-6>",
"address": "<ip-and-prefix-in-CIDR>",
"gateway": "<ip-address-of-the-gateway>" (optional)
"interface": <numeric index into 'interfaces' list>
},
...
],
"routes": [ (optional)
{
"dst": "<ip-and-prefix-in-cidr>",
"gw": "<ip-of-next-hop>" (optional)
},
...
],
"dns": {
"nameservers": "<list-of-nameservers>", (optional)
"domain": "<name-of-local-domain>", (optional)
"search": "<list-of-search-domains>" (optional)
"options": "<list-of-options>" (optional)
}
}
接口调用失败时,返回码不为0,应通过标准输出返回包含错误信息的如下JSON报文:
{
"cniVersion": "0.4.0",
"code": <numeric-error-code>,
"msg": <short-error-message>,
"details": <long-error-message> (optional)
}
错误码包括如下内容。
◎ CNI版本不匹配。
◎ 在网络配置中存在不支持的字段,详细信息应在msg中说明。
小结:
本章内容大家作文了解即可。
谢谢大家的支持与浏览
更多推荐
所有评论(0)