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

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
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  "cniVersion": "0.4.0",
  "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": {
        "nameservers": [ "10.1.0.1" ]
      }
    },
    {
      "type": "tuning",
      "sysctl": {
        "net.core.somaxconn": "500"
      }
    }
  ]
}

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

ADD

  1. 首先使用下面的配置调用bridge插件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "cniVersion": "0.4.0",
  "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插件,配置中preResult是前面bridge插件的执行结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
  "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": "00:11:22:33:44:55",
        },
        {
            "name": "veth3243",
            "mac": "55:44:33:22:11:11",
        },
        {
            "name": "eth0",
            "mac": "99:88:77:66:55:44",
            "sandbox": "/var/run/netns/blue",
        }
    ],
    "dns": {
      "nameservers": [ "10.1.0.1" ]
    }
  }
}

CHECK

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
  "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": "00:11:22:33:44:55",
        },
        {
            "name": "veth3243",
            "mac": "55:44:33:22:11:11",
        },
        {
            "name": "eth0",
            "mac": "99:88:77:66:55:44",
            "sandbox": "/var/run/netns/blue",
        }
    ],
    "dns": {
      "nameservers": [ "10.1.0.1" ]
    }
  }
}

DEL

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

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

k8s pod网络的CNI配置列表

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

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

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

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

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

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

参考