本节来学习CNI的网络配置。

CNI网络配置(Network Configuration)

CNI的网络配置是JSON格式的,可以是存储在磁盘中的文件,也可以由容器运行时以其他方式生成。

下面是cni json配置文件中的一些重要字段:

  • cniVersion(string): 描述cni配置遵循的cni规范版本(版本号为语义化版本,如0.4.0)
  • name(string): 表示network name,在主机(或其他管理域)上的所有容器中应该是唯一的
  • type(string): 表示cni插件的可执行文件名
  • args(dictionary, optional): 由容器运行时提供的可选参数。例如,可以通过将标签添加到args下的标签字段,将标签字典传递给CNI插件
  • ipMasq(boolean, optional): 如果插件支持此字段,将为这个网络上的主机设置一个ip伪装(ip masquerade)。如果主机将充当分配给容器的子网的网管,那么这个配置字段是必须的
  • ipam(boolean, optional): 包含具体IPAM(IP地址管理)值的键值对
    • type(string) 表示ipam插件的可执行文件名,如dhscp, host-local, static
  • dns(dictionary, optional): 包含具体DNS配置的键值对
    • nameservers(list of strings, optional): 一个对配置网络可见的按优先级顺序排列的dns服务器列表,列表中的每个值是一个IPV4或IPV6的字符串
    • domain(string, optional): 用于短主机名查找的本地域名
    • search(list of strings, optional): 用于短主机名查找的优先级排序搜索域列表,被大多数解析器(resolver)在解析时优先于domain
    • options (list of strings, optional): 一组可以传递给解析器(resolver)的选项值

cni网络的JSON配置除了上面这些标准字段外,某个具体的插件还可以定义自己的附加字段,但如果配置了插件未定义的字段将会报错。args中配置的附加字段可以用来传递任意数据,如果插件不认识args中传递的字段,将会直接忽略而不会报错。

下面是一些cni网络配置的示例:

 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "type": "bridge",
 5  // type (plugin) specific
 6  "bridge": "cni0",
 7  "ipam": {
 8    "type": "host-local",
 9    // ipam specific
10    "subnet": "10.1.0.0/16",
11    "gateway": "10.1.0.1"
12  },
13  "dns": {
14    "nameservers": [ "10.1.0.1" ]
15  }
16}
 1{
 2  "cniVersion": "0.4.0",
 3  "name": "pci",
 4  "type": "ovs",
 5  // type (plugin) specific
 6  "bridge": "ovs0",
 7  "vxlanID": 42,
 8  "ipam": {
 9    "type": "dhcp",
10    "routes": [ { "dst": "10.3.0.0/16" }, { "dst": "10.4.0.0/16" } ]
11  },
12  // args may be ignored by plugins
13  "args": {
14    "labels" : {
15        "appVersion" : "1.0"
16    }
17  }
18}
 1{
 2  "cniVersion": "0.4.0",
 3  "name": "wan",
 4  "type": "macvlan",
 5  // ipam specific
 6  "ipam": {
 7    "type": "dhcp",
 8    "routes": [ { "dst": "10.0.0.0/8", "gw": "10.0.0.1" } ]
 9  },
10  "dns": {
11    "nameservers": [ "10.0.0.1" ]
12  }
13}

CNI网络配置列表(Network Configuration Lists)

CNI的网络配置列表提供了一种机制,可以为单个容器按已经定义好的顺序运行多个CNI插件,执行过程中将每个插件的结果传递给下一个插件。 CNI的网络配置列表由多个标准的CN网络配置组成。

CNI网络配置也是JSON格式的,可以是存储在磁盘中的文件,也可以由容器运行时以其他方式生成。下面是CNI网络配置列表的字段:

  • cniVersion(string): 描述cni配置遵循的cni规范版本(版本号为语义化版本,如0.4.0)
  • name(string): 表示network name,在主机(或其他管理域)上的所有容器中应该是唯一的
  • disableCheck(string): 如果配置为false,运行时将不会为此配置列表调用CHECK接口
  • plugins(list): 一组CNI网络配置(如前面描述)

当执行一个插件列表时,运行时必须将列表中的每个网络配置的namecniVersion字段替换为列表本身的namecniVersion字段,这样可以确保列表中所有插件的namecniVersion是一致的,避免出现插件之间的版本冲突 。 CNI接口定义了ADD,DEL,VERSION,CHECK等接口,对于CNI网络配置列表在执行时需满足以下要求。 对于ADD操,运行时必须在每一个插件后面的插件的JSON配置中添加一个prevResult字段,该字段必须是前一个插件(如果有的话)执行的JSON格式的结果。 对于CHECK和DEL,运行时必须在每个插件的配置JSON中添加一个prevResult字段(除非DEL不可用可以省略),该字段必须是前一个ADD执行的JSON结果。 对于ADD操作,插件应该将prevResult字段的内容显示到的标准输出中,以允许后边的插件及运行时接收结果,除非它们希想要改或禁抑制前面的结果。 允许插件修改或抑制前一个插件的结果preResult的全部或部分内容。运行时必须使用相同的环境执行列表中的每个插件,对于DEL操作运行时必须以反向顺序执行插件。

当在插件列表上执行一个操作(如ADD或DEL)时发生了错误,运行时必须停止列表的执行。如果ADD执行失败,当运行时决定进行错误处理时,它应该为列表中的所有插件以与上面指定的ADD相反的顺序执行DEL,即使有些插件在ADD操作期间没有被调用。

下面是一些cni网络配置列表的示例:

 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "plugins": [
 5    {
 6      "type": "bridge",
 7      // type (plugin) specific
 8      "bridge": "cni0",
 9      // args may be ignored by plugins
10      "args": {
11        "labels" : {
12            "appVersion" : "1.0"
13        }
14      },
15      "ipam": {
16        "type": "host-local",
17        // ipam specific
18        "subnet": "10.1.0.0/16",
19        "gateway": "10.1.0.1"
20      },
21      "dns": {
22        "nameservers": [ "10.1.0.1" ]
23      }
24    },
25    {
26      "type": "tuning",
27      "sysctl": {
28        "net.core.somaxconn": "500"
29      }
30    }
31  ]
32}

下面一起看一下,对于上面示例的cni网络配置列表容器运行时是如何执行ADD、CHEK、DEL的。

ADD

  1. 首先使用下面的配置调用bridge插件
 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "type": "bridge",
 5  "bridge": "cni0",
 6  "args": {
 7    "labels" : {
 8        "appVersion" : "1.0"
 9    }
10  },
11  "ipam": {
12    "type": "host-local",
13    "subnet": "10.1.0.0/16",
14    "gateway": "10.1.0.1"
15  },
16  "dns": {
17    "nameservers": [ "10.1.0.1" ]
18  }
19}

2.接下来使用下面的配置调用tuning插件,配置中preResult是前面bridge插件的执行结果

 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "type": "tuning",
 5  "sysctl": {
 6    "net.core.somaxconn": "500"
 7  },
 8  "prevResult": {
 9    "ips": [
10        {
11          "version": "4",
12          "address": "10.0.0.5/32",
13          "interface": 2
14        }
15    ],
16    "interfaces": [
17        {
18            "name": "cni0",
19            "mac": "00:11:22:33:44:55",
20        },
21        {
22            "name": "veth3243",
23            "mac": "55:44:33:22:11:11",
24        },
25        {
26            "name": "eth0",
27            "mac": "99:88:77:66:55:44",
28            "sandbox": "/var/run/netns/blue",
29        }
30    ],
31    "dns": {
32      "nameservers": [ "10.1.0.1" ]
33    }
34  }
35}

CHECK

  1. 首先使用下面的配置调用brdige插件,配置中的preResutl包含ADD的执行结果
 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "type": "bridge",
 5  "bridge": "cni0",
 6  "args": {
 7    "labels" : {
 8        "appVersion" : "1.0"
 9    }
10  },
11  "ipam": {
12    "type": "host-local",
13    // ipam specific
14    "subnet": "10.1.0.0/16",
15    "gateway": "10.1.0.1"
16  },
17  "dns": {
18    "nameservers": [ "10.1.0.1" ]
19  }
20  "prevResult": {
21    "ips": [
22        {
23          "version": "4",
24          "address": "10.0.0.5/32",
25          "interface": 2
26        }
27    ],
28    "interfaces": [
29        {
30            "name": "cni0",
31            "mac": "00:11:22:33:44:55",
32        },
33        {
34            "name": "veth3243",
35            "mac": "55:44:33:22:11:11",
36        },
37        {
38            "name": "eth0",
39            "mac": "99:88:77:66:55:44",
40            "sandbox": "/var/run/netns/blue",
41        }
42    ],
43    "dns": {
44      "nameservers": [ "10.1.0.1" ]
45    }
46  }
47}

2.接下来使用下面的配置调用tuning插件,配置中的preResutl包含ADD的执行结果

 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "type": "tuning",
 5  "sysctl": {
 6    "net.core.somaxconn": "500"
 7  },
 8  "prevResult": {
 9    "ips": [
10        {
11          "version": "4",
12          "address": "10.0.0.5/32",
13          "interface": 2
14        }
15    ],
16    "interfaces": [
17        {
18            "name": "cni0",
19            "mac": "00:11:22:33:44:55",
20        },
21        {
22            "name": "veth3243",
23            "mac": "55:44:33:22:11:11",
24        },
25        {
26            "name": "eth0",
27            "mac": "99:88:77:66:55:44",
28            "sandbox": "/var/run/netns/blue",
29        }
30    ],
31    "dns": {
32      "nameservers": [ "10.1.0.1" ]
33    }
34  }
35}

DEL

DEL执行插件的顺序与ADD和CHECK相反。

  1. 首先使用下面的配置调用tuning插件,配置中的preResult字段是ADD的执行结果
 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "type": "tuning",
 5  "sysctl": {
 6    "net.core.somaxconn": "500"
 7  },
 8  "prevResult": {
 9    "ips": [
10        {
11          "version": "4",
12          "address": "10.0.0.5/32",
13          "interface": 2
14        }
15    ],
16    "interfaces": [
17        {
18            "name": "cni0",
19            "mac": "00:11:22:33:44:55",
20        },
21        {
22            "name": "veth3243",
23            "mac": "55:44:33:22:11:11",
24        },
25        {
26            "name": "eth0",
27            "mac": "99:88:77:66:55:44",
28            "sandbox": "/var/run/netns/blue",
29        }
30    ],
31    "dns": {
32      "nameservers": [ "10.1.0.1" ]
33    }
34  }
35}
  1. 接下来使用下面的配置调用bridge插件,配置中的preResult字段是ADD的执行结果
 1{
 2  "cniVersion": "0.4.0",
 3  "name": "dbnet",
 4  "type": "bridge",
 5  "bridge": "cni0",
 6  "args": {
 7    "labels" : {
 8        "appVersion" : "1.0"
 9    }
10  },
11  "ipam": {
12    "type": "host-local",
13    // ipam specific
14    "subnet": "10.1.0.0/16",
15    "gateway": "10.1.0.1"
16  },
17  "dns": {
18    "nameservers": [ "10.1.0.1" ]
19  },
20  "prevResult": {
21    "ips": [
22        {
23          "version": "4",
24          "address": "10.0.0.5/32",
25          "interface": 2
26        }
27    ],
28    "interfaces": [
29        {
30            "name": "cni0",
31            "mac": "00:11:22:33:44:55",
32        },
33        {
34            "name": "veth3243",
35            "mac": "55:44:33:22:11:11",
36        },
37        {
38            "name": "eth0",
39            "mac": "99:88:77:66:55:44",
40            "sandbox": "/var/run/netns/blue",
41        }
42    ],
43    "dns": {
44      "nameservers": [ "10.1.0.1" ]
45    }
46  }
47}

k8s pod网络的CNI配置列表

已经学习了CNI网络配置和网络配置列表,再看k8s pod网络的CNI配置列表文件就很清晰了。

使用calico作为k8s pod网络组件时,其CNI将配置列表文件/etc/cni/net.d/10-calico.conflist如下:

 1{
 2  "name": "k8s-pod-network",
 3  "cniVersion": "0.3.1",
 4  "plugins": [
 5    {
 6      "type": "calico",
 7      "datastore_type": "kubernetes",
 8      "mtu": 0,
 9      "nodename_file_optional": false,
10      "log_level": "Info",
11      "log_file_path": "/var/log/calico/cni/cni.log",
12      "ipam": { "type": "calico-ipam", "assign_ipv4" : "true", "assign_ipv6" : "false"},
13      "container_settings": {
14          "allow_ip_forwarding": false
15      },
16      "policy": {
17          "type": "k8s"
18      },
19      "kubernetes": {
20          "k8s_api_root":"https://10.96.0.1:443",
21          "kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
22      }
23    },
24    {
25      "type": "bandwidth",
26      "capabilities": {"bandwidth": true}
27    },
28    {"type": "portmap", "snat": true, "capabilities": {"portMappings": true}}
29  ]
30}

上面的配置中使用calico的k8s-pod-network,遵循cni 0.3.1规范,插件列表配置了calico, bandwidth, portmap插件。

使用flannel作为k8s pod网络组件时,其CNI将配置列表文件10-flannel.conflist如下:

 1{
 2  "name": "cbr0",
 3  "cniVersion": "0.3.1",
 4  "plugins": [
 5    {
 6      "type": "flannel",
 7      "delegate": {
 8        "hairpinMode": true,
 9        "isDefaultGateway": true
10      }
11    },
12    {
13      "type": "portmap",
14      "capabilities": {
15        "portMappings": true
16      }
17    }
18  ]
19}

参考