Netpath
学习路径42 / 49 · K8s 网络看全程 →
实验预计 35 分钟

动手:给 Pod 插第二张网卡

AI 训练和虚拟机场景都需要 Pod 直连物理网。Multus、Spiderpool、MacVLAN 的实际配法。

学完这节你能做到

  • 用注解给 Pod 申请次级网卡与固定 IP 段
  • 解释 MacVLAN、IPvlan、SR-IOV 三种接入方式的差异
  • 判断什么场景必须 hostNetwork、什么场景该用 MacVLAN

什么时候需要第二张网卡

默认 CNI 给的那张 eth0 走软件转发路径,对业务足够。但有两类场景绕不过去:

场景为什么默认 CNI 不行
AI 训练 / 高性能存储要用网卡的 RDMA 能力,软件转发路径帮不上忙(L2 详解)
虚拟机(KubeVirt)虚机需要二层语义:自己的 MAC、能收发任意帧、能跑 DHCP

做法都是给 Pod 插第二张网卡:业务流量走 eth0(默认 CNI), 高性能或二层流量走 net1(次级 CNI)。

Multus:多网卡的调度者

Multus 本身不实现网络,它是个 meta-plugin:kubelet 调它,它再按 Pod 注解去调真正的插件。

kubelet → Multus → ① 默认 CNI(Cilium)→ eth0
                 → ② 按注解调 MacVLAN/SR-IOV → net1

配置载体是 NetworkAttachmentDefinition(NAD),Pod 用注解引用它:

metadata:
  annotations:
    k8s.v1.cni.cncf.io/networks: network-operator/hca
kubectl get network-attachment-definitions -A
# 验证生效:Pod 里应该能看到两张网卡
kubectl exec -it mypod -- ip -brief addr
lo     UNKNOWN  127.0.0.1/8
eth0   UP       10.244.1.7/32          ← 默认 CNI
net1   UP       192.168.0.9/20         ← 次级网卡

Pod 的 status 里也会记录:

kubectl get pod mypod -o jsonpath='{.metadata.annotations.k8s\.v1\.cni\.cncf\.io/network-status}' | jq

实验:MacVLAN + nv-ipam 给 Pod 一张直连网卡

这是 RoCE 场景最常用的组合。前提是节点已装好 network-operator (L2 的 K8s RDMA 那节 讲部署)。

第一步:定义网络与 IP 池

apiVersion: mellanox.com/v1alpha1
kind: MacvlanNetwork
metadata:
  name: hca
  namespace: network-operator
spec:
  networkNamespace: "default"      # 允许哪个命名空间的 Pod 用
  master: "bond0"                  # 从哪张物理卡派生
  mode: "bridge"
  mtu: 1500
  ipam: |
    {
      "type": "nv-ipam",
      "poolName": "hca"
    }
---
apiVersion: nv-ipam.nvidia.com/v1alpha1
kind: IPPool
metadata:
  name: hca
  namespace: network-operator
spec:
  subnet: 192.168.0.0/20
  perNodeBlockSize: 8              # 每节点先领 8 个地址
  gateway: 192.168.0.1
kubectl apply -f macvlan-hca.yaml
kubectl get ippool -n network-operator
kubectl get macvlannetwork -n network-operator

第二步:起一个带次级网卡的 Pod

apiVersion: v1
kind: Pod
metadata:
  name: rdma-test
  annotations:
    k8s.v1.cni.cncf.io/networks: network-operator/hca
spec:
  containers:
    - name: app
      image: mellanox/rping-test
      command: ["sleep", "infinity"]
      resources:
        limits:
          rdma/hca: 1                       # 申请 RDMA 设备
      securityContext:
        capabilities:
          add: ["IPC_LOCK"]                 # 注册内存要锁内存

第三步:验证

# 两张网卡都在
kubectl exec -it rdma-test -- ip -brief addr

# RDMA 设备可见
kubectl exec -it rdma-test -- ibv_devinfo | grep -E 'hca_id|state'
kubectl exec -it rdma-test -- ibdev2netdev

# GID 表里有 RoCEv2 条目(L2 会讲怎么用它)
kubectl exec -it rdma-test -- show_gids | grep v2
×perNodeBlockSize 决定了单节点能跑几个这种 Pod

每个节点从池子里领一整块地址(例子里 8 个)。含义是:

  • 单节点上用这张网的 Pod 最多 8 个,第 9 个分不到 IP,卡在 ContainerCreating
  • 整个池子容量 ÷ 块大小 = 能有多少个节点

和 Pod CIDR 一样,这是一次性决定、事后难改的参数 (K8s 网络模型 那节讲过同类问题)。 按未来的并发任务数算,别按当前用量算。

排查线索:kubectl describe pod 的 Events 里会写 IPAM 分配失败。

三种接入方式怎么选

L4 的 SR-IOV / MacVLAN / IPvlan 那节讲了机制差异, 这里只给选择结论:

方式选它的理由别选它的理由
MacVLAN配置最简单,性能够用交换机限制 MAC 数量时不行
IPvlan交换机开了端口安全、只允许一个 MAC失去独立二层身份
SR-IOV要极致性能、要硬件隔离VF 数量硬件写死、调整要重置网卡

hostNetwork 还是次级网卡

RDMA 场景下这是个真实的取舍,不是理论问题:

hostNetwork: trueMacVLAN 次级网卡
额外组件不需要需要 Multus/Spiderpool + IP 池
Pod IP就是宿主机 IP独立 IP
同节点跑第二个任务❌ 端口冲突✅ 可以
配置复杂度低中
适合单任务独占整机共享集群、多任务并行
!hostNetwork 下同节点起不了第二个任务

hostNetwork: true 让 Pod 直接用宿主机端口空间。NCCL、MPI 的 sshd 都要监听固定端口, 同节点起第二个任务时端口直接撞车,症状是第二个 Pod 一直 CrashLoopBackOff。

这就是共享 GPU 集群要上 MacVLAN 的实际理由:给每个任务一套独立的 IP 与端口空间。 独占整机跑单个大任务时,hostNetwork 更省事。

虚拟机场景:Kube-OVN 作次级 CNI

KubeVirt 里的虚机需要的不是高性能,是二层语义:自己的 MAC、能跑 DHCP、 能做 VLAN、最好还能保留 IP 迁移。Kube-OVN 基于 OVN/OVS,天生提供这些。

典型用法是默认 CNI 保持 Cilium(给容器),Kube-OVN 作为次级 CNI(给虚机):

kubectl get subnets.kubeovn.io
kubectl get vlans.kubeovn.io
kubectl get ips.kubeovn.io | head        # 固定 IP 记录

要点是职责分离:容器网络的性能与策略交给 eBPF 数据平面,虚机的二层需求交给 OVN, 不要试图用一个 CNI 满足两类完全不同的语义。

排障清单

# 1. NAD 存在且命名空间对得上
kubectl get net-attach-def -A

# 2. Pod 注解写对了(namespace/name 格式)
kubectl get pod mypod -o jsonpath='{.metadata.annotations}' | jq

# 3. 网卡真的插上了
kubectl exec -it mypod -- ip -brief addr

# 4. IPAM 有没有分到地址(Events 里最直接)
kubectl describe pod mypod | tail -20

# 5. 节点上的 Multus 与设备插件是否健康
kubectl get pods -n network-operator -o wide
kubectl describe node <node> | grep -A5 'Allocatable'      # 看 rdma/hca 数量

第 5 步里 Allocatable 没有 rdma/hca 这项,说明设备插件没生效—— 那是 L2 那节要解决的问题,不是 Multus 的问题。

检查点

Checkpoint单选

Pod 加了次级网卡注解,但一直 ContainerCreating。describe 显示 IPAM 分配失败。最可能的原因?

Checkpoint单选

共享 GPU 集群,要在同一节点上同时跑两个 RDMA 训练任务。网络该怎么配?

Checkpoint单选

集群里既有容器业务也有 KubeVirt 虚机。比较合理的网络方案是?

这节课的落点

  • 只有两类场景需要第二张网卡:RDMA/高性能 与 虚拟机的二层语义
  • Multus 是 meta-plugin:按 Pod 注解去调真正的插件,配置载体是 NAD
  • 验证插上了没有:ip -brief addr 应该看到 eth0 + net1
  • MacVLAN + nv-ipam 是 RoCE 场景的常用组合;Pod 侧还要 rdma/hca 与 IPC_LOCK
  • perNodeBlockSize 决定单节点能跑几个这种 Pod,与 Pod CIDR 同属一次性决定
  • MacVLAN / IPvlan / SR-IOV 的选择由交换机限制与性能要求决定
  • hostNetwork 简单但同节点跑不了第二个任务;共享集群用 MacVLAN 换独立端口空间
  • 虚机场景用 Kube-OVN 作次级 CNI,职责分离而不是让一个 CNI 兼顾两种语义
  • Allocatable 里没有 rdma/hca 是设备插件的问题,不是 Multus 的问题

延伸资料

  • k8s-in-actionnetwork/network-operator/macvlan/README.md
  • k8s-in-actionnetwork/spiderpool/
  • k8s-in-actionnetwork/kube-ovn/SKILL.md