为 pod 配置多个网络接口

本文档介绍了如何配置 Google Distributed Cloud,以便为 Pod 提供多个网络接口(多 NIC)。pod 的多 NIC 功能可以帮助分离控制平面流量和数据平面流量,从而在层面之间创建隔离。额外的网络接口还可以支持 pod 的多播功能。用户集群、混合集群和独立集群均支持 pod 的多 NIC 功能。管理员类型集群不允许使用该功能。

网络层面隔离对使用网络功能虚拟化 (NFV) 的系统非常重要,这包括广域网 (SD-WAN) 中的软件定义网络、云访问安全代理 (CASB) 和下一代防火墙 (NG-FW)。这些类型的 NFV 依赖于对多个接口的访问,以使管理和数据平面在作为容器运行时保持隔离。

多网络接口配置支持将网络接口与节点池相关联,从而提供性能优势。集群可以包含混合的节点类型。将高性能机器分组到一个节点池中时,您可以向节点池添加其他接口以改善流量。

设置多个网络接口

通常,为 pod 设置多个网络接口包括三个步骤:

  1. 使用集群自定义资源中的 multipleNetworkInterfaces 字段为集群启用多 NIC

  2. 使用 NetworkAttachmentDefinition 自定义资源指定网络接口

  3. 使用 k8s.v1.cni.cncf.io/networks 注解向 pod 分配网络接口

我们还提供更多信息,帮助您以最符合您的网络要求的方式配置和使用多 NIC 功能。

启用多 NIC

如需为 pod 启用多 NIC,请将 multipleNetworkInterfaces 字段添加到集群自定义资源的 clusterNetwork 部分并将其设置为 true

  ...
  clusterNetwork:
    multipleNetworkInterfaces: true
    pods:
      cidrBlocks:
      - 192.168.0.0/16
    services:
      cidrBlocks:
      - 10.96.0.0/20
  ...

指定网络接口

使用 NetworkAttachmentDefinition 自定义资源指定其他网络接口。NetworkAttachmentDefinition 自定义资源对应于可用于您的 Pod 的网络。您可以在集群配置中指定自定义资源(如以下示例所示),也可以直接创建 NetworkAttachmentDefinition 自定义资源。

---
apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: my-cluster
  namespace: cluster-my-cluster
spec:
    type: user
    clusterNetwork:
      multipleNetworkInterfaces: true
...
---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: gke-network-1
  namespace: cluster-my-cluster
spec:
  config: '{
  "cniVersion":"0.3.0",
  "type": "ipvlan",
  "master": "enp2342",  # defines the node interface that this pod interface would
                         map to.
  "mode": "l2",
  "ipam": {
    "type": "whereabouts",
    "range": "172.120.0.0/24"
  }
}'
---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: gke-network-2
  namespace: cluster-my-cluster
spec:
  config: '{
  "cniVersion":"0.3.0",
  "type": "macvlan",
  "mode": "bridge",
  "master": "vlan102",
  "ipam": {
    "type": "static",
    "addresses": [
      {
        "address": "10.10.0.1/24",
        "gateway": "10.10.0.254"
      }
    ],
    "routes": [
      { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }
    ]
  }
}'

在集群配置文件中指定 NetworkAttachmentDefinition 自定义资源时,Google Distributed Cloud 会在创建集群后使用此名称来控制 NetworkAttachmentDefinition 自定义资源。Google Distributed Cloud 会将集群命名空间内的这一自定义资源视为可信来源,并将其与目标集群的 default 命名空间协调。

下图说明了 Google Distributed Cloud 如何将 NetworkAttachmentDefinition 自定义资源从集群专用命名空间到 default 命名空间进行协调。

NetworkAttachmentDefinition 协调

虽然这是可选项,但我们建议您在集群创建期间以这种方式指定 NetworkAttachmentDefinition 自定义资源。在集群创建期间指定自定义资源时,用户集群将受益最大,因为您可以从管理员集群控制 NetworkAttachmentDefinition 自定义资源。

如果您选择在集群创建期间不指定 NetworkAttachmentDefinition 自定义资源,则可以之后将 NetworkAttachmentDefinition 自定义资源直接添加到现有目标集群。Google Distributed Cloud 会协调集群命名空间中定义的 NetworkAttachmentDefinition 自定义资源。在执行删除操作时也会进行协调。从集群命名空间中移除 NetworkAttachmentDefinition 自定义资源时,Google Distributed Cloud 会从目标集群中移除该自定义资源。

将网络接口分配给 pod

使用 k8s.v1.cni.cncf.io/networks 注解为 pod 分配一个或多个网络接口。每个网络接口都使用命名空间和 NetworkAttachmentDefinition 自定义资源的名称指定,并以正斜杠 (/) 分隔。

---
apiVersion: v1
kind: Pod
metadata:
  name: samplepod
  annotations:
    k8s.v1.cni.cncf.io/networks: NAMESPACE/NAD_NAME
spec:
  containers:
  ...

请替换以下内容:

  • NAMESPACE:命名空间。对于默认命名空间请使用 default,这是标准选项。如需了解例外情况,请参阅安全考量
  • NAD_NAMENetworkAttachmentDefinition 自定义资源的名称。

使用英文逗号分隔列表来指定多个网络接口。

在以下示例中,为 samplepod Pod 分配了两个网络接口。网络接口由目标集群默认命名空间中的两个 NetworkAttachmentDefinition 自定义资源 gke-network-1gke-network-2 的名称指定。

---
apiVersion: v1
kind: Pod
metadata:
  name: samplepod
  annotations:
    k8s.v1.cni.cncf.io/networks: default/gke-network-1,default/gke-network-2
spec:
  containers:
  ...

将网络接口限制为 NodePool

使用 k8s.v1.cni.cncf.io/nodeSelector 注解指定 NetworkAttachmentDefinition 自定义资源对其有效的节点池。Google Distributed Cloud 会将引用此自定义资源的所有 Pod 强制部署到这些特定节点上。在以下示例中,Google Distributed Cloud 会强制部署所有已分配 gke-network-1 网络接口的 Pod 到 multinicNP 节点池。Google Distributed Cloud 会相应地使用 baremetal.cluster.gke.io/node-pool 标签来标记节点池。

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  annotations:
    k8s.v1.cni.cncf.io/nodeSelector: baremetal.cluster.gke.io/node-pool=multinicNP
  name: gke-network-1
spec:
...

您可以使用标准标签以外的标签。您可以通过向节点应用自定义标签,从集群节点创建自己的自定义池。使用 kubectl label nodes 命令应用自定义标签:

kubectl label nodes NODE_NAME LABEL_KEY=LABEL_VALUE

请替换以下内容:

  • NODE_NAME:您要为其添加标签的节点的名称。
  • LABEL_KEY:要用于标签的键。
  • LABEL_VALUE:标签名称。

为节点添加标签后,请在该节点上应用 baremetal.cluster.gke.io/label-taint-no-sync 注解,以防止 Google Distributed Cloud 协调标签。使用 kubectl get nodes --show-labels 命令验证是否已为节点添加标签。

安全考量

NetworkAttachmentDefinition 自定义资源提供对网络的完整访问权限,因此集群管理员在向其他用户提供创建、更新或删除权限时必须小心谨慎。如果必须隔离指定的 NetworkAttachmentDefinition 自定义资源,则可以将其放在非默认命名空间中,只有该命名空间中的 pod 才能访问它。对于集群配置文件中指定的 NetworkAttachmentDefinition 自定义资源,它们将始终放在默认命名空间中以供协调。

在下图中,default 命名空间中的 pod 无法访问 privileged 命名空间中的网络接口。

使用命名空间隔离网络流量

支持的 CNI 插件

本部分列出了 Google Distributed Cloud 的多 NIC 功能支持的 CNI 插件。在指定 NetworkAttachmentDefinition 自定义资源时,请仅使用以下插件。

接口创建:

  • ipvlan
  • macvlan
  • bridge
  • sriov

Meta 插件:

  • portmap
  • sbr
  • tuning

IPAM 插件:

  • host-local
  • static
  • whereabouts

路由配置

具有一个或多个已分配 NetworkAttachmentDefinition 自定义资源的 Pod 具有多个网络接口。在这种情况下,路由表默认仅通过已分配 NetworkAttachmentDefinition 自定义资源中本地可用的其他接口进行扩展。默认网关仍配置为使用 pod 的主/默认接口 eth0

您可以使用以下 CNI 插件修改此行为:

  • sbr
  • static
  • whereabouts

例如,您可能希望所有流量都通过默认网关和默认接口。但是,某些特定流量会经过一个非默认接口。根据目标 IP(正常路由)可能难以区分流量,因为这两种接口类型上的可用端点是同一个。在这种情况下,基于来源的路由 (SBR) 将能够发挥作用。

SBR 插件

sbr 插件可让应用控制路由决策。应用可以控制其建立的连接的来源 IP 地址。如果应用选择使用 NetworkAttachmentDefinition 自定义资源的 IP 地址作为其来源 IP 地址,则数据包会到达 sbr 设置的额外路由表。sbr 路由表将 NetworkAttachmentDefinition 自定义资源的接口指定为默认网关。该表中的默认网关 IP 由 whereaboutsstatic 插件中的 gateway 字段控制。将 sbr 插件作为链式插件提供。如需详细了解 sbr 插件(包括使用方法信息),请参阅基于来源的路由插件

以下示例显示了 whereabouts 中设置的 "gateway":"21.0.111.254",以及 ipvlan 之后设置为链式插件的 sbr

# ip route
default via 192.168.0.64 dev eth0  mtu 1500
192.168.0.64 dev eth0 scope link
# ip route list table 100
default via 21.0.111.254 dev net1
21.0.104.0/21 dev net1 proto kernel scope link src 21.0.111.1

static 插件和 whereabouts 插件

whereabouts 插件基本上是 static 插件的扩展,二者共享路由配置。如需查看配置示例,请参阅静态 IP 地址管理插件。您可以定义要添加到 pod 的路由表的网关和路由。但是,您无法以这种方式修改 pod 的默认网关。

以下示例展示了如何在 NetworkAttachmentDefinition 自定义资源中添加 "routes": [{ "dst": "172.31.0.0/16" }]

# ip route
default via 192.168.0.64 dev eth0  mtu 1500
172.31.0.0/16 via 21.0.111.254 dev net1
21.0.104.0/21 dev net1 proto kernel scope link src 21.0.111.1
192.168.0.64 dev eth0 scope link

配置示例

本部分说明了多 NIC 功能支持的一些常见网络配置。

多个 pod 使用一个网络连接

多个 pod 使用一个网络连接

一个 pod 使用多个网络连接

一个 pod 使用多个网络连接

多个网络连接指向一个 pod 使用的同一接口

多个网络连接指向一个 pod 使用的同一接口

一个 pod 多次使用同一网络连接

一个 pod 多次使用同一网络连接

问题排查

如果额外的网络接口配置有误,则它们分配到的 pod 将不会启动。本部分重点介绍如何查找信息以排查多 NIC 功能的问题。

检查 pod 事件

Multus 通过 Kubernetes pod 事件报告故障。使用以下 kubectl describe 命令查看一个给定 pod 的事件:

kubectl describe pod POD_NAME

检查日志

对于每个节点,您可以在以下位置找到 Whereabouts 和 Multus 日志:

  • /var/log/whereabouts.log
  • /var/log/multus.log

检查 pod 接口

使用 kubectl exec 命令检查 pod 接口。成功应用 NetworkAttachmentDefinition 自定义资源后,Pod 接口应如下所示:

$ kubectl exec samplepod-5c6df74f66-5jgxs -- ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: net1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:82:3e:f0 brd ff:ff:ff:ff:ff:ff
    inet 21.0.103.112/21 scope global net1
       valid_lft forever preferred_lft forever
38: eth0@if39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 36:23:79:a9:26:b3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.2.191/32 scope global eth0
       valid_lft forever preferred_lft forever

获取 pod 状态

使用 kubectl get 检索给定 pod 的网络状态:

kubectl get pods POD_NAME -oyaml

以下示例输出显示了具有多个网络的 pod 的状态:

apiVersion: v1
kind: Pod
metadata:
  annotations:
    k8s.v1.cni.cncf.io/network-status: |-
      [{
          "name": "",
          "interface": "eth0",
          "ips": [
              "192.168.1.88"
          ],
          "mac": "36:0e:29:e7:42:ad",
          "default": true,
          "dns": {}
      },{
          "name": "default/gke-network-1",
          "interface": "net1",
          "ips": [
              "21.0.111.1"
          ],
          "mac": "00:50:56:82:a7:ab",
          "dns": {}
      }]
    k8s.v1.cni.cncf.io/networks: gke-network-1