Linux sriov 的 VF 分配与 DPDK 应用在 Kubernetes 中的实践

13次阅读

vf 需经 sr-iov 插件注册为扩展资源(如 intel.com/sriov_net_0),pod 须声明该资源、挂载 /dev/vfio、启用特权或特定 capabilities,并绕过 cni 直接通过 hostnetwork/loadbalancer 接入流量。

Linux sriov 的 VF 分配与 DPDK 应用在 Kubernetes 中的实践

VF 设备怎么被 Pod 正确识别并挂载

DPDK 应用在容器里跑不起来,八成卡在 VF 没进到 Pod 里。Kubernetes 默认不把 SR-IOV 设备当“可调度资源”处理,vfio-pci 驱动加载后,VF 只是 Linux 设备树里的一个节点,K8s 完全看不见。

必须靠 SR-IOV Network Device Plugin(官方维护的 k8s-sriov-network-device-plugin)把 VF 注册成扩展资源,比如 intel.com/sriov_net_0。它会扫描 /sys/class/net/ 下绑定 vfio-pci 的 VF 接口,生成节点标签和资源名。

  • 确保 VF 已用 echo "vfio-pci" > /sys/bus/pci/devices/0000:xx:yy.z/driver_overridebindvfio-pci,否则插件直接跳过
  • 插件 DaemonSet 必须用 hostNetwork: true,否则无法访问宿主机 PCI 设备路径
  • Pod 的 resources.limits["intel.com/sriov_net_0"] 值必须为 1(不能是 "1" 字符串),否则调度失败且无明确报错

DPDK 应用启动时找不到 VF PCI 地址

即使 VF 进了 Pod,dpdk-devbind.py -s 看不到设备,或 rte_eal_init()EAL: Couldn't get fd on hugepage fileNo probed devices,本质是容器没拿到 VF 的 PCI 设备节点和 IOMMU 组权限。

VF 不是普通网卡——它需要完整的 PCI 设备文件(/dev/vfio/xxx)+ hugepage + udev 规则 + cgroup device 白名单,缺一不可。

  • Pod spec 中必须显式挂载 /dev/vfio 目录:volumeMounts: [{name: vfio, mountPath: /dev/vfio}],对应 volumes: [{name: vfio, hostPath: {path: /dev/vfio}}]
  • 启用 securityContext.privileged: true(DPDK 早期版本绕不开);若用较新 DPDK(22.11+)且内核支持,可改用 capabilities: {add: ["SYS_ADMIN", "IPC_LOCK"]} + 显式 device_cgroup_rules
  • 确保宿主机已开启 IOMMU(intel_iommu=onamd_iommu=on),且 vfio-pci 在 initramfs 里加载(否则重启后 VF 绑定丢失)

Kubernetes Service 和 CNI 怎么绕过 VF 流量

VF 被 Pod 独占后,传统 CNI(如 Calico、Cilium)的 veth pair、iptables、eBPF 转发全部失效。Service ClusterIP 流量不会自动进入 VF,更不会被 DPDK 应用收到。

这不是配置问题,是架构冲突:DPDK 绕过内核协议栈,而 K8s Service 依赖内核 netfilter。想让外部流量进 VF,只能走外部负载均衡或 HostPort + 物理网络直通。

  • 不要给 DPDK Pod 配 service: ClusterIP,它根本收不到请求;可用 type: LoadBalancer 并配合 MetalLB 或硬件 LB 将流量导向宿主机物理端口
  • 若需同节点其他 Pod 访问该 DPDK 服务,必须走 HostNetwork + NodePort,并在宿主机上用 iptables DNAT 把目标端口映射到 VF 绑定的物理 IP(注意:不是容器 IP)
  • CNI 插件如 multus 可为 Pod 添加第二接口(例如 macvlan 到 VF 所在物理网卡),但该接口仍需 DPDK 应用自己调用 rte_eth_dev_start() 启用,CNI 不参与数据面

VF 数量变化时 Pod 调度失败却没提示

宿主机上增删 VF(echo 4 > /sys/class/net/enp1s0f0/device/sriov_numvfs)后,kubectl describe nodeintel.com/sriov_net_0 的 Allocatable 数没更新,旧 Pod 可能卡在 Pending,新 Pod 调度失败但事件里只显示“0/1 nodes are available”,完全不提 SR-IOV 资源不足。

因为 Device Plugin 不监听 sysfs 变化,只在启动时扫描一次。手动触发重发现必须删掉插件的 DaemonSet 再重装,或者用它的 rescan 接口(如果启用了 HTTP endpoint)。

  • 上线前务必固定 VF 数量,避免运行时调整;生产环境建议用 modprobe.conf 设置 options ixgbe max_vfs=4 等参数固化
  • 检查 Device Plugin 日志:kubectl logs -n kube-system ds/sriov-network-device-plugin -c sriov-network-device-plugin | grep -i "found.*vf",确认实际发现数量
  • 别依赖 kubectl top node 查 SR-IOV 资源,它只显示 CPU/Mem;要用 kubectl describe nodeCapacityAllocatable 下的自定义资源行

VF 生命周期和内核驱动状态强耦合,任何一步绑定失败都不会抛出清晰错误,而是静默降级到普通网卡模式——这时候 DPDK 应用可能还在跑,但早已不在预期的数据路径上。

text=ZqhQzanResources