documentation.suse.com / SUSE Edge 文档 / 产品文档 / 电信功能配置

41 电信功能配置

本章将阐释通过 SUSE Edge for Telco 部署的群集上与电信相关的功能配置。

将使用有关自动置备的一章(第 42 章 “全自动定向网络置备)中所述的定向网络置备部署方法。

本章涵盖以下主题:

41.1 实时内核映像

实时内核映像不一定比标准内核更好。它是针对特定使用场景进行微调的另一种内核。经过微调的实时内核可以降低延迟,但代价是降低了吞吐量。不建议将实时内核用于一般用途,但在本例中,则建议为电信工作负载使用该内核,因为在该场景下,延迟是一项关键考虑因素。

实时内核有四大特性:

  • 确定性执行:

    获得更高的可预测性 — 确保关键业务流程每次都能及时完成并提供高质量的服务,即使系统负载极高的情况下也不例外。通过围隔出关键系统资源供高优先级流程使用,可以确保为时间敏感型应用程序提供更高的可预测性。

  • 低抖动:

    基于高确定性技术的低抖动有助于应用程序与现实世界保持同步。这可以为那些需要持续重复计算的服务提供帮助。

  • 优先级继承:

    优先级继承是指当较高优先级的进程在完成其任务之前需要先等待较低优先级的进程完成时,较低优先级的进程可以提升为较高优先级的功能。SUSE Linux Enterprise Real Time 解决了任务关键型进程的优先级倒置问题。

  • 线程中断:

    在通用操作系统中以中断模式运行的进程不可抢占。在 SUSE Linux Enterprise Real Time 中,这些中断已由可中断的内核线程封装,并允许用户定义的较高优先级进程抢占硬中断和软中断。

    在本例中,如果您安装了 SUSE Linux Micro RT 之类的实时映像,那么就已经安装了实时内核。可以从 SUSE Customer Center 下载实时内核映像。

    注意
    注意

    有关实时内核的详细信息,请访问 SUSE Real Time

41.2 实现低延迟和高性能需指定的内核参数

内核参数必须进行配置,以便实时内核能够正常工作,从而为运行电信工作负载提供最佳性能和低延迟。在为此使用场景配置内核参数时,需要特别注意一些重要的概念:

  • 使用 SUSE 实时内核时需去除 kthread_cpus。此参数控制在哪些 CPU 上创建内核线程。它还控制允许哪些 CPU 用于 PID 1 及加载内核模块(由 kmod 用户空间辅助工具加载)。此参数无法被 SUSE 实时内核识别,因此没有任何效果。

  • 通过 isolcpusnohz_fullrcu_nocbsirqaffinity 隔离 CPU 核心。有关 CPU 绑定技术的完整列表,请参见第 41.3 节 “通过 Tuned 和内核参数实现 CPU 绑定”

  • domain,nohz,managed_irq 标志添加到 isolcpus 内核参数。如果没有任何标志,isolcpus 相当于只指定 domain 标志。这将导致指定的 CPU 无法进行调度,包括内核任务。nohz 标志会停止指定 CPU 上运行的调度器节拍(如果一个 CPU 上只有一个任务可运行),managed_irq 标志可避免在指定 CPU 上路由受管理的外部(设备)中断。需要注意的是,NVMe 设备的中断请求 (IRQ) 线路由内核全权管理,因此会被路由至非隔离(系统管理)核心。例如,本节末尾提供的命令行会导致系统中仅分配 4 个队列(外加 1 个管理/控制队列):

    for I in $(grep nvme0 /proc/interrupts | cut -d ':' -f1); do cat /proc/irq/${I}/effective_affinity_list; done | column
    39      0       19      20      39

    此行为可防止磁盘 I/O 对运行在隔离核心上的任何时间敏感型应用程序造成干扰,但可能需要对以存储为重点的工作负载进行关注和精心设计。

  • 调整节拍(内核的周期性定时器中断):

    • skew_tick=1:有时可能同时发生多个节拍。将 skew_tick 设置为 1 可使所有 CPU 不在同一时刻接收定时器节拍,而是在略微错开的时间点接收。这有助于减少系统抖动,从而实现更一致且更低的中断响应时间(这是对延迟敏感型应用程序的基本要求)。

    • nohz=on:停止空闲 CPU 上的周期性定时器节拍。

    • nohz_full=<cpu-cores>:停止专用于实时应用程序的指定 CPU 上的周期性定时器节拍。

  • 通过指定 mce=off 禁用计算机检查异常 (MCE) 处理。MCE 是处理器检测到的硬件错误,禁用它们可以避免产生冗余日志。

  • 添加 nowatchdog 以禁用软锁死看门狗,该看门狗通过运行在定时器硬中断上下文中的定时器实现。当定时器到期时(即检测到软锁死),它会(在硬中断上下文中)打印警告,违背所有延迟目标。即便从未到期,它也会加入定时器列表,略微增加每次定时器中断的开销。此选项还会禁用 NMI 看门狗,因此 NMI 不会造成干扰。

  • nmi_watchdog=0 会禁用 NMI(不可屏蔽中断)看门狗。当使用 nowatchdog 时,可以省略此设置。

  • RCU(读取 - 复制 - 更新)是一种内核机制,允许多个读取器以无锁方式并发访问共享数据。RCU 回调是在“宽限期”后触发的函数,确保所有先前的读取器都已完成操作,从而可以安全地回收旧数据。我们对 RCU 进行微调,特别是针对敏感工作负载,将这些回调从专用(绑定的)CPU 卸载,防止内核操作干扰关键的时间敏感型任务。

    • rcu_nocbs 中指定绑定的 CPU,使 RCU 回调不会在这些 CPU 上运行。这有助于减轻实时工作负载的抖动和延迟。

    • rcu_nocb_poll 会使无回调 CPU 定期“轮询”,以确定是否需要处理回调。这可以减少中断开销。

    • rcupdate.rcu_cpu_stall_suppress=1 会抑制 RCU CPU 停滞警告,在高负载实时系统中,这些警告有时可能是误报。

    • rcupdate.rcu_expedited=1 会加速 RCU 操作的宽限期,使读取端关键部分的响应更加迅速。

    • rcupdate.rcu_normal_after_boot=1 与 rcu_expedited 一起使用时,允许 RCU 在系统引导后恢复到正常(非加速)操作模式。

    • rcupdate.rcu_task_stall_timeout=0 会禁用 RCU 任务停滞检测器,防止长时间运行的 RCU 任务可能引发的警告或系统暂停。

    • rcutree.kthread_prio=99 会将 RCU 回调内核线程的优先级设置为可能的最高值 (99),确保在需要时能够及时调度该线程并处理 RCU 回调。

  • 为使 Metal3 和 Cluster API 成功置备/取消置备群集,请添加 ignition.platform.id=openstack。该配置供 Metal3 Python 代理使用,该代理源自 OpenStack Ironic。

  • 去除 intel_pstate=passive。此选项将 intel_pstate 配置为与通用 cpufreq 调节器搭配工作,但缺点是,为了实现这一点,它会禁用硬件管理的 P 状态 (HWP)。为了减少硬件延迟,不建议将此选项用于实时工作负载。

  • intel_idle.max_cstate=0 processor.max_cstate=1 替换为 idle=poll。为了避免 C 状态转换,使用 idle=poll 选项来禁用 C 状态转换并将 CPU 保持在最高 C 状态。intel_idle.max_cstate=0 选项会禁用 intel_idle,因此使用 acpi_idle,然后 acpi_idle.max_cstate=1 会为 acpi_idl 设置最大 C 状态。在 AMD64/Intel 64 体系结构上,第一个 ACPI C 状态始终是轮询,但它使用 poll_idle() 函数,这可能会因为定期读取时钟并在超时后重启 do_idle() 中的主循环(也涉及清除和设置 TIF_POLL 任务标志)而导致一些细微的延迟。相比之下,idle=poll 以紧凑循环运行,通过忙等待方式等待任务被重新调度。这最大限度地减少了由退出空闲状态造成的延迟,但代价是 CPU 在空闲线程中也要保持全速运行。

  • 在 BIOS 中禁用 C1E。此选项对于禁用 BIOS 中的 C1E 状态非常重要,可以避免 CPU 在空闲时进入 C1E 状态。C1E 状态是一种低功耗状态,可能会在 CPU 空闲时造成延迟。

本文档的其余部分介绍了其他参数,包括大页和 IOMMU。

以下是一个包含上述调整的 32 核 Intel 服务器的内核参数示例:

$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll

以下是一个 64 核 AMD 服务器的配置示例。在 128 个逻辑处理器 (0-127) 中,前 8 个核心 (0-7) 用于系统管理,而其余 120 个核心 (8-127) 专用于运行应用程序:

$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=575291cf-74e8-42cf-8f2c-408a20dc00b8 skew_tick=1 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack amd_iommu=on iommu=pt irqaffinity=0-7 isolcpus=domain,nohz,managed_irq,8-127 nohz_full=8-127 rcu_nocbs=8-127 mce=off nohz=on net.ifnames=0 nowatchdog nmi_watchdog=0 nosoftlockup quiet rcu_nocb_poll rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll

41.3 通过 Tuned 和内核参数实现 CPU 绑定

Tuned 是一个系统调优工具,它通过各种预定义配置文件监控系统状况以优化性能。其关键特性之一是能够为特定工作负载(如实时应用程序)隔离 CPU 核心。这可防止操作系统使用这些核心,从而避免潜在的延迟增加。

要启用和配置此功能,首先应该为我们想要隔离的 CPU 核心创建一个配置文件。在本示例中,64 个核心中,我们将 60 个核心(1-30 和 33-62)专用于应用程序,剩余 4 个核心用于系统管理。需要注意的是,隔离 CPU 的设计在很大程度上取决于实时应用程序的需求。

$ echo "export tuned_params" >> /etc/grub.d/00_tuned

$ echo "isolated_cores=1-30,33-62" >> /etc/tuned/cpu-partitioning-variables.conf

$ tuned-adm profile cpu-partitioning
Tuned (re)started, changes applied.

然后我们需要修改用于隔离 CPU 核心的 GRUB 选项以及其他重要的 CPU 使用参数。请务必根据您的当前硬件规格自定义以下选项:

参数说明

isolcpus

domain,nohz,​managed_irq,1-30,33-62

隔离核心 1-30 和 33-62。domain 表示这些 CPU 属于隔离域。nohz 在这些隔离的 CPU 空闲时启用无节拍操作,以减少中断。managed_irq 使绑定的 CPU 免受 IRQ 干扰。这考虑了 irqaffinity=0-7,它已将大多数 IRQ 定向到系统管理核心。

skew_tick

1

此选项允许内核在隔离的 CPU 之间错开定时器中断。

nohz

on

启用后,内核的周期性定时器中断(即“节拍”)将在任何空闲的 CPU 核心上停止。这主要有益于系统管理 CPU(0、31、32、63)。这可节省电力并减少这些通用核心上不必要的唤醒。

nohz_full

1-30,33-62

对于隔离的核心,这会停止节拍,即使 CPU 运行单个活动任务,也不例外。这意味着它使 CPU 以完全无节拍模式(或“动态节拍”)运行。内核仅在实际需要时才会传递定时器中断。

rcu_nocbs

1-30,33-62

此选项会将 RCU 回调处理从指定的 CPU 核心卸载。

rcu_nocb_poll

 

如果设置此选项,无 RCU 回调的 CPU 将定期“轮询”以确定是否需要处理回调,而不是由其他 CPU 显式唤醒。这可以减少中断开销。

irqaffinity

0,31,32,63

此选项允许内核在系统管理核心上运行中断。

idle

poll

最大限度减少因退出空闲状态造成的延迟,但代价是 CPU 在空闲线程中也要保持全速运行。

nmi_watchdog

0

此选项仅禁用 NMI 看门狗。如果设置了 nowatchdog,则可以省略此选项。

nowatchdog

 

此选项会禁用软锁死看门狗,该看门狗通过运行在定时器硬中断上下文中的定时器实现。

以下命令会修改 GRUB 配置并应用上述更改,以便下次引导时使用更改的配置:

编辑 /etc/default/grub 文件,在其中添加上述参数,如下所示:

GRUB_CMDLINE_LINUX="BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll"

更新 GRUB 配置:

$ transactional-update grub.cfg
$ reboot

要验证重引导后是否应用了这些参数,可使用以下命令检查内核命令行:

$ cat /proc/cmdline

另外还有一个脚本可用于调整 CPU 配置,它主要执行以下步骤:

  • 将 CPU 调节器设置为 performance

  • 取消将定时器迁移到隔离 CPU 的设置。

  • 将 kdaemon 线程迁移到系统管理 CPU。

  • 将隔离的 CPU 延迟设置为尽可能低的值。

  • 将 vmstat 更新延迟到 300 秒。

该脚本可在 SUSE Edge for Telco 示例储存库中获得。

41.4 CNI 配置

41.4.1 Cilium

Cilium 是 SUSE Edge for Telco 的默认 CNI 插件。要在 RKE2 群集上启用 Cilium 作为默认插件,需要在 /etc/rancher/rke2/config.yaml 文件中进行以下配置:

cni:
- cilium

也可以使用命令行参数来指定此配置,即,将 --cni=cilium 添加到 /etc/systemd/system/rke2-server 文件的 server 行中。

要使用下一节(第 41.5 节 “SR-IOV”)中所述的 SR-IOV 网络操作器,请将 Multus 与另一个 CNI 插件(例如 CiliumCalico)一起用作辅助插件。

cni:
- multus
- cilium
注意
注意

有关 CNI 插件的详细信息,请访问 Network Options

41.5 SR-IOV

SR-IOV 允许网络适配器等设备在各种 PCIe 硬件功能之间分隔对其资源的访问。可以通过多种方式部署 SR-IOV,本节将介绍两种不同的方式:

  • 方式 1:使用 SR-IOV CNI 设备插件和配置映射来正确配置 SR-IOV。

  • 方式 2(建议):使用 Rancher Prime 中的 SR-IOV Helm chart 来轻松完成此部署。

方式 1 - 安装 SR-IOV CNI 设备插件并准备配置映射来正确配置 SR-IOV

  • 为设备插件准备配置映射

使用 lspci 命令获取用于填充配置映射的信息:

$ lspci | grep -i acc
8a:00.0 Processing accelerators: Intel Corporation Device 0d5c

$ lspci | grep -i net
19:00.0 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
19:00.1 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
19:00.2 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
19:00.3 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
51:00.0 Ethernet controller: Intel Corporation Ethernet Controller E810-C for QSFP (rev 02)
51:00.1 Ethernet controller: Intel Corporation Ethernet Controller E810-C for QSFP (rev 02)
51:01.0 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:01.1 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:01.2 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:01.3 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.0 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.1 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.2 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.3 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)

配置映射由一个 JSON 文件组成,该文件描述通过过滤器发现的设备,以及创建接口组所需的信息。此处的关键在于理解过滤器和组。过滤器用于发现设备,组用于创建接口。

可以设置过滤器:

  • vendorID:8086 (Intel)

  • deviceID:0d5c(加速卡)

  • driver:vfio-pci(驱动程序)

  • pfNames:p2p1(物理接口名称)

还可以设置过滤器来匹配更复杂的接口语法,例如:

  • pfNames:["eth1#1,2,3,4,5,6"][eth1#1-6](物理接口名称)

至于组,我们可为 FEC 卡创建一个组,为 Intel 卡创建另一个组,甚至可以根据具体使用场景创建一个前缀:

  • resourceName:pci_sriov_net_bh_dpdk

  • resourcePrefix:Rancher.io

有很多组合方式可用于发现并创建资源组,以将一些 VF 分配给 Pod。

注意
注意

有关过滤器和组的详细信息,请访问 sr-iov 网络设备插件

根据硬件和使用场景设置用于匹配接口的过滤器和组后,下面的配置映射展示了一个可使用的示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: sriovdp-config
  namespace: kube-system
data:
  config.json: |
    {
        "resourceList": [
            {
                "resourceName": "intel_fec_5g",
                "devicetype": "accelerator",
                "selectors": {
                    "vendors": ["8086"],
                    "devices": ["0d5d"]
                }
            },
            {
                "resourceName": "intel_sriov_odu",
                "selectors": {
                    "vendors": ["8086"],
                    "devices": ["1889"],
                    "drivers": ["vfio-pci"],
                    "pfNames": ["p2p1"]
                }
            },
            {
                "resourceName": "intel_sriov_oru",
                "selectors": {
                    "vendors": ["8086"],
                    "devices": ["1889"],
                    "drivers": ["vfio-pci"],
                    "pfNames": ["p2p2"]
                }
            }
        ]
    }
  • 准备 daemonset 文件以部署设备插件。

设备插件支持多种体系结构(armamdppc64le),因此同一文件可用于不同的体系结构,以便为每个体系结构部署多个 daemonset

apiVersion: v1
kind: ServiceAccount
metadata:
  name: sriov-device-plugin
  namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-sriov-device-plugin-amd64
  namespace: kube-system
  labels:
    tier: node
    app: sriovdp
spec:
  selector:
    matchLabels:
      name: sriov-device-plugin
  template:
    metadata:
      labels:
        name: sriov-device-plugin
        tier: node
        app: sriovdp
    spec:
      hostNetwork: true
      nodeSelector:
        kubernetes.io/arch: amd64
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      serviceAccountName: sriov-device-plugin
      containers:
      - name: kube-sriovdp
        image: rancher/hardened-sriov-network-device-plugin:v3.7.0-build20240816
        imagePullPolicy: IfNotPresent
        args:
        - --log-dir=sriovdp
        - --log-level=10
        securityContext:
          privileged: true
        resources:
          requests:
            cpu: "250m"
            memory: "40Mi"
          limits:
            cpu: 1
            memory: "200Mi"
        volumeMounts:
        - name: devicesock
          mountPath: /var/lib/kubelet/
          readOnly: false
        - name: log
          mountPath: /var/log
        - name: config-volume
          mountPath: /etc/pcidp
        - name: device-info
          mountPath: /var/run/k8s.cni.cncf.io/devinfo/dp
      volumes:
        - name: devicesock
          hostPath:
            path: /var/lib/kubelet/
        - name: log
          hostPath:
            path: /var/log
        - name: device-info
          hostPath:
            path: /var/run/k8s.cni.cncf.io/devinfo/dp
            type: DirectoryOrCreate
        - name: config-volume
          configMap:
            name: sriovdp-config
            items:
            - key: config.json
              path: config.json
  • 应用配置映射和 daemonset 后,将部署设备插件,发现接口并将其提供给 Pod 使用。

    $ kubectl get pods -n kube-system | grep sriov
    kube-system  kube-sriov-device-plugin-amd64-twjfl  1/1  Running  0  2m
  • 检查节点中发现的且可供 Pod 使用的接口:

    $ kubectl get $(kubectl get nodes -oname) -o jsonpath='{.status.allocatable}' | jq
    {
      "cpu": "64",
      "ephemeral-storage": "256196109726",
      "hugepages-1Gi": "40Gi",
      "hugepages-2Mi": "0",
      "intel.com/intel_fec_5g": "1",
      "intel.com/intel_sriov_odu": "4",
      "intel.com/intel_sriov_oru": "4",
      "memory": "221396384Ki",
      "pods": "110"
    }
  • FECintel.com/intel_fec_5g,值为 1。

  • 如果您部署 SR-IOV 时使用了设备插件和配置映射,但未使用 Helm chart,则 VFintel.com/intel_sriov_oduintel.com/intel_sriov_oru

重要
重要

如果此处没有接口,则继续操作就意义不大,因为 Pod 没有可用的接口。请先检查配置映射和过滤器来解决问题。

方式 2(建议)- 使用 Rancher 和 Helm chart 安装 SR-IOV CNI 和设备插件

  • 获取 Helm(如果没有):

$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
  • 安装 SR-IOV。

helm install sriov-crd oci://registry.suse.com/edge/charts/sriov-crd -n sriov-network-operator
helm install sriov-network-operator oci://registry.suse.com/edge/charts/sriov-network-operator -n sriov-network-operator
  • 检查已部署的资源 CRD 和 Pod:

$ kubectl get crd
$ kubectl -n sriov-network-operator get pods
  • 检查节点中的标签。

所有资源都运行后,标签会自动出现在您的节点中:

$ kubectl get nodes -oyaml | grep feature.node.kubernetes.io/network-sriov.capable

feature.node.kubernetes.io/network-sriov.capable: "true"
  • 查看 daemonset,您会看到新的 sriov-network-config-daemonsriov-rancher-nfd-worker 处于活动状态并已准备就绪:

$ kubectl get daemonset -A
NAMESPACE             NAME                            DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                                           AGE
calico-system            calico-node                     1         1         1       1            1           kubernetes.io/os=linux                                  15h
sriov-network-operator   sriov-network-config-daemon     1         1         1       1            1           feature.node.kubernetes.io/network-sriov.capable=true   45m
sriov-network-operator   sriov-rancher-nfd-worker        1         1         1       1            1           <none>                                                  45m
kube-system              rke2-ingress-nginx-controller   1         1         1       1            1           kubernetes.io/os=linux                                  15h
kube-system              rke2-multus-ds                  1         1         1       1            1           kubernetes.io/arch=amd64,kubernetes.io/os=linux         15h

几分钟后(最多可能需要 10 分钟才会更新),将检测到节点,其上已配置了 SR-IOV 功能:

$ kubectl get sriovnetworknodestates.sriovnetwork.openshift.io -A
NAMESPACE             NAME     AGE
sriov-network-operator   xr11-2   83s
  • 检查已检测到的接口。

发现的接口应为网络设备的 PCI 地址。请在主机中使用 lspci 命令检查此信息。

$ kubectl get sriovnetworknodestates.sriovnetwork.openshift.io -n kube-system -oyaml
apiVersion: v1
items:
- apiVersion: sriovnetwork.openshift.io/v1
  kind: SriovNetworkNodeState
  metadata:
    creationTimestamp: "2023-06-07T09:52:37Z"
    generation: 1
    name: xr11-2
    namespace: sriov-network-operator
    ownerReferences:
    - apiVersion: sriovnetwork.openshift.io/v1
      blockOwnerDeletion: true
      controller: true
      kind: SriovNetworkNodePolicy
      name: default
      uid: 80b72499-e26b-4072-a75c-f9a6218ec357
    resourceVersion: "356603"
    uid: e1f1654b-92b3-44d9-9f87-2571792cc1ad
  spec:
    dpConfigVersion: "356507"
  status:
    interfaces:
    - deviceID: "1592"
      driver: ice
      eSwitchMode: legacy
      linkType: ETH
      mac: 40:a6:b7:9b:35:f0
      mtu: 1500
      name: p2p1
      pciAddress: "0000:51:00.0"
      totalvfs: 128
      vendor: "8086"
    - deviceID: "1592"
      driver: ice
      eSwitchMode: legacy
      linkType: ETH
      mac: 40:a6:b7:9b:35:f1
      mtu: 1500
      name: p2p2
      pciAddress: "0000:51:00.1"
      totalvfs: 128
      vendor: "8086"
    syncStatus: Succeeded
kind: List
metadata:
  resourceVersion: ""
注意
注意

如果此处未检测到您的接口,请确保该接口存在于下一个配置映射中:

$ kubectl get cm supported-nic-ids -oyaml -n sriov-network-operator

如果此处未检测到您的设备,请编辑配置映射,添加要发现的正确值(如有必要,请重启 sriov-network-config-daemon daemonset)。

  • 创建 NetworkNode 策略来配置 VF

将在设备 (rootDevices) 中创建一些 VF (numVfs),并在其上配置驱动程序 deviceTypeMTU

注意
注意

resourceName 字段不得包含任何特殊字符,并且在整个群集中必须是唯一的。该示例使用 deviceType: vfio-pci,因为 dpdk 将与 sr-iov 结合使用。如果您不使用 dpdk,则 deviceType 应为 deviceType: netdevice(默认值)。

apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetworkNodePolicy
metadata:
  name: policy-dpdk
  namespace: sriov-network-operator
spec:
  nodeSelector:
    feature.node.kubernetes.io/network-sriov.capable: "true"
  resourceName: intelnicsDpdk
  deviceType: vfio-pci
  numVfs: 8
  mtu: 1500
  nicSelector:
    deviceID: "1592"
    vendor: "8086"
    rootDevices:
    - 0000:51:00.0
  • 验证配置:

$ kubectl get $(kubectl get nodes -oname) -o jsonpath='{.status.allocatable}' | jq
{
  "cpu": "64",
  "ephemeral-storage": "256196109726",
  "hugepages-1Gi": "60Gi",
  "hugepages-2Mi": "0",
  "intel.com/intel_fec_5g": "1",
  "memory": "200424836Ki",
  "pods": "110",
  "rancher.io/intelnicsDpdk": "8"
}
  • 创建 sr-iov 网络(可选操作,仅在需要不同的网络时才执行):

apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetwork
metadata:
  name: network-dpdk
  namespace: sriov-network-operator
spec:
  ipam: |
    {
      "type": "host-local",
      "subnet": "192.168.0.0/24",
      "rangeStart": "192.168.0.20",
      "rangeEnd": "192.168.0.60",
      "routes": [{
        "dst": "0.0.0.0/0"
      }],
      "gateway": "192.168.0.1"
    }
  vlan: 500
  resourceName: intelnicsDpdk
  • 检查创建的网络:

$ kubectl get network-attachment-definitions.k8s.cni.cncf.io -A -oyaml

apiVersion: v1
items:
- apiVersion: k8s.cni.cncf.io/v1
  kind: NetworkAttachmentDefinition
  metadata:
    annotations:
      k8s.v1.cni.cncf.io/resourceName: rancher.io/intelnicsDpdk
    creationTimestamp: "2023-06-08T11:22:27Z"
    generation: 1
    name: network-dpdk
    namespace: sriov-network-operator
    resourceVersion: "13124"
    uid: df7c89f5-177c-4f30-ae72-7aef3294fb15
  spec:
    config: '{ "cniVersion":"0.4.0", "name":"network-dpdk","type":"sriov","vlan":500,"vlanQoS":0,"ipam":{"type":"host-local","subnet":"192.168.0.0/24","rangeStart":"192.168.0.10","rangeEnd":"192.168.0.60","routes":[{"dst":"0.0.0.0/0"}],"gateway":"192.168.0.1"}
      }'
kind: List
metadata:
  resourceVersion: ""

41.6 DPDK

DPDK(数据平面开发包)是一组用于实现快速数据包处理的库和驱动程序。它用于加速各种 CPU 体系结构上运行的数据包处理工作负载。DPDK 包含以下组件的数据平面库和优化的网络接口控制器 (NIC) 驱动程序:

  1. 队列管理器,实现无锁队列。

  2. 缓冲区管理器,预先分配固定大小的缓冲区。

  3. 内存管理器,在内存中分配对象池,并使用环来存储空闲对象;确保对象均匀分布在所有 DRAM 通道上。

  4. 轮询模式驱动程序 (PMD),可在没有异步通知的情况下运行,从而降低开销。

  5. 作为一组库提供的数据包框架,可帮助开发数据包处理解决方案。

以下步骤说明如何启用 DPDK,以及如何从 NIC 创建供 DPDK 接口使用的 VF

  • 安装 DPDK 软件包:

$ transactional-update pkg install dpdk dpdk-tools libdpdk-23
$ reboot
  • 内核参数:

要使用 DPDK,请采用一些驱动程序来启用内核中的某些参数:

参数说明

iommu

pt

此选项允许为 DPDK 接口使用 vfio 驱动程序。

intel_iommu 或 amd_iommu

on

此选项允许为 VF 使用 vfio

要启用这些参数,请将其添加到 /etc/default/grub 文件中:

GRUB_CMDLINE_LINUX="BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll"

更新 GRUB 配置,并重引导系统以应用更改:

$ transactional-update grub.cfg
$ reboot
  • 加载 vfio-pci 内核模块,并在 NIC 上启用 SR-IOV

$ modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
  • NIC 创建一些虚拟功能 (VF)。

例如,要为两个不同的 NIC 创建 VF,需要运行以下命令:

$ echo 4 > /sys/bus/pci/devices/0000:51:00.0/sriov_numvfs
$ echo 4 > /sys/bus/pci/devices/0000:51:00.1/sriov_numvfs
  • 将新的 VF 绑定到 vfio-pci 驱动程序:

$ dpdk-devbind.py -b vfio-pci 0000:51:01.0 0000:51:01.1 0000:51:01.2 0000:51:01.3 \
                              0000:51:11.0 0000:51:11.1 0000:51:11.2 0000:51:11.3
  • 检查是否正确应用了配置:

$ dpdk-devbind.py -s

Network devices using DPDK-compatible driver
============================================
0000:51:01.0 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.1 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.2 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.3 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.0 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:11.1 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:21.2 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:31.3 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio

Network devices using kernel driver
===================================
0000:19:00.0 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em1 drv=bnxt_en unused=igb_uio,vfio-pci *Active*
0000:19:00.1 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em2 drv=bnxt_en unused=igb_uio,vfio-pci
0000:19:00.2 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em3 drv=bnxt_en unused=igb_uio,vfio-pci
0000:19:00.3 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em4 drv=bnxt_en unused=igb_uio,vfio-pci
0000:51:00.0 'Ethernet Controller E810-C for QSFP 1592' if=eth13 drv=ice unused=igb_uio,vfio-pci
0000:51:00.1 'Ethernet Controller E810-C for QSFP 1592' if=rename8 drv=ice unused=igb_uio,vfio-pci

41.7 vRAN 加速 (Intel ACC100/ACC200)

随着通讯服务提供商从 4G 过渡到 5G 网络,有许多提供商正在采用虚拟化无线接入网络 (vRAN) 体系结构来提高信道容量及简化基于边缘的服务和应用程序的部署。vRAN 解决方案非常适合用于提供低延迟服务,并可以根据实时流量和网络需求灵活地增加或减少容量。

计算密集程度最高的 4G 和 5G 工作负载之一是 RAN 第 1 层 (L1) FEC,它可以解决不可靠或高干扰信道上的数据传输错误。FEC 技术可以检测并纠正 4G 或 5G 数据中有限数量的错误,因此消除了重新传输的需要。由于 FEC 加速事务不包含特定的单元状态信息,因此可以轻松虚拟化,从而带来了池化优势并可实现轻松的单元迁移。

  • 内核参数

要启用 vRAN 加速,需要启用以下内核参数(如果尚未启用):

参数说明

iommu

pt

此选项允许为 DPDK 接口使用 vfio。

intel_iommu 或 amd_iommu

on

此选项允许为 VF 使用 vfio。

修改 GRUB 文件 /etc/default/grub,以将这些参数添加到内核命令行:

GRUB_CMDLINE_LINUX="BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll"

更新 GRUB 配置,并重引导系统以应用更改:

$ transactional-update grub.cfg
$ reboot

要校验重引导后是否应用了这些参数,请检查命令行:

$ cat /proc/cmdline
  • 加载 vfio-pci 内核模块以启用 vRAN 加速:

$ modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
  • 获取 Acc100 接口信息:

$ lspci | grep -i acc
8a:00.0 Processing accelerators: Intel Corporation Device 0d5c
  • 将物理接口 (PF) 绑定到 vfio-pci 驱动程序:

$ dpdk-devbind.py -b vfio-pci 0000:8a:00.0
  • 从物理接口 (PF) 创建虚拟功能 (VF)。

PF 创建 2 个 VF,并按照以下步骤将其绑定到 vfio-pci

$ echo 2 > /sys/bus/pci/devices/0000:8a:00.0/sriov_numvfs
$ dpdk-devbind.py -b vfio-pci 0000:8b:00.0
  • 使用建议的配置文件配置 acc100:

$ pf_bb_config ACC100 -c /opt/pf-bb-config/acc100_config_vf_5g.cfg
Tue Jun  6 10:49:20 2023:INFO:Queue Groups: 2 5GUL, 2 5GDL, 2 4GUL, 2 4GDL
Tue Jun  6 10:49:20 2023:INFO:Configuration in VF mode
Tue Jun  6 10:49:21 2023:INFO: ROM version MM 99AD92
Tue Jun  6 10:49:21 2023:WARN:* Note: Not on DDR PRQ version  1302020 != 10092020
Tue Jun  6 10:49:21 2023:INFO:PF ACC100 configuration complete
Tue Jun  6 10:49:21 2023:INFO:ACC100 PF [0000:8a:00.0] configuration complete!
  • 检查从 FEC PF 创建的新 VF:

$ dpdk-devbind.py -s
Baseband devices using DPDK-compatible driver
=============================================
0000:8a:00.0 'Device 0d5c' drv=vfio-pci unused=
0000:8b:00.0 'Device 0d5d' drv=vfio-pci unused=

Other Baseband devices
======================
0000:8b:00.1 'Device 0d5d' unused=

41.8 大页

当某个进程使用 RAM 时,CPU 会将 RAM 标记为已由该进程使用。为提高效率,CPU 会以区块的形式分配 RAM,在许多平台上,默认的区块大小值为 4K 字节。这些区块称为页。页可以交换到磁盘等位置。

由于进程地址空间是虚拟的,CPU 和操作系统需要记住哪些页属于哪个进程,以及每个页存储在哪个位置。页数越多,内存映射的搜索时间就越长。当进程使用 1 GB 内存时,需要查找 262144 个项 (1 GB / 4 K)。如果一个页表项占用 8 个字节,则需要查找 2 MB (262144 * 8) 内存。

当前的大多数 CPU 体系结构都支持大于默认值的页,因此减少了 CPU/操作系统需要查找的项。

  • 内核参数

要启用大页,我们应添加以下内核参数。在此例中,我们配置了 40 个 1G 页面,不过大页大小和确切数量应根据应用程序的内存需求进行调整:

参数说明

hugepagesz

1G

此选项允许将大页的大小设置为 1 G

hugepages

40

这是先前定义的大页数量

default_hugepagesz

1G

这是用于获取大页的默认值

修改 GRUB 文件 /etc/default/grub,在 GRUB_CMDLINE_LINUX 中添加这些参数:

default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0

更新 GRUB 配置,并重引导系统以应用更改:

$ transactional-update grub.cfg
$ reboot

要验证重引导后是否应用了这些参数,可以检查命令行:

$ cat /proc/cmdline
  • 使用大页

要使用大页,需要挂载它们:

$ mkdir -p /hugepages
$ mount -t hugetlbfs nodev /hugepages

部署 Kubernetes 工作负载,并创建资源和卷:

...
 resources:
   requests:
     memory: "24Gi"
     hugepages-1Gi: 16Gi
     intel.com/intel_sriov_oru: '4'
   limits:
     memory: "24Gi"
     hugepages-1Gi: 16Gi
     intel.com/intel_sriov_oru: '4'
...
...
volumeMounts:
  - name: hugepage
    mountPath: /hugepages
...
volumes:
  - name: hugepage
    emptyDir:
      medium: HugePages
...

41.9 在 Kubernetes 上进行 CPU 绑定

41.9.1 先决条件

必须根据第 41.3 节 “通过 Tuned 和内核参数实现 CPU 绑定”一节中所述的性能配置文件微调 CPU

41.9.2 配置 Kubernetes 以进行 CPU 绑定

配置 kubelet 参数以在 RKE2 群集中实现 CPU 管理。将以下配置块(如下例所示)添加到 /etc/rancher/rke2/config.yaml 文件中。确保在 kubelet-reservedsystem-reserved 参数中指定系统管理 CPU 核心:

kubelet-arg:
- "cpu-manager-policy=static"
- "cpu-manager-policy-options=full-pcpus-only=true"
- "cpu-manager-reconcile-period=0s"
- "kubelet-reserved=cpu=0,31,32,63"
- "system-reserved=cpu=0,31,32,63"

41.9.3 为工作负载使用绑定的 CPU

根据您在工作负载上定义的请求和限制,可以用三种方式通过 kubelet 中定义的静态策略来使用该功能:

  1. BestEffort QoS 类:如果没有定义任何 CPU 请求或限制,则 Pod 将调度到系统中第一个可用的 CPU 上。

    使用 BestEffort QoS 类的示例如下:

    spec:
      containers:
      - name: nginx
        image: nginx
  2. Burstable QoS 类:如果定义了 CPU 请求且该请求不等于限制值,或者没有定义 CPU 请求,请使用此方式。

    使用 Burstable QoS 类的示例如下:

    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "200Mi"
          requests:
            memory: "100Mi"

    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "200Mi"
            cpu: "2"
          requests:
            memory: "100Mi"
            cpu: "1"
  3. Guaranteed QoS 类:如果定义了 CPU 请求且该请求等于限制值,请使用此方式。

    使用 Guaranteed QoS 类的示例如下:

    spec:
      containers:
        - name: nginx
          image: nginx
          resources:
            limits:
              memory: "200Mi"
              cpu: "2"
            requests:
              memory: "200Mi"
              cpu: "2"

41.10 可感知 NUMA 的调度

非统一内存访问或非统一内存体系结构 (NUMA) 是 SMP(多处理器)体系结构中使用的物理内存设计,其中内存访问时间取决于相对于处理器的内存位置。在 NUMA 下,与访问非本地内存(即,另一个处理器本地的内存,或者在处理器之间共享的内存)相比,处理器可以更快地访问自身的本地内存。

41.10.1 识别 NUMA 节点

要识别 NUMA 节点,请在系统上使用以下命令:

$ lscpu | grep NUMA
NUMA node(s):                       1
NUMA node0 CPU(s):                  0-63
注意
注意

对于此示例,只有一个 NUMA 节点显示了 64 个 CPU

NUMA 需要在 BIOS 中启用。如果 dmesg 中没有引导过程中 NUMA 初始化的记录,则可能表示内核环缓冲区中的 NUMA 相关消息已被重写。

41.11 MetalLB

MetalLB 是裸机 Kubernetes 群集的负载平衡器实现,使用 L2BGP 等标准路由协议作为广告协议。它是一个网络负载平衡器,可用于向外部公开 Kubernetes 群集中的服务(因为需要在裸机上使用 Kubernetes 服务类型 LoadBalancer)。

要在 RKE2 群集中启用 MetalLB,需要执行以下步骤:

  • 使用以下命令安装 MetalLB

$ kubectl apply <<EOF -f
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
  name: metallb
  namespace: kube-system
spec:
  chart: oci://registry.suse.com/edge/charts/metallb
  targetNamespace: metallb-system
  version: 303.0.0+up0.14.9
  createNamespace: true
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
  name: endpoint-copier-operator
  namespace: kube-system
spec:
  chart: oci://registry.suse.com/edge/charts/endpoint-copier-operator
  targetNamespace: endpoint-copier-operator
  version: 303.0.0+up0.2.1
  createNamespace: true
EOF
  • 创建 IpAddressPoolL2advertisement 配置:

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: kubernetes-vip-ip-pool
  namespace: metallb-system
spec:
  addresses:
    - 10.168.200.98/32
  serviceAllocation:
    priority: 100
    namespaces:
      - default
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: ip-pool-l2-adv
  namespace: metallb-system
spec:
  ipAddressPools:
    - kubernetes-vip-ip-pool
  • 创建端点服务来公开 VIP

apiVersion: v1
kind: Service
metadata:
  name: kubernetes-vip
  namespace: default
spec:
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: rke2-api
    port: 9345
    protocol: TCP
    targetPort: 9345
  - name: k8s-api
    port: 6443
    protocol: TCP
    targetPort: 6443
  sessionAffinity: None
  type: LoadBalancer
  • 检查 VIP 是否已创建并且 MetalLB Pod 是否正在运行:

$ kubectl get svc -n default
$ kubectl get pods -n default

41.12 专用注册表配置

可以配置 Containerd 以连接到专用注册表,然后使用专用注册表提取每个节点上的专用映像。

启动时,RKE2 会检查 /etc/rancher/rke2/ 中是否存在 registries.yaml 文件,并指示 containerd 使用该文件中定义的任何注册表。如果您希望使用某个专用注册表,请在要使用该注册表的每个节点上以 root 身份创建此文件。

要添加专用注册表,请创建包含以下内容的 /etc/rancher/rke2/registries.yaml 文件:

mirrors:
  docker.io:
    endpoint:
      - "https://registry.example.com:5000"
configs:
  "registry.example.com:5000":
    auth:
      username: xxxxxx # this is the registry username
      password: xxxxxx # this is the registry password
    tls:
      cert_file:            # path to the cert file used to authenticate to the registry
      key_file:             # path to the key file for the certificate used to authenticate to the registry
      ca_file:              # path to the ca file used to verify the registry's certificate
      insecure_skip_verify: # may be set to true to skip verifying the registry's certificate

或者不设置身份验证:

mirrors:
  docker.io:
    endpoint:
      - "https://registry.example.com:5000"
configs:
  "registry.example.com:5000":
    tls:
      cert_file:            # path to the cert file used to authenticate to the registry
      key_file:             # path to the key file for the certificate used to authenticate to the registry
      ca_file:              # path to the ca file used to verify the registry's certificate
      insecure_skip_verify: # may be set to true to skip verifying the registry's certificate

要使注册表更改生效,需要先配置此文件再在节点上启动 RKE2,或者在配置的每个节点上重启 RKE2。

注意
注意

有关详细信息,请查看 RKE2 containerd 注册表配置

41.13 精确时间协议

精确时间协议 (PTP) 是由电气和电子工程师协会 (IEEE) 开发的一种网络协议,旨在实现计算机网络中的亚微秒级时间同步。自诞生以来的几十年里,PTP 已在许多行业广泛应用。近年来,随着其作为 5G 网络关键要素的重要性凸显,在电信网络中的采用率不断提升。尽管 PTP 协议相对简单,但其配置会因应用场景的不同而有显著差异。为此,已定义并标准化多个配置文件。

本节仅介绍专用于电信行业的配置文件。因此,假设 NIC 具备时间戳能力和 PTP 硬件时钟 (PHC)。如今,所有电信级网络适配器均在硬件层面支持 PTP,但您可以通过以下命令验证此类功能:

# ethtool -T p1p1
Time stamping parameters for p1p1:
Capabilities:
        hardware-transmit
        software-transmit
        hardware-receive
        software-receive
        software-system-clock
        hardware-raw-clock
PTP Hardware Clock: 0
Hardware Transmit Timestamp Modes:
        off
        on
Hardware Receive Filter Modes:
        none
        all

p1p1 替换为用于 PTP 的接口名称。

以下几节将具体介绍如何在 SUSE Edge 上安装和配置 PTP,但以您已熟悉 PTP 的基本概念为前提。如需简要了解 PTP 以及 SUSE Edge for Telco 中包含的实现,请访问 https://documentation.suse.com/sles/html/SLES-all/cha-tuning-ptp.html

41.13.1 安装 PTP 软件组件

在 SUSE Edge for Telco 中,PTP 功能通过 linuxptp 软件包实现,该软件包包含两个组件:

  • ptp4l:控制 NIC 上的 PHC 并运行 PTP 协议的守护程序

  • phc2sys:将系统时钟与 NIC 上经 PTP 同步的 PHC 保持同步的守护程序

要使系统同步正常工作,就必须运行这两个守护程序,并且必须根据您的设置正确配置它们。相关信息,请参见第 41.13.2 节 “为电信部署配置 PTP”

在下游群集中集成 PTP 最简单且最佳的方式是,在 Edge Image Builder (EIB) 定义文件的 packageList 下添加 linuxptp 软件包。这样,在群集置备期间就会自动安装 PTP 控制平面软件。有关安装软件包的详细信息,请参见 EIB 文档(第 3.3.4 节 “配置 RPM 软件包”)。

以下是包含 linuxptp 的 EIB 清单示例:

apiVersion: 1.0
image:
  imageType: RAW
  arch: x86_64
  baseImage: {micro-base-rt-image-raw}
  outputImageName: eibimage-slmicrort-telco.raw
operatingSystem:
  time:
    timezone: America/New_York
  kernelArgs:
    - ignition.platform.id=openstack
    - net.ifnames=1
  systemd:
    disable:
      - rebootmgr
      - transactional-update.timer
      - transactional-update-cleanup.timer
      - fstrim
      - time-sync.target
    enable:
      - ptp4l
      - phc2sys
  users:
    - username: root
      encryptedPassword: ${ROOT_PASSWORD}
  packages:
    packageList:
      - jq
      - dpdk
      - dpdk-tools
      - libdpdk-23
      - pf-bb-config
      - open-iscsi
      - tuned
      - cpupower
      - linuxptp
    sccRegistrationCode: ${SCC_REGISTRATION_CODE}
注意
注意

SUSE Edge for Telco 中包含的 linuxptp 软件包默认不会启用 ptp4lphc2sys。如果在置备时部署了针对特定系统的配置文件(请参见第 41.13.3 节 “Cluster API 集成”),则应启用它们。可通过将其添加到清单的 systemd 部分来实现,如上例所示。

按照 EIB 文档(第 3.4 节 “构建映像”)中所述的常规过程构建映像,并使用该映像部署群集。如果您是 EIB 新手,请从第 11 章 “Edge Image Builder开始。

41.13.2 为电信部署配置 PTP

许多电信应用场景要求严格保持偏差极小的相位和时间同步,为此定义了两个面向电信的配置文件:ITU-T G.8275.1 和 ITU-T G.8275.2。这两个配置文件均设置了高频率同步消息,以及其他独特特性(如使用替代的最佳主时钟算法 (BMCA))。这种特性要求 ptp4l 所使用的配置文件中包含特定设置,以下几节将提供相关参考信息。

注意
注意
  • 以下两节仅介绍时间接收器配置中的普通时钟场景。

  • 对于任何此类配置文件,都必须在精心规划的 PTP 基础架构中使用。

  • 要用于您的特定 PTP 网络,可能需要额外微调配置,请务必检查并根据需要调整所提供的示例。

41.13.2.1 PTP 配置文件 ITU-T G.8275.1

G.8275.1 配置文件具有以下特点:

  • 直接运行在以太网上,需要完整的网络支持(相邻节点/交换机必须支持 PTP)。

  • 默认域设置为 24。

  • 数据集比较基于 G.8275.x 算法及其在 priority2 之后的 localPriority 值。

将以下内容复制到名为 /etc/ptp4l-G.8275.1.conf 的文件中:

# Telecom G.8275.1 example configuration
[global]
domainNumber                    24
priority2			255
dataset_comparison              G.8275.x
G.8275.portDS.localPriority     128
G.8275.defaultDS.localPriority  128
maxStepsRemoved                 255
logAnnounceInterval             -3
logSyncInterval                 -4
logMinDelayReqInterval          -4
announceReceiptTimeout		3
serverOnly                      0
ptp_dst_mac                     01:80:C2:00:00:0E
network_transport               L2

创建好文件后,必须在 /etc/sysconfig/ptp4l 中引用该文件,才能使守护程序正确启动。可通过将 OPTIONS= 行更改为以下内容实现:

OPTIONS="-f /etc/ptp4l-G.8275.1.conf -i $IFNAME --message_tag ptp-8275.1"

具体说明:

  • -f 指定要使用的配置文件名称(此处为 /etc/ptp4l-G.8275.1.conf)。

  • -i 指定要使用的接口名称,请将 $IFNAME 替换为实际接口名称。

  • --message_tag 可用于在系统日志中更好地识别 ptp4l 输出,这是可选参数。

完成上述步骤后,必须(重新)启动 ptp4l 守护程序:

# systemctl restart ptp4l

运行以下命令,通过观察日志来检查同步状态:

# journalctl -e -u ptp4l

41.13.2.2 PTP 配置文件 ITU-T G.8275.2

G.8275.2 配置文件具有以下特点:

  • 运行在 IP 上,不需要完整的网络支持(相邻节点/交换机可以不支持 PTP)。

  • 默认域设置为 44。

  • 数据集比较基于 G.8275.x 算法及其在 priority2 之后的 localPriority 值。

将以下内容复制到名为 /etc/ptp4l-G.8275.2.conf 的文件中:

# Telecom G.8275.2 example configuration
[global]
domainNumber                    44
priority2			255
dataset_comparison              G.8275.x
G.8275.portDS.localPriority     128
G.8275.defaultDS.localPriority  128
maxStepsRemoved                 255
logAnnounceInterval             0
serverOnly                      0
hybrid_e2e                      1
inhibit_multicast_service       1
unicast_listen                  1
unicast_req_duration            60
logSyncInterval                 -5
logMinDelayReqInterval          -4
announceReceiptTimeout		2
#
# Customize the following for slave operation:
#
[unicast_master_table]
table_id                        1
logQueryInterval                2
UDPv4                           $PEER_IP_ADDRESS
[$IFNAME]
unicast_master_table            1

请确保替换以下占位符:

  • $PEER_IP_ADDRESS - 要与之通讯的下一个 PTP 节点的 IP 地址,例如提供同步的主时钟或边界时钟。

  • $IFNAME - 告知 ptp4l 使用哪个接口进行 PTP。

创建好文件后,必须在 /etc/sysconfig/ptp4l 中引用该文件以及 PTP 所用接口的名称,才能使守护程序正确启动。可通过将 OPTIONS= 行更改为以下内容实现:

OPTIONS="-f /etc/ptp4l-G.8275.2.conf --message_tag ptp-8275.2"

具体说明:

  • -f 指定要使用的配置文件名称(此处为 /etc/ptp4l-G.8275.2.conf)。

  • --message_tag 可用于在系统日志中更好地识别 ptp4l 输出,这是可选参数。

完成上述步骤后,必须(重新)启动 ptp4l 守护程序:

# systemctl restart ptp4l

运行以下命令,通过观察日志来检查同步状态:

# journalctl -e -u ptp4l

41.13.2.3 phc2sys 的配置

建议在配置 phc2sys 之前先完成 ptp4l 的全部配置,不过这不是强制要求。phc2sys 不需要配置文件,其执行参数可通过 /etc/sysconfig/ptp4l 中的 OPTIONS= 变量单独控制,方式与 ptp4l 类似:

OPTIONS="-s $IFNAME -w"

其中,$IFNAME 是已在 ptp4l 中设置的接口名称,将用作系统时钟的同步源。此参数用于识别源 PHC。

41.13.3 Cluster API 集成

当通过管理群集和定向置备功能部署群集时,配置文件及 /etc/sysconfig 中的两个配置变量均可在置备时部署到主机上。以下是某个群集定义的节选,重点展示了经过修改的 RKE2ControlPlane 对象,该对象会在所有主机上部署相同的 G.8275.1 配置文件:

apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: RKE2ControlPlane
metadata:
  name: single-node-cluster
  namespace: default
spec:
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3MachineTemplate
    name: single-node-cluster-controlplane
  replicas: 1
  version: ${RKE2_VERSION}
  rolloutStrategy:
    type: "RollingUpdate"
    rollingUpdate:
      maxSurge: 0
  registrationMethod: "control-plane-endpoint"
  serverConfig:
    cni: canal
  agentConfig:
    format: ignition
    cisProfile: cis
    additionalUserData:
      config: |
        variant: fcos
        version: 1.4.0
        systemd:
          units:
            - name: rke2-preinstall.service
              enabled: true
              contents: |
                [Unit]
                Description=rke2-preinstall
                Wants=network-online.target
                Before=rke2-install.service
                ConditionPathExists=!/run/cluster-api/bootstrap-success.complete
                [Service]
                Type=oneshot
                User=root
                ExecStartPre=/bin/sh -c "mount -L config-2 /mnt"
                ExecStart=/bin/sh -c "sed -i \"s/BAREMETALHOST_UUID/$(jq -r .uuid /mnt/openstack/latest/meta_data.json)/\" /etc/rancher/rke2/config.yaml"
                ExecStart=/bin/sh -c "echo \"node-name: $(jq -r .name /mnt/openstack/latest/meta_data.json)\" >> /etc/rancher/rke2/config.yaml"
                ExecStartPost=/bin/sh -c "umount /mnt"
                [Install]
                WantedBy=multi-user.target
        storage:
          files:
            - path: /etc/ptp4l-G.8275.1.conf
              overwrite: true
              contents:
                inline: |
                  # Telecom G.8275.1 example configuration
                  [global]
                  domainNumber                    24
                  priority2                       255
                  dataset_comparison              G.8275.x
                  G.8275.portDS.localPriority     128
                  G.8275.defaultDS.localPriority  128
                  maxStepsRemoved                 255
                  logAnnounceInterval             -3
                  logSyncInterval                 -4
                  logMinDelayReqInterval          -4
                  announceReceiptTimeout          3
                  serverOnly                      0
                  ptp_dst_mac                     01:80:C2:00:00:0E
                  network_transport               L2
              mode: 0644
              user:
                name: root
              group:
                name: root
            - path: /etc/sysconfig/ptp4l
              overwrite: true
              contents:
                inline: |
                  ## Path:           Network/LinuxPTP
                  ## Description:    Precision Time Protocol (PTP): ptp4l settings
                  ## Type:           string
                  ## Default:        "-i eth0 -f /etc/ptp4l.conf"
                  ## ServiceRestart: ptp4l
                  #
                  # Arguments when starting ptp4l(8).
                  #
                  OPTIONS="-f /etc/ptp4l-G.8275.1.conf -i $IFNAME --message_tag ptp-8275.1"
              mode: 0644
              user:
                name: root
              group:
                name: root
            - path: /etc/sysconfig/phc2sys
              overwrite: true
              contents:
                inline: |
                  ## Path:           Network/LinuxPTP
                  ## Description:    Precision Time Protocol (PTP): phc2sys settings
                  ## Type:           string
                  ## Default:        "-s eth0 -w"
                  ## ServiceRestart: phc2sys
                  #
                  # Arguments when starting phc2sys(8).
                  #
                  OPTIONS="-s $IFNAME -w"
              mode: 0644
              user:
                name: root
              group:
                name: root
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    nodeName: "localhost.localdomain"

除了其他变量外,必须为上述定义补全接口名称及其他 Cluster API 对象(如第 42 章 “全自动定向网络置备中所述)。

注意
注意
  • 仅当群集中的硬件保持统一且所有主机都需要采用相同配置(包括接口名称)时,这种方法才适用。

  • 也可以使用其他方法,未来版本中将会介绍相关内容。

至此,您的主机应已具备可正常运行的 PTP 堆栈,并将开始协商其 PTP 角色。

Documentation survey