上一篇 下一篇 分享链接 返回 返回顶部

如何在香港服务器运行 RHEL 9 时,结合 OpenShift 与 SR‑IOV 网络,提升容器化应用带宽?

发布人:Minchunlin 发布时间:2025-09-02 10:40 阅读量:777


凌晨1点40,香港将军澳机房的客户紧急反馈,说他们的容器化行情引擎在港区跨机柜吞吐打不满 25G,延迟还偶有抖动。既要 OpenShift 的调度弹性,又要接近裸金属的带宽与时延——只靠 OVN-Kubernetes 的 overlay 肯定不够。最后我们定了方案:在 RHEL 9 裸机上做 OpenShift(带 Multus),把关键业务网卡走 SR‑IOV,在容器里拿到近似直通的链路。

那晚我用 KVM 推着一箱 Intel XXV710、Mellanox ConnectX‑5 的备件穿过冷通道,想着两个问题:

OpenShift 的 SR‑IOV Operator 在 RHEL 9 Worker 上的边角如何抹平?

带 VLAN 的多租隔离、MTU、VF Trust 与 Spoof Check 在香港这边的交换机策略下会不会“打架”?

1. 目标与边界

目标

  • 把关键容器网卡改走 SR‑IOV,单流吞吐接近线速(25G),P99 延迟低且稳定。
  • 保持与 OpenShift/Multus 的生态兼容:命名空间隔离、弹性调度、YAML 即基础设施。
  • 预留两种模式:netdevice(内核网络栈)与 vfio-pci(DPDK/用户态)。

边界

控制面仍走 OVN-Kubernetes/主机默认网卡;SR‑IOV 只承载东西向/南北向的高速业务面。

不引入专有硬件卸载(例如 SmartNIC 上的交换功能),尽量通用。

2. 现场环境与清单(BOM)

2.1 机柜/链路拓扑(简化)

[Leaf A]====(25G LACP)====[RHEL9 Worker-01]
[Leaf B]====(25G LACP)====[RHEL9 Worker-02]
                   ...

交换机:Arista 7xxx(等价的 Cisco/Juniper 也没问题),端口为 25G,支持 LLDP、LACP、VLAN trunk。

上联到 HKIX 与专线边界,客户侧 VLAN:200/201/202。

2.2 服务器硬件

角色 型号 CPU 内存 系统盘 高速网卡(PF) 驱动 BIOS 要点
Worker Dell R650 2×Intel® Xeon® 6348 256GB 2×960GB SSD 2×Intel XXV710(25G)/ 1×Mellanox ConnectX‑5(25G) i40e/mlx5_core SR‑IOV=Enabled, VT‑d/IOMMU=Enabled, NUMA=Enabled

现场建议:XXV710 更“皮实”,Mellanox 在 DPDK 模式更强;香港机房里 XXV710 的备件也更好找。

2.3 软件版本

  • OS:RHEL 9.3(kernel 5.14 系列)
  • 容器平台:OpenShift 4.14(RHEL Worker 节点)
  • CNI:OVN-Kubernetes + Multus;SR‑IOV Network Operator(openshift-sriov-network-operator)
  • 测试工具:iperf3, qperf, pktgen, tcpdump, ethtool。

注:版本不是唯一解,只要 SR‑IOV Operator 与内核/驱动匹配即可。

3. 原理快述:为什么 SR‑IOV 能提速?

SR‑IOV 把一张物理功能(PF)的网卡划分成多个虚拟功能(VF),每个 VF 都有独立的队列和硬件资源,容器/Pod 直接拿到 VF 网口,绕开 overlay/OVS 的数据面,减少内核路径和转发开销。

在 OpenShift 里,Multus 让 Pod 可以拥有多张网卡,普通业务继续走 Pod 默认网(eth0),而大流量数据面走 SR‑IOV(net1)。

模式:

netdevice:VF 仍走内核网络栈,兼容性好,调试简单。

vfio-pci:把 VF 绑给 VFIO,用户态(DPDK)拉包,吞吐与时延更进一步。

4. RHEL 9 基础准备(裸机)

4.1 BIOS/固件

开启:SR-IOV、Intel VT-d/AMD-Vi、NUMA。

如有“PCIe ARI/ACS”,尽量打开,避免 IOMMU 分组过粗。

4.2 内核参数

# /etc/default/grub(追加或合并)
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt spectre_v2=on mitigations=auto"

grub2-mkconfig -o /boot/grub2/grub.cfg
reboot

4.3 驱动与网络工具

yum -y install ethtool lshw pciutils tcpdump iproute tuned-profiles-cpu-partitioning
modprobe i40e || true
modprobe mlx5_core || true

4.4 验证 SR‑IOV 能力

lspci | egrep -i "(ethernet|network)"
ethtool -i ens1f0 | egrep "driver|version|firmware"
# 确认 Similar to: supports-sriov: yes

5. OpenShift 侧准备

5.1 安装 SR‑IOV Network Operator

oc get ns openshift-sriov-network-operator || oc create ns openshift-sriov-network-operator
# OperatorHub 安装(Web 控制台)或 CLI:
oc apply -f - <<'EOF'
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: sriov-network-operator-sub
  namespace: openshift-sriov-network-operator
spec:
  channel: stable
  name: sriov-network-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
EOF

等待 sriov-network-operator、sriov-device-plugin、sriov-cni 等组件 Ready。

5.2 为节点打标(选择哪些节点开 SR‑IOV)

# 只让 Worker-01/02 参与 SR‑IOV
oc label node worker-01 sriov.node=true --overwrite
oc label node worker-02 sriov.node=true --overwrite

6. 划分 VF:SriovNetworkNodePolicy(关键)

小技巧:先把 PF 从 Bond/LACP 中解耦再划 VF;否则 echo sriov_numvfs 可能报忙。

提醒:如果你一开始只想验证,可以先划 4 个 VF;上线前再扩到 16/32。

# policy-intel25g.yaml
apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetworkNodePolicy
metadata:
  name: policy-intel25g
  namespace: openshift-sriov-network-operator
spec:
  resourceName: intelnics               # 将来 Pod 里用 openshift.io/intelnics 申请
  nodeSelector:
    sriov.node: "true"                 # 仅对打标节点生效
  numVfs: 16                            # 每个 PF 划 16 个 VF
  mtu: 9000                             # 建议 jumbo,具体看园区网络是否放通
  linkType: ethernet
  isRdma: false                         # 需要 RDMA 时改 true(Mellanox 常用)
  deviceType: netdevice                 # 或 vfio-pci(用于 DPDK 模式)
  nicSelector:
    pfNames:
      - ens1f0                          # 按实际 PF 名称
      - ens1f1
  spoofChk: "off"                       # 可选:关闭防欺骗,配合 Trust 使用
  trust: "on"                           # 可选:允许 VF 修改自身 MAC/VLAN 等

应用并观察状态:

oc apply -f policy-intel25g.yaml
watch -n1 oc get SriovNetworkNodeState -n openshift-sriov-network-operator
# 等待对应 node 的 status.interface 数组里出现 VF 列表与 MTU=9000

现场坑 1:MTU 不一致。交换机端口 trunk 的原生 VLAN + QOS 队列有时会把 MTU 限到 9200;你设 9000 没问题,但遇到 overlay 的 50-100 字节开销时,实际有效 MTU 会掉。建议机房侧端到端 9216 或更高,并用 ping -M do -s 8972 验证。

7. 定义 SR‑IOV 业务网络(SriovNetwork)

我们为每个租户/业务划一个 VLAN:

# sriov-net-a.yaml
apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetwork
metadata:
  name: net-a
  namespace: openshift-sriov-network-operator
spec:
  resourceName: intelnics
  networkNamespace: demo             # 会在 demo 命名空间里创建 NAD
  vlan: 200                          # 交换机 trunk 放通 200
  ipam: |
    {
      "type": "host-local",
      "ranges": [[{"subnet": "10.200.0.0/24"}]],
      "routes": [{"dst": "0.0.0.0/0"}],
      "dataDir": "/var/lib/cni/networks"
    }

创建业务命名空间并应用:

oc create ns demo || true
oc apply -f sriov-net-a.yaml
oc get network-attachment-definition -n demo

现场坑 2:VLAN 模式。有同事把 vlan 当“trunk 列表”填了多个值——SR‑IOV CNI 这里填的是单个接入 VLAN。要 trunk 多 VLAN,请在交换机与 VF Trust 配合下,用 DPDK/内核在容器里再做 VLAN 子接口。

8. 在 Pod 里消费 VF:两种模式

8.1 netdevice(内核栈)示例

# pod-iperf-server.yaml
apiVersion: v1
kind: Pod
metadata:
  name: iperf-srv
  namespace: demo
  annotations:
    k8s.v1.cni.cncf.io/networks: '[{"name":"net-a","namespace":"demo","interface":"net1"}]'
spec:
  nodeSelector:
    sriov.node: "true"
  containers:
    - name: srv
      image: networkstatic/iperf3
      command: ["/bin/sh","-c","ip a && iperf3 -s"]
      resources:
        requests:
          openshift.io/intelnics: "1"
        limits:
          openshift.io/intelnics: "1"
---
# pod-iperf-client.yaml
apiVersion: v1
kind: Pod
metadata:
  name: iperf-cli
  namespace: demo
  annotations:
    k8s.v1.cni.cncf.io/networks: '[{"name":"net-a","namespace":"demo","interface":"net1"}]'
spec:
  nodeSelector:
    sriov.node: "true"
  containers:
    - name: cli
      image: networkstatic/iperf3
      command: ["/bin/sh","-c","sleep 3; ip -br a; iperf3 -c 10.200.0.10 -P 4 -t 60"]
      resources:
        requests:
          openshift.io/intelnics: "1"
        limits:
          openshift.io/intelnics: "1"

部署前,把 server Pod 的 net1 IP(示例是 10.200.0.10)换成实测获得的地址。

8.2 vfio-pci(DPDK)示例

将 SriovNetworkNodePolicy 的 deviceType 改为 vfio-pci 并 oc apply,Operator 会自动短暂重启对应节点的 SR‑IOV 组件(生产上要先 drain)。Pod 里通过 dpdk-devbind.py 绑定 VF,应用自行跑 DPDK(如 VPP/DPDK App)。

# 示例:给 Pod 以 VFIO 直通的 VF
apiVersion: v1
kind: Pod
metadata:
  name: dpdk-pod
  namespace: demo
  annotations:
    k8s.v1.cni.cncf.io/networks: '[{"name":"net-a","namespace":"demo","interface":"net1"}]'
spec:
  nodeSelector:
    sriov.node: "true"
  containers:
    - name: app
      image: quay.io/yourorg/dpdk:22.11
      securityContext:
        capabilities:
          add: ["IPC_LOCK","SYS_RESOURCE","NET_ADMIN","SYS_RAWIO"]
      command: ["/bin/sh","-c","dpdk-devbind.py --status; sleep infinity"]
      resources:
        requests:
          openshift.io/intelnics: "1"
        limits:
          openshift.io/intelnics: "1"

现场坑 3:HugePages。DPDK/vfio-pci 模式通常需要 HugePages:

oc edit machineconfigpool worker
# 或者直接在节点:
echo 16384 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

9. 性能实测:SR‑IOV 之前与之后

测试方法:iperf3 多并发(4~8 流),MTU=9000,服务器与客户端分别落在 worker-01/02,同一租户 VLAN(200)。

场景 模式 单向吞吐(Gbps) 双向(Gbps) P99 时延(µs) Pod CPU(单核%)
基线:OVN-K + 默认 Pod 网 overlay 8.5–10.2 16–18 350–520 65–80
SR‑IOV(netdevice 直连 22.5–24.2 45–47 120–180 30–45
SR‑IOV(vfio-pci + DPDK) 直连 24.8–25.0 49–50 70–110 20–30

解释:25G 环境里,netdevice 已可接近线速;DPDK 在小包与低时延场景更稳。

10. 运维细节:我在现场踩过的坑与解法

VF 划分失败(echo 报 Busy)

现象:echo 16 > /sys/class/net/ens1f0/device/sriov_numvfs 报 Device or resource busy。

原因:PF 处在 bond/LACP 或被 OS/OVS 占用。

解法:先 echo 0 > .../sriov_numvfs,解绑 bond,down 口,再划分;在 OpenShift 里交由 Operator 执行,事前把 PF 从其他网络对象中移除。

MTU 不一致导致间歇丢包

现象:iperf3 带宽波动,tcpdump 见 frag needed。

解法:统一交换机端口、PF、VF、容器内 net1 的 MTU(例如 9000),用 ping -M do -s 8972 端到端验证。

VLAN 与 Trust/SpoofChk 冲突

现象:容器里改 MAC/VLAN 不生效或被交换机挡下。

解法:在 SriovNetworkNodePolicy 开 trust: on、spoofChk: off,交换机端允许 VF 侧切换,严格计费环境则只在特定租户放开。

资源名与调度

现象:Pod 申请 openshift.io/intelnics 失败。

解法:确认 resourceName 与 Pod requests/limits 前缀一致(openshift.io/),并确认该节点 SriovNetworkNodeState 中数量足够。

DPDK 模式下的 NUMA 与 IRQ 亲和

现象:吞吐抖动,CPU 飙升。

解法:让 Pod 绑核到同一 NUMA,tuned 的 cpu-partitioning,irqbalance 关闭或调亲和;DPDK --lcores/--socket-mem 与 VF 所在 NUMA 对齐。

运维可观测性

建议:给 SR‑IOV 网卡打 Prometheus exporter(如 node_exporter Textfile 或 eBPF 指标),记录 per‑VF 的丢包/队列拥塞,配合 ethtool -S 与交换机 show int counters 交叉验证。

升级变更窗口

提醒:deviceType 从 netdevice → vfio-pci 会触发 VF 绑定变化,需要节点 drain;把策略分多份(每 PF 一份),逐步灰度。

11. 生产最佳实践(我总结的 10 条)

  1. 按租户/业务划 SriovNetwork,明确 VLAN,避免共享 VF 池导致抢占。
  2. Node 池分层:有 SR‑IOV 的专用计算池,调度关键业务;普通节点继续走 overlay。
  3. 端到端 MTU 设计:统一 9000/9126,不让任何一跳“掉队”。
  4. 双栈/IPv6:香港双栈越来越常见,IPAM 直接规划 v4/v6 双栈,避免二次返工。
  5. 链路冗余:PF 成对(ens1f0/ens1f1),每个 PF 划相同数量 VF;业务侧用 ECMP/多 IP 会话做容灾。
  6. 带宽配额:交换机对 VF 口做队列与 policer,OpenShift 侧在 Pod/Namespace 设 BandwidthLimit(TC)。
  7. 基准测试留档:每次变更前后都跑相同 iperf3、包长与并发参数,输出保存在 ConfigMap/对象存储。
  8. CrashDump 兜底:高频包场景建议开启 kdump,留存复盘。
  9. Audit:对 SR‑IOV CRD 的变更走 GitOps,YAML 走 MR/Code Review。
  10. 跨地域延迟:香港–深圳/上海跨域链路,SR‑IOV 无法改变物理 RTT,必要时上边界加 TCP 优化或 QUIC。

12. 完整样例(可直接套入实验环境)

假设 PF 为 ens1f0/ens1f1,VLAN=200,命名空间 demo。

# 1) 安装 SR‑IOV Operator(略,见上文)
# 2) 打标节点
oc label node worker-01 sriov.node=true --overwrite
oc label node worker-02 sriov.node=true --overwrite

# 3) 应用策略与网络
oc apply -f policy-intel25g.yaml
oc apply -f sriov-net-a.yaml

# 4) 部署测试 Pod
oc apply -f pod-iperf-server.yaml
oc apply -f pod-iperf-client.yaml

# 5) 验证网卡与带宽
oc rsh -n demo iperf-srv ip a
oc rsh -n demo iperf-cli iperf3 -c <server-ip> -P 4 -t 60

13. 运维复盘:配置与结果“对账表”

现场值 期望/标准 结果
BIOS SR‑IOV/VT‑d Enabled Enabled OK
MTU(端到端) 9000 ≥9000 OK
PF→VF 数量 16/口 16/口 OK
VLAN 放通 200 trunk 200 trunk OK
Pod 资源申请 openshift.io/intelnics=1 =1 OK
吞吐(单向) 24.2 Gbps ≥23 Gbps OK
P99 延迟 120–180 µs ≤200 µs OK

凌晨 3:20,机房空调还是那股熟悉的冷味。最后一轮 iperf3 跑完,曲线稳稳贴在 24+Gbps 上,Grafana 的 CPU 也安静了许多。我们把变更单签完,客户说“像把车道从城市支路并回了高速”。

我懂这句话的意思:OpenShift 负责交通规则与调度,SR‑IOV 负责让车道通畅。当你需要容器的弹性,又想要接近裸金属的网络性能,这条路,值得走一次。

如果你需要把这套方案适配到不同的 NIC(如 X710/XL710/ConnectX‑6)或不同的 VLAN/二层策略,改动的关键点只有三个:PF 名称、numVfs/MTU、VLAN/IPAM。其他,交给 Operator 与 YAML 即可。真有卡点,来机房吹一吹“海风”,我们把每个小按钮一一拨到位.

目录结构
全文