2. Multus 架构原理:CRD 设计、Delegated Plugin 机制与网络附加定义详解

Multus 是 Kubernetes 生态中最主流的多网卡 CNI 插件,其核心设计哲学是 “不替代现有 CNI,而是作为 CNI 的调度器”。它通过自定义资源定义(CRD)和委托插件(Delegated Plugin)机制,让 Pod 能够同时接入多个网络平面,而无需修改底层 CNI 实现。

2.1 Multus 整体架构与工作流

Multus 以 DaemonSet 形式运行在每个节点上,作为 kubelet 调用的“主 CNI 插件”。当 kubelet 请求为 Pod 配置网络时,Multus 首先解析 Pod 的注解,获取网络附加定义列表,然后依次调用每个网络对应的委托 CNI 插件完成配置。

核心角色:Multus 本身不创建网络接口,它只负责编排——读取配置、调用委托插件、合并结果。
Multus 委托调用架构图 kubelet Multus 主插件 解析 Pod 注解 / NAD 委托 CNI 1 (如 macvlan) 委托 CNI 2 (如 ipvlan) 委托 CNI 3 (如 bridge) Pod eth0 net1 net2 ... 说明: Multus 不修改 Pod 的网络命名空间,而是通过 CNI 链式调用,将多个委托插件的执行结果合并到同一个 Pod 网络命名空间中。

2.2 CRD 设计:NetworkAttachmentDefinition

Multus 的核心 CRD 是 NetworkAttachmentDefinition(NAD),它定义了一个可被 Pod 引用的网络配置。NAD 是 Multus 与底层 CNI 配置之间的桥梁。

字段 类型 说明
apiVersion string k8s.cni.cncf.io/v1
kind string NetworkAttachmentDefinition
metadata.name string NAD 名称,Pod 注解中引用
metadata.namespace string NAD 所属命名空间(跨命名空间引用需特殊配置)
spec.config string (JSON) 委托 CNI 的完整配置 JSON 字符串
关键设计:spec.config 字段是一个 JSON 字符串,它直接嵌入委托 CNI 的配置。这意味着 NAD 可以承载任何 CNI 插件的配置,包括 macvlan、ipvlan、bridge、vlan 等。

以下是一个典型的 NAD 示例,定义了一个基于 macvlan 的辅助网络:

apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
  name: macvlan-conf
  namespace: default
spec:
  config: '{
    "cniVersion": "0.3.1",
    "type": "macvlan",
    "master": "eth0",
    "mode": "bridge",
    "ipam": {
      "type": "host-local",
      "subnet": "192.168.1.0/24",
      "rangeStart": "192.168.1.100",
      "rangeEnd": "192.168.1.200",
      "routes": [
        { "dst": "0.0.0.0/0" }
      ]
    }
  }'

2.3 Delegated Plugin 机制详解

委托插件机制是 Multus 实现多网络接入的技术核心。当 Multus 收到 kubelet 的 ADD 请求时,它执行以下步骤:

  1. 读取 Pod 注解:从 Pod 的 k8s.v1.cni.cncf.io/networks 注解中获取需要附加的网络列表。
  2. 解析 NAD 引用:根据注解中的名称和命名空间,查找对应的 NAD 资源。
  3. 提取委托配置:从 NAD 的 spec.config 字段中解析出委托 CNI 的配置 JSON。
  4. 调用委托 CNI:将委托配置传递给对应的 CNI 插件二进制文件(如 macvlan、ipvlan),并执行 ADD 操作。
  5. 合并结果:将所有委托 CNI 返回的接口信息合并,返回给 kubelet。
注意:委托插件机制要求每个委托 CNI 插件必须存在于节点的 CNI_PATH 目录中。Multus 本身不包含任何底层 CNI 实现,它完全依赖系统中已安装的 CNI 插件。
Delegated Plugin 执行流程 1. 读取 Pod 注解 k8s.v1.cni.cncf.io/networks 2. 解析 NAD 查找 NetworkAttachmentDefinition 3. 提取配置 spec.config JSON 4. 调用委托 CNI 执行 ADD 操作 5. 合并接口结果 返回给 kubelet 循环处理每个网络 关键行为: • 每个委托 CNI 在独立的网络命名空间操作,Multus 负责协调 • 委托 CNI 的配置完全由 NAD 的 spec.config 决定,Multus 不做任何修改 • 如果某个委托 CNI 执行失败,Multus 会回滚已创建的网络接口

2.4 Pod 注解与网络选择

Pod 通过注解 k8s.v1.cni.cncf.io/networks 指定要附加的网络。Multus 支持三种引用方式:

引用方式 示例 说明
简单名称 macvlan-conf 引用当前命名空间下的 NAD
命名空间/名称 other-ns/macvlan-conf 引用指定命名空间下的 NAD
JSON 对象 [{"name":"macvlan-conf","namespace":"default"}] 支持更复杂的配置,如指定接口名称

Pod 注解示例:

apiVersion: v1
kind: Pod
metadata:
  name: multi-net-pod
  annotations:
    k8s.v1.cni.cncf.io/networks: macvlan-conf, other-ns/ipvlan-conf
spec:
  containers:
  - name: app
    image: nginx

2.5 网络附加定义(NAD)的配置规范

NAD 的 spec.config 字段必须是一个合法的 CNI 配置 JSON。Multus 对配置有以下要求:

  • 必须包含 cniVersion:指定 CNI 规范版本,推荐 0.3.1 或 1.0.0。
  • 必须包含 type:指定委托 CNI 插件的名称,如 macvlan、ipvlan、bridge。
  • 可选包含 ipam:IP 地址管理配置,如果委托 CNI 需要 IPAM 则必须提供。
  • 可选包含 capabilities:声明该网络支持的能力,如 ips、mac。
最佳实践:建议将 NAD 与使用它的 Pod 放在同一个命名空间中,避免跨命名空间引用带来的权限和可见性问题。如果必须跨命名空间,确保 Multus 的 RBAC 规则允许跨命名空间读取 NAD。

2.6 Multus 与默认 CNI 的协作关系

Multus 通常与一个默认 CNI(如 Calico、Flannel、Cilium)配合使用。默认 CNI 负责 Pod 的主网络接口(eth0),而 Multus 负责附加网络接口(net1、net2 等)。

网络类型 接口名称 负责插件 用途
主网络 eth0 默认 CNI(如 Calico) 集群内通信、Service 访问
附加网络 1 net1 委托 CNI(如 macvlan) 外部网络直连、高性能数据面
附加网络 2 net2 委托 CNI(如 ipvlan) 存储网络、管理网络

Multus 通过 delegates 字段在 CNI 配置中声明默认 CNI 的位置:

{
  "cniVersion": "0.3.1",
  "name": "multus-cni-network",
  "type": "multus",
  "delegates": [
    {
      "type": "calico",
      "name": "k8s-pod-network",
      "capabilities": {"portMappings": true}
    }
  ],
  "kubeconfig": "/etc/cni/net.d/multus.d/multus.kubeconfig"
}

在这个配置中,delegates 数组的第一个元素定义了默认 CNI(Calico),Multus 会优先为 Pod 创建这个网络接口,然后再处理 Pod 注解中指定的附加网络。