跳到内容
documentation.suse.com / SUSE Edge 文档

SUSE Edge 文档

出版日期:2024 年 7 月 10 日

SUSE Edge 文档

欢迎阅读 SUSE Edge 文档,在其中可以找到快速入门指南、经过验证的设计、组件用法指南、第三方集成,以及有关管理边缘计算基础架构和工作负载的最佳实践。

1 什么是 SUSE Edge?

SUSE Edge 是有针对性的、紧密集成且经过全面验证的端到端解决方案,用于解决在边缘处部署基础架构和云原生应用程序时存在的独特挑战。其核心作用是提供一个有主见但高度灵活、高度可缩放且安全的平台,涵盖初始部署映像的构建、节点置备和初始配置、应用程序部署、可观测性和完整生命周期操作。该平台从一开始就构建于同类最佳的开源软件基础之上,与我们 30 年来提供安全、稳定且经认证的 SUSE Linux 平台的历史,以及通过 Rancher 产品组合提供高度可缩放且功能丰富的 Kubernetes 管理经验相一致。SUSE Edge 是基于这些功能构建的,可以提供满足众多细分市场需求的功能,包括零售、医疗、交通、物流、电信、智能制造和工业物联网 (IoT)。

2 设计理念

该解决方案的设计考虑到了客户的需求和期望千差万别,因此不存在“以一应百”的边缘平台。边缘部署促使我们解决并不断设想出一些极具挑战性的问题,包括大规模可伸缩性、网络受限情况下的可用性、物理空间限制、新的安全威胁和攻击途径、硬件体系结构和系统资源的差异、部署旧式基础架构和应用程序并与之连接的要求,以及使用寿命较长的客户解决方案。由于其中的许多挑战与传统思维方式不同(例如在数据中心或公有云中部署基础架构和应用程序),我们必须更仔细地审视设计,并反复思考许多常见假设条件。

例如,我们发现极简主义、模块化和易操作性具有重要价值。极简主义对于边缘环境非常重要,因为系统越复杂,就越容易出现故障。在分析数百个甚至数十万个位置后,我们发现复杂的系统会出现纷繁复杂的故障。解决方案中的模块化允许用户做出更多选择,同时消除部署的平台中不必要的复杂性。我们还需要在这些方面与易操作性之间取得平衡。人类用户在重复某个流程数千次后可能会出现失误,因此平台应确保任何潜在失误都可恢复,从而消除技术人员亲临现场解决问题的需要,同时尽力实现一致性和标准化。

3 应使用哪一篇快速入门?

由于操作环境和生命周期要求各不相同,我们已针对一些不同的部署模式履行了支持,这些模式与 SUSE Edge 所属的细分市场和用例大体一致。我们为其中的每种部署模式编写了一份快速入门指南,以帮助您根据自己的需求熟悉 SUSE Edge 平台。下面介绍了我们目前支持的三种部署模式,并附有相关快速入门页面的链接。

3.1 定向网络置备

定向网络置备适用于您知道所要部署到的硬件的细节,并可以直接访问带外管理界面来协调和自动化整个置备过程的情况。在这种情况下,客户预期解决方案能够从一个中心位置全自动地置备边缘站点,并可以最大限度地减少边缘位置的手动操作,也就是说,解决方案的作用远不止是创建引导映像;您只需将物理硬件装入机架、通电并为其连接所需的网络,自动化过程就会通过带外管理(例如通过 Redfish API)打开计算机电源并处理基础架构的置备、初始配置和部署,全程无需用户的干预。做到这一点的关键在于管理员了解系统;他们知道哪个硬件在哪个位置,并且部署预期可以得到集中处理。

此解决方案最为稳健,因为您可以直接与硬件的管理界面交互和处理已知硬件,并且很少会遇到网络可用性方面的限制。在功能上,此解决方案广泛使用群集 API 和 Metal3 来自动完成从裸机到操作系统、Kubernetes 和分层应用程序的置备,还可让您链接到 SUSE Edge 部署后的其他常用生命周期管理功能。此解决方案的快速入门可在第 1 章 “使用 Metal3 实现 BMC 自动化部署中找到。

3.2 “电告总部”网络置备

有时,在您的操作环境中,中心管理群集无法直接管理硬件(例如,您的远程网络位于防火墙后面,或者没有带外管理界面;这种情况在边缘处经常使用的“PC”型硬件中很常见)。对于这种情况,我们提供了相应的工具来远程置备群集及其工作负载,而无需知道硬件在引导时位于何处。这就是大多数人对边缘计算的看法;有成千上万种不太常见的系统在边缘位置引导、安全地电告总部、验证它们的身份,并接收有关要执行哪种操作的指令。为此,我们希望除了出厂前预先构建计算机映像,或者简单挂接引导映像(例如通过 USB)来打开系统外,置备和生命周期管理工作几乎不需要用户干预即可完成。在此方面存在的主要挑战是如何解决这些设备在各种环境下的缩放性、一致性、安全性和生命周期。

此解决方案针对系统置备和初始配置方式提供了极大的灵活性和一致性,不受系统位置、类型或规格以及首次开机时间的影响。在 SUSE Edge 中,可以通过 Edge Image Builder 十分灵活地对系统进行自定义,同时可以利用 Rancher Elemental 提供的注册功能来初始配置节点和置备 Kubernetes,并利用 SUSE Manager 来修补操作系统。此解决方案的快速入门可在第 2 章 “使用 Elemental 进行远程主机初始配置中找到。

3.3 基于映像的置备

对于需要在独立、隔离或网络受限的环境中操作的客户,SUSE Edge 提供了一种解决方案供客户生成完全自定义的安装媒体,其中包含所有必要的部署项目,用于在边缘启用单节点和多节点高可用性 Kubernetes 群集,包括任何所需的工作负载或其他分层组件。所有这些项目无需与外界建立任何网络连接,且无需集中式管理平台的干预。用户体验与“电告总部”解决方案非常相似,安装媒体同样会提供给目标系统,但该解决方案会“就地引导”。在这种情况下,可将创建的群集挂接到 Rancher 进行持续管理(即从“断开连接”转换为“已连接”操作模式,无需经过大范围的重新配置或重新部署),或者群集可以继续独立运行。请注意,在这两种情况下,都可以应用相同的一致性机制来自动执行生命周期操作。

此外,使用此解决方案可以快速创建管理集群,这些管理群集可以托管同时支持“定向网络置备”和“电告总部网络置备”模型的集中式基础架构,因为它可能是置备各种 Edge 基础架构最快速、最简单的方式。此解决方案重度使用 SUSE Edge Image Builder 的功能来创建完全自定义的无人照管安装媒体;快速入门可在第 3 章 “使用 Edge Image Builder 配置独立群集中找到。

4 SUSE Edge 中使用的组件

SUSE Edge 由现有的 SUSE 组件(包括 Linux 和 Rancher 团队提供的组件),以及 Edge 团队构建的、使 SUSE 能够解决基础架构要求和各种复杂问题的其他功能和组件构成。在以下章节中可以找到组件列表,以及每个组件的简要介绍及其在 SUSE Edge 中的用法的链接:

第 I 部分 快速入门

从这里快速入门

  • 1 使用 Metal3 实现 BMC 自动化部署
  • Metal3 是一个 CNCF 项目,它为 Kubernetes 提供裸机基础架构管理功能。

  • 2 使用 Elemental 进行远程主机初始配置
  • 本章介绍 SUSE Edge 中的“电告总部网络置备”解决方案。我们将使用 Elemental 来协助完成节点初始配置。Elemental 是一个软件堆栈,可用于注册远程主机和通过 Kubernetes 实现集中式云原生操作系统全面管理。在 SUSE Edge 堆栈中,我们将使用 Elemental 的注册功能将远程主机初始配置到 Rancher,以便将主机集成到集中式管理平台,然后从该平台部署和管理 Kubernetes 群集以及分层组件、应用程序及其生命周期,所有这些操作都在一个中心位置完成。

  • 3 使用 Edge Image Builder 配置独立群集
  • Edge Image Builder (EIB) 工具可以简化为引导计算机生成自定义的、随时可引导 (CRB) 磁盘映像的过程,即使在完全隔离式方案中也能做到这一点。EIB 用于创建所有三个 SUSE Edge 部署空间中使用的部署映像,因为它足够灵活,可以提供最简单的自定义,例如通过提供全面配置的映像来添加用户或设置时区。例如,该映像可以设置复杂的网络配置、部署多节点 Kubernetes 群集、部署客户工作负载,并通过 Rancher/Elemental 和 SUSE Manager 注册到集中式管理平台。EIB 以容器映像的形式运行,因此具有极高的跨平台可移植性,可确保所有必需的依赖项都…

1 使用 Metal3 实现 BMC 自动化部署

Metal3 是一个 CNCF 项目,它为 Kubernetes 提供裸机基础架构管理功能。

Metal3 提供 Kubernetes 原生资源来管理裸机服务器的生命周期,支持通过 Redfish 等带外协议进行管理。

它还为群集 API (CAPI) 提供成熟的支持,允许通过广泛采用的不区分供应商的 API 来管理跨多个基础架构提供商的基础架构资源。

1.1 为何使用此方法

此方法非常适合用于目标硬件支持带外管理,并且需要全自动化基础架构管理流程的方案。

管理群集配置为提供声明性 API 来对下游群集裸机服务器进行清单和状态管理,包括自动检查、清理和置备/取消置备。

1.2 概要体系结构

metal3 体系结构快速入门

1.3 先决条件

下游群集服务器硬件和网络相关的限制具体如下所述:

  • 管理群集

    • 必须与目标服务器管理/BMC API 建立网络连接

    • 必须与目标服务器控制平面网络建立网络连接

    • 对于多节点管理群集,需要配置额外的预留 IP 地址

  • 要控制的主机

    • 必须支持通过 Redfish、iDRAC 或 iLO 接口进行带外管理

    • 必须支持通过虚拟媒体进行部署(目前不支持 PXE)

    • 必须与管理群集建立网络连接,以便能够访问 Metal3 置备 API

需要一些工具,可以安装在管理群集上,也可以安装在能够访问管理群集的主机上。

必须从 SUSE Customer CenterSUSE 下载页面下载 SLE-Micro.x86_64-5.5.0-Default-GM.raw.xz 操作系统映像文件。

1.3.1 设置管理群集

安装管理群集和使用 Metal3 的基本步骤如下:

  1. 安装 RKE2 管理群集

  2. 安装 Rancher

  3. 安装存储提供程序

  4. 安装 Metal3 依赖项

  5. 安装 CAPI 依赖项

  6. 为下游群集主机构建 SLEMicro 操作系统映像

  7. 注册 BareMetalHost CR 以定义裸机清单

  8. 通过定义 CAPI 资源创建下游群集

本指南假设已安装现有的 RKE2 群集和 Rancher(包括 cert-manager),例如已使用 Edge Image Builder 安装(第 9 章 “Edge Image Builder)。

提示
提示

也可以按照 ATIP 管理群集文档(第 29 章 “设置管理群集)中所述,将此处所述的步骤完全自动化。

1.3.2 安装 Metal3 依赖项

必须安装并运行 cert-manager(如果在安装 Rancher 的过程中未安装)。

必须安装永久存储提供程序。建议使用 Longhorn,但对于开发/PoC 环境,也可以使用 local-path。以下说明假设已将 StorageClass 标记为默认,否则需要对 Metal3 chart 进行额外的配置。

需要提供一个额外的 IP,该 IP 由 MetalLB 管理,用于为 Metal3 管理服务提供一致的端点。此 IP 必须是控制平面子网的一部分,并且是为静态配置预留的(不是任何 DHCP 池的一部分)。

提示
提示

如果管理群集是单个节点,则可以避免通过 MetalLB 管理额外的浮动 IP,具体参见“单节点配置”(第 1.6.1 节 “单节点配置”

  1. 首先,我们需要安装 MetalLB:

    helm install \
      metallb oci://registry.suse.com/edge/metallb-chart \
      --namespace metallb-system \
      --create-namespace
  2. 然后使用定义为 STATIC_IRONIC_IP(如下所示)的预留 IP 来定义 IPAddressPoolL2Advertisment

    export STATIC_IRONIC_IP=<STATIC_IRONIC_IP>
    
    cat <<-EOF | kubectl apply -f -
    apiVersion: metallb.io/v1beta1
    kind: IPAddressPool
    metadata:
      name: ironic-ip-pool
      namespace: metallb-system
    spec:
      addresses:
      - ${STATIC_IRONIC_IP}/32
      serviceAllocation:
        priority: 100
        serviceSelectors:
        - matchExpressions:
          - {key: app.kubernetes.io/name, operator: In, values: [metal3-ironic]}
    EOF
    cat <<-EOF | kubectl apply -f -
    apiVersion: metallb.io/v1beta1
    kind: L2Advertisement
    metadata:
      name: ironic-ip-pool-l2-adv
      namespace: metallb-system
    spec:
      ipAddressPools:
      - ironic-ip-pool
    EOF
  3. 现在可以安装 Metal3

    helm install \
      metal3 oci://registry.suse.com/edge/metal3-chart \
      --namespace metal3-system \
      --create-namespace \
      --set global.ironicIP="${STATIC_IRONIC_IP}"
  4. 大约要经过两分钟,initContainer 才会在此部署中运行,因此在继续之前,请确保所有 Pod 都已运行:

    kubectl get pods -n metal3-system
    NAME                                                    READY   STATUS    RESTARTS   AGE
    baremetal-operator-controller-manager-85756794b-fz98d   2/2     Running   0          15m
    metal3-metal3-ironic-677bc5c8cc-55shd                   4/4     Running   0          15m
    metal3-metal3-mariadb-7c7d6fdbd8-64c7l                  1/1     Running   0          15m
警告
警告

请在 metal3-system 名称空间中的所有 Pod 都已运行之后才继续执行以下步骤

1.3.3 安装群集 API 依赖项

首先,我们需要禁用 Rancher 嵌入的 CAPI 控制器:

cat <<-EOF | kubectl apply -f -
apiVersion: management.cattle.io/v3
kind: Feature
metadata:
  name: embedded-cluster-api
spec:
  value: false
EOF

kubectl delete mutatingwebhookconfiguration.admissionregistration.k8s.io mutating-webhook-configuration
kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration
kubectl wait --for=delete namespace/cattle-provisioning-capi-system --timeout=300s

然后,要使用 SUSE 映像,需要创建一个配置文件:

mkdir ~/.cluster-api
cat >  ~/.cluster-api/clusterctl.yaml <<EOF
images:
  all:
    repository: registry.suse.com/edge
EOF

安装 clusterctl 1.6.x,之后我们将安装核心、基础架构、引导程序和控制平面提供程序,如下所示:

clusterctl init --core "cluster-api:v1.6.2" --infrastructure "metal3:v1.6.0" --bootstrap "rke2:v0.2.6" --control-plane "rke2:v0.2.6"

一段时间后,控制器 Pod 应会在 capi-systemcapm3-systemrke2-bootstrap-systemrke2-control-plane-system 名称空间中运行。

1.3.4 准备下游群集映像

Edge Image Builder(第 9 章 “Edge Image Builder)用于准备下游群集主机上置备的经过修改的 SLEMicro 基础映像。

可以通过 Edge Image Builder 完成大部分配置,但本指南仅介绍设置下游群集所需的最低限度配置。

1.3.4.1 映像配置

运行 Edge Image Builder 时,将从主机挂载一个目录,因此需要创建一个目录结构来存储用于定义目标映像的配置文件。

├── downstream-cluster-config.yaml
├── base-images/
│   └ SLE-Micro.x86_64-5.5.0-Default-GM.raw
├── network/
|   └ configure-network.sh
└── custom/
    └ scripts/
        └ growfs.sh
1.3.4.1.1 下游群集映像定义文件

downstream-cluster-config.yaml 文件是下游群集映像的主配置文件。下面是通过 Metal3 进行部署的极简示例:

apiVersion: 1.0
image:
  imageType: RAW
  arch: x86_64
  baseImage: SLE-Micro.x86_64-5.5.0-Default-GM.raw
  outputImageName: SLE-Micro-eib-output.raw
operatingSystem:
  kernelArgs:
    - ignition.platform.id=openstack
    - net.ifnames=1
  systemd:
    disable:
      - rebootmgr
  users:
    - username: root
      encryptedPassword: ${ROOT_PASSWORD}
      sshKeys:
      - ${USERKEY1}

${ROOT_PASSWORD} 是 root 用户的已加密口令,可用于测试/调试。可以使用 openssl passwd-6 PASSWORD 命令生成此口令

对于生产环境,建议使用可添加到 users 块的 SSH 密钥(将该块中的 ${USERKEY1} 替换为实际 SSH 密钥)。

注意
注意

net.ifnames=1 会启用可预测网络接口命名

这与 metal3 chart 的默认配置相匹配,但设置必须与配置的 chart predictableNicNames 值相匹配。

另请注意,ignition.platform.id=openstack 是必需的,如果不指定此参数,在 Metal3 自动化流程中通过 ignition 进行 SLEMicro 配置将会失败。

1.3.4.1.2 Growfs 脚本

目前是一个自定义脚本 (custom/scripts/growfs.sh),在置备后首次引导时,必须使用此脚本来增大文件系统,使之与磁盘大小匹配。growfs.sh 脚本包含以下信息:

#!/bin/bash
growfs() {
  mnt="$1"
  dev="$(findmnt --fstab --target ${mnt} --evaluate --real --output SOURCE --noheadings)"
  # /dev/sda3 -> /dev/sda, /dev/nvme0n1p3 -> /dev/nvme0n1
  parent_dev="/dev/$(lsblk --nodeps -rno PKNAME "${dev}")"
  # Last number in the device name: /dev/nvme0n1p42 -> 42
  partnum="$(echo "${dev}" | sed 's/^.*[^0-9]\([0-9]\+\)$/\1/')"
  ret=0
  growpart "$parent_dev" "$partnum" || ret=$?
  [ $ret -eq 0 ] || [ $ret -eq 1 ] || exit 1
  /usr/lib/systemd/systemd-growfs "$mnt"
}
growfs /
注意
注意

使用相同的方法添加您自己的自定义脚本,以便在置备过程中执行。有关详细信息,请参见第 3 章 “使用 Edge Image Builder 配置独立群集

与此解决方法相关的 bug 为 https://bugzilla.suse.com/show_bug.cgi?id=1217430

1.3.4.2 映像创建

按照前面的章节准备好目录结构后,运行以下命令来构建映像:

podman run --rm --privileged -it -v $PWD:/eib \
 registry.suse.com/edge/edge-image-builder:1.0.2 \
 build --definition-file downstream-cluster-config.yaml

这会根据上述定义创建名为 SLE-Micro-eib-output.raw 的输出映像文件。

然后必须通过 Web 服务器提供输出映像,该服务器可以是通过 Metal3 chart 启用的媒体服务器容器(注意),也可以是其他某个本地可访问的服务器。在下面的示例中,此服务器是 imagecache.local:8080

1.3.5 添加 BareMetalHost 清单

注册自动部署的裸机服务器需要创建两个资源:一个用于存储 BMC 访问身份凭证的密钥,以及一个用于定义 BMC 连接和其他细节的 Metal3 BareMetalHost 资源:

apiVersion: v1
kind: Secret
metadata:
  name: controlplane-0-credentials
type: Opaque
data:
  username: YWRtaW4=
  password: cGFzc3dvcmQ=
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
  name: controlplane-0
  labels:
    cluster-role: control-plane
spec:
  online: true
  bootMACAddress: "00:f3:65:8a:a3:b0"
  bmc:
    address: redfish-virtualmedia://192.168.125.1:8000/redfish/v1/Systems/68bd0fb6-d124-4d17-a904-cdf33efe83ab
    disableCertificateVerification: true
    credentialsName: controlplane-0-credentials

请注意以下几点:

  • 密钥用户名/口令必须采用 base64 编码。请注意,此值不能包含任何尾部换行符(例如,应使用 echo-n,而不是简单地使用 echo!)

  • 可以现在设置 cluster-role 标签,也可以稍后在创建群集时设置。在以下示例中,应该设置 control-planeworker

  • bootMACAddress 必须是与主机的控制平面 NIC 匹配的有效 MAC

  • bmc 地址是与 BMC 管理 API 的连接,支持以下设置:

    • redfish-virtualmedia://<IP 地址>/redfish/v1/Systems/<系统 ID>:Redfish 虚拟媒体,例如 SuperMicro

    • idrac-virtualmedia://<IP 地址>/redfish/v1/Systems/System.Embedded.1:Dell iDRAC

  • 有关 BareMetalHost API 的更多细节,请参见上游 API 文档

1.3.5.1 配置静态 IP

上面的 BareMetalHost 示例假设 DHCP 提供控制平面网络配置,但对于需要手动配置(例如静态 IP)的情况,可以提供附加配置,如下所述。

1.3.5.1.1 用于静态网络配置的附加脚本

使用 Edge Image Builder 创建基础映像时,请在 network 文件夹中创建以下 configure-network.sh 文件。

这会在首次引导时使用配置驱动器数据,并使用 NM Configurator 工具来配置主机网络。

#!/bin/bash

set -eux

# Attempt to statically configure a NIC in the case where we find a network_data.json
# In a configuration drive

CONFIG_DRIVE=$(blkid --label config-2 || true)
if [ -z "${CONFIG_DRIVE}" ]; then
  echo "No config-2 device found, skipping network configuration"
  exit 0
fi

mount -o ro $CONFIG_DRIVE /mnt

NETWORK_DATA_FILE="/mnt/openstack/latest/network_data.json"

if [ ! -f "${NETWORK_DATA_FILE}" ]; then
  umount /mnt
  echo "No network_data.json found, skipping network configuration"
  exit 0
fi

DESIRED_HOSTNAME=$(cat /mnt/openstack/latest/meta_data.json | tr ',{}' '\n' | grep '\"metal3-name\"' | sed 's/.*\"metal3-name\": \"\(.*\)\"/\1/')

mkdir -p /tmp/nmc/{desired,generated}
cp ${NETWORK_DATA_FILE} /tmp/nmc/desired/${DESIRED_HOSTNAME}.yaml
umount /mnt

./nmc generate --config-dir /tmp/nmc/desired --output-dir /tmp/nmc/generated
./nmc apply --config-dir /tmp/nmc/generated
1.3.5.1.2 包含主机网络配置的附加密钥

可为每个主机定义一个附加密钥,其中包含采用 NM Configurator(第 10 章 “边缘网络)所支持的 nmstate 格式的数据。

然后通过 preprovisioningNetworkDataName 规范字段在 BareMetalHost 资源中引用该密钥。

apiVersion: v1
kind: Secret
metadata:
  name: controlplane-0-networkdata
type: Opaque
stringData:
  networkData: |
    interfaces:
    - name: enp1s0
      type: ethernet
      state: up
      mac-address: "00:f3:65:8a:a3:b0"
      ipv4:
        address:
        - ip:  192.168.125.200
          prefix-length: 24
        enabled: true
        dhcp: false
    dns-resolver:
      config:
        server:
        - 192.168.125.1
    routes:
      config:
      - destination: 0.0.0.0/0
        next-hop-address: 192.168.125.1
        next-hop-interface: enp1s0
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
  name: controlplane-0
  labels:
    cluster-role: control-plane
spec:
  preprovisioningNetworkDataName: controlplane-0-networkdata
# Remaining content as in previous example
注意
注意

尽管 mac-address 在 nmstate API 中是可选的,但要通过 NM Configurator 进行配置,必须提供 mac-address。

1.3.5.2 BareMetalHost 准备

按照上述步骤创建 BareMetalHost 资源和关联的密钥后,将触发主机准备工作流程:

  • 虚拟媒体附件将 ramdisk 映像引导至目标主机 BMC

  • ramdisk 检查硬件细节,并为主机做好置备准备(例如,清理磁盘中的旧数据)

  • 完成此过程后,BareMetalHost status.hardware 字段中的硬件细节将会更新并可供校验

此过程可能需要几分钟时间,但完成后,您应会看到 BareMetalHost 状态变为 available

% kubectl get baremetalhost
NAME             STATE       CONSUMER   ONLINE   ERROR   AGE
controlplane-0   available              true             9m44s
worker-0         available              true             9m44s

1.3.6 创建下游群集

现在创建用于定义下游群集的群集 API 资源,并创建计算机资源,后者会导致置备 BareMetalHost 资源,然后引导这些资源以形成 RKE2 群集。

1.3.7 控制平面部署

为了部署控制平面,我们需要定义一个如下所示的 yaml 清单,其中包含以下资源:

  • 群集资源定义群集名称、网络和控制平面/基础架构提供程序的类型(在本例中为 RKE2/Metal3)

  • Metal3Cluster 定义控制平面端点(单节点群集的主机 IP,多节点群集的负载平衡器端点,本示例假设使用单节点群集)

  • RKE2ControlPlane 定义 RKE2 版本,以及群集引导期间所需的任何其他配置

  • Metal3MachineTemplate 定义要应用于 BareMetalHost 资源的操作系统映像,hostSelector 定义要使用的 BareMetalHost

  • Metal3DataTemplate 定义要传递给 BareMetalHost 的附加 metaData(请注意,Edge 解决方案目前不支持 networkData)

请注意,为简单起见,本示例假设使用单节点控制平面,其中 BareMetalHost 配置了 IP 192.168.125.200 - 有关更高级的多节点示例,请参见 ATIP 文档(第 31 章 “全自动定向网络置备

apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: sample-cluster
  namespace: default
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
        - 192.168.0.0/18
    services:
      cidrBlocks:
        - 10.96.0.0/12
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
    kind: RKE2ControlPlane
    name: sample-cluster
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3Cluster
    name: sample-cluster
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3Cluster
metadata:
  name: sample-cluster
  namespace: default
spec:
  controlPlaneEndpoint:
    host: 192.168.125.200
    port: 6443
  noCloudProvider: true
---
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: RKE2ControlPlane
metadata:
  name: sample-cluster
  namespace: default
spec:
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3MachineTemplate
    name: sample-cluster-controlplane
  replicas: 1
  agentConfig:
    format: ignition
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    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
    version: v1.28.9+rke2r1
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
metadata:
  name: sample-cluster-controlplane
  namespace: default
spec:
  template:
    spec:
      dataTemplate:
        name: sample-cluster-controlplane-template
      hostSelector:
        matchLabels:
          cluster-role: control-plane
      image:
        checksum: http://imagecache.local:8080/SLE-Micro-eib-output.raw.sha256
        checksumType: sha256
        format: raw
        url: http://imagecache.local:8080/SLE-Micro-eib-output.raw
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3DataTemplate
metadata:
  name: sample-cluster-controlplane-template
  namespace: default
spec:
  clusterName: sample-cluster
  metaData:
    objectNames:
      - key: name
        object: machine
      - key: local-hostname
        object: machine
      - key: local_hostname
        object: machine

复制以上示例并根据您的环境进行修改后,可以通过 kubectl 应用该示例,然后使用 clusterctl 监控群集状态

% kubectl apply -f rke2-control-plane.yaml

# Wait for the cluster to be provisioned - status can be checked via clusterctl
% clusterctl describe cluster sample-cluster
NAME                                                    READY  SEVERITY  REASON  SINCE  MESSAGE
Cluster/sample-cluster                                  True                     22m
├─ClusterInfrastructure - Metal3Cluster/sample-cluster  True                     27m
├─ControlPlane - RKE2ControlPlane/sample-cluster        True                     22m
│ └─Machine/sample-cluster-chflc                        True                     23m

1.3.8 工作/计算节点部署

与部署控制平面时一样,我们需要定义一个 yaml 清单,其中包含以下资源:

  • MachineDeployment 定义副本(主机)的数量和引导/基础架构提供程序(在本例中为 RKE2/Metal3)

  • RKE2ConfigTemplate 描述代理主机引导的 RKE2 版本和首次引导配置

  • Metal3MachineTemplate 定义要应用于 BareMetalHost 资源的操作系统映像,hostSelector 定义要使用的 BareMetalHost

  • Metal3DataTemplate 定义要传递给 BareMetalHost 的附加 metaData(请注意,Edge 解决方案目前不支持 networkData)

apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineDeployment
metadata:
  labels:
    cluster.x-k8s.io/cluster-name: sample-cluster
  name: sample-cluster
  namespace: default
spec:
  clusterName: sample-cluster
  replicas: 1
  selector:
    matchLabels:
      cluster.x-k8s.io/cluster-name: sample-cluster
  template:
    metadata:
      labels:
        cluster.x-k8s.io/cluster-name: sample-cluster
    spec:
      bootstrap:
        configRef:
          apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1
          kind: RKE2ConfigTemplate
          name: sample-cluster-workers
      clusterName: sample-cluster
      infrastructureRef:
        apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
        kind: Metal3MachineTemplate
        name: sample-cluster-workers
      nodeDrainTimeout: 0s
      version: v1.28.9+rke2r1
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1
kind: RKE2ConfigTemplate
metadata:
  name: sample-cluster-workers
  namespace: default
spec:
  template:
    spec:
      agentConfig:
        format: ignition
        version: v1.28.9+rke2r1
        kubelet:
          extraArgs:
            - provider-id=metal3://BAREMETALHOST_UUID
        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
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
metadata:
  name: sample-cluster-workers
  namespace: default
spec:
  template:
    spec:
      dataTemplate:
        name: sample-cluster-workers-template
      hostSelector:
        matchLabels:
          cluster-role: worker
      image:
        checksum: http://imagecache.local:8080/SLE-Micro-eib-output.raw.sha256
        checksumType: sha256
        format: raw
        url: http://imagecache.local:8080/SLE-Micro-eib-output.raw
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3DataTemplate
metadata:
  name: sample-cluster-workers-template
  namespace: default
spec:
  clusterName: sample-cluster
  metaData:
    objectNames:
      - key: name
        object: machine
      - key: local-hostname
        object: machine
      - key: local_hostname
        object: machine

复制以上示例并根据您的环境进行修改后,可以通过 kubectl 应用该示例,然后使用 clusterctl 监控群集状态

% kubectl apply -f rke2-agent.yaml

# Wait some time for the compute/agent hosts to be provisioned
% clusterctl describe cluster sample-cluster
NAME                                                    READY  SEVERITY  REASON  SINCE  MESSAGE
Cluster/sample-cluster                                  True                     25m
├─ClusterInfrastructure - Metal3Cluster/sample-cluster  True                     30m
├─ControlPlane - RKE2ControlPlane/sample-cluster        True                     25m
│ └─Machine/sample-cluster-chflc                        True                     27m
└─Workers
  └─MachineDeployment/sample-cluster                    True                     22m
    └─Machine/sample-cluster-56df5b4499-zfljj           True                     23m

1.3.9 群集取消置备

可以通过删除上述创建步骤中应用的资源来取消置备下游群集:

% kubectl delete -f rke2-agent.yaml
% kubectl delete -f rke2-control-plane.yaml

这会触发 BareMetalHost 资源的取消置备,此过程可能需要几分钟,之后,这些资源将再次处于可用状态:

% kubectl get bmh
NAME             STATE            CONSUMER                            ONLINE   ERROR   AGE
controlplane-0   deprovisioning   sample-cluster-controlplane-vlrt6   false            10m
worker-0         deprovisioning   sample-cluster-workers-785x5        false            10m

...

% kubectl get bmh
NAME             STATE       CONSUMER   ONLINE   ERROR   AGE
controlplane-0   available              false            15m
worker-0         available              false            15m

1.4 已知问题

  • 上游 IP 地址管理控制器目前不受支持,因为它与我们在 SLEMicro 中选择的网络配置工具和首次引导工具链尚不兼容。

  • 相关的 IPAM 资源和 Metal3DataTemplate networkData 字段目前也不受支持。

  • 目前仅支持通过 redfish-virtualmedia 进行部署。

  • 部署的群集目前不会导入 Rancher

  • 由于禁用了 Rancher 嵌入式 CAPI 控制器,如上所述为 Metal3 配置的管理群集也无法用于其他群集置备方法,例如 Elemental(第 11 章 “Elemental

1.5 计划的更改

  • 我们已计划好将来通过 Rancher Turtles 将部署的群集导入 Rancher

  • 采用与 Rancher Turtles 一致的做法还有望消除禁用 Rancher 嵌入式 CAPI 的要求,因此其他群集方法应该可以通过管理群集来实现。

  • 通过 networkData 字段启用 IPAM 资源和配置支持

1.6 其他资源

ATIP 文档(第 26 章 “SUSE 自适应电信基础架构平台 (ATIP))提供了 Metal3 在电信用例中的更高级用法示例。

1.6.1 单节点配置

对于管理群集是单个节点的测试/PoC 环境,可能不需要通过 MetalLB 管理额外的浮动 IP。

在此模式下,管理群集 API 的端点是管理群集的 IP,因此在使用 DHCP 时应预留该 IP,或者配置静态 IP,以确保管理群集 IP 不会变化 - 在下面显示为 MANAGEMENT_CLUSTER_IP

为了实现此方案,必须如下所示指定 metal3 chart 值:

global:
  ironicIP: <MANAGEMENT_CLUSTER_IP>
metal3-ironic:
  service:
    type: NodePort

1.6.2 对虚拟媒体 ISO 附件禁用 TLS

某些服务器供应商在将虚拟媒体 ISO 映像挂接到 BMC 时会校验 SSL 连接,这可能会导致问题,因为为 Metal3 部署生成的证书是自我签名证书。要解决此问题,可以使用如下所示的 metal3 chart 值仅对虚拟媒体磁盘附件禁用 TLS:

global:
  enable_vmedia_tls: false

另一种解决方法是使用 CA 证书配置 BMC - 在这种情况下,可以使用 kubectl 从群集读取证书:

kubectl get secret -n metal3-system ironic-vmedia-cert -o yaml

然后可以在服务器 BMC 控制台上配置证书,不过,配置过程根据特定的供应商而异(并且不一定适用于所有供应商,如果不适用,可能需要指定 enable_vmedia_tls 标志)。

2 使用 Elemental 进行远程主机初始配置

本章介绍 SUSE Edge 中的“电告总部网络置备”解决方案。我们将使用 Elemental 来协助完成节点初始配置。Elemental 是一个软件堆栈,可用于注册远程主机和通过 Kubernetes 实现集中式云原生操作系统全面管理。在 SUSE Edge 堆栈中,我们将使用 Elemental 的注册功能将远程主机初始配置到 Rancher,以便将主机集成到集中式管理平台,然后从该平台部署和管理 Kubernetes 群集以及分层组件、应用程序及其生命周期,所有这些操作都在一个中心位置完成。

此方法在以下情况下可能很有用:您要控制的设备与上游群集不在同一网络中,或没有带外管理控制器初始配置功能可以进行更直接的控制;您要在边缘处引导许多不同的“未知”系统,并且需要安全地大规模初始配置和管理这些系统。这种情况在以下领域的用例中很常见:零售、工业物联网,或几乎无法通过设备要安装到的网络进行控制的其他领域。

2.1 概要体系结构

Elemental 体系结构快速入门

2.2 所需资源

下面说明了学习本快速入门所要满足的最低系统和环境要求:

  • 集中式管理群集的主机(托管 Rancher 和 Elemental 的主机):

    • 至少 8 GB RAM 和 20 GB 磁盘空间,用于开发或测试(对于生产用途,请参见此处

  • 要置备的目标节点,即边缘设备(可以使用虚拟机进行演示或测试)

    • 至少 4GB RAM、2 个 CPU 核心和 20 GB 磁盘空间

  • 管理群集的可解析主机名,或用于 sslip.io 等服务的静态 IP 地址

  • 用于通过 Edge Image Builder 构建安装媒体的主机

    • 运行 SLES 15 SP5、openSUSE Leap 15.5 或其他支持 Podman 的兼容操作系统。

    • 已安装 KubectlPodmanHelm

  • 用于引导的 USB 闪存盘(如果使用物理硬件)

注意
注意

在初始配置过程中会重写目标计算机上的现有数据,因此请务必备份挂接到目标部署节点的所有 USB 存储设备和磁盘上的所有数据。

本指南是使用托管上游群集的 Digital Ocean droplet 以及用作下游设备的 Intel NUC 制作的。为了构建安装媒体,我们使用了 SUSE Linux Enterprise Server。

2.3 如何使用 Elemental

安装和使用 Elemental 的基本步骤如下:

2.3.1 构建引导群集

首先创建一个能够托管 Rancher 和 Elemental 的群集。必须可以从下游节点所连接到的网络路由此群集。

2.3.1.1 创建 Kubernetes 群集

如果您使用的是超大规模云(例如 Azure、AWS 或 Google Cloud),那么,设置群集的最简单方法是使用这些云的内置工具。为简洁起见,本指南不会详细介绍每种选项的用法过程。

如果您要安装到裸机或其他宿主服务,同时需要提供 Kubernetes 发行版本身,我们建议您使用 RKE2

2.3.1.2 设置 DNS

在继续之前,需要设置群集访问权限。与群集本身的设置一样,DNS 的配置方式根据群集的托管位置而异。

提示
提示

如果您不想处理 DNS 记录的设置(例如,这只是一个临时使用的测试服务器),可以改用 sslip.io 之类的服务。通过此服务,可以使用 <address>.sslip.io 解析任何 IP 地址。

2.3.2 安装 Rancher

要安装 Rancher,需要访问刚刚创建的群集的 Kubernetes API。具体方法取决于使用的 Kubernetes 发行版。

对于 RKE2,kubeconfig 文件会写入 /etc/rancher/rke2/rke2.yaml。将此文件作为 ~/.kube/config 保存在本地系统上。可能需要编辑该文件,以包含正确的外部可路由 IP 地址或主机名。

使用 Rancher 文档中所述的命令轻松安装 Rancher:

  1. 安装 cert-manager

    • Linux
    • Windows
    helm repo add rancher-prime https://charts.rancher.com/server-charts/prime
    
    kubectl create namespace cattle-system
    
    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.crds.yaml
    helm repo add jetstack https://charts.jetstack.io
    
    helm repo update
    
    helm install cert-manager jetstack/cert-manager \
     --namespace cert-manager \
     --create-namespace
  2. 然后安装 Rancher 本身:

    • Linux
    • Windows
    helm install rancher rancher-prime/rancher \
      --namespace cattle-system \
      --set hostname=<DNS or sslip from above> \
      --set replicas=1 \
      --set bootstrapPassword=<PASSWORD_FOR_RANCHER_ADMIN>
注意
注意

如果目标系统是生产系统,请使用 cert-manager 配置实际证书(例如 Let's Encrypt 提供的证书)。

浏览到您设置的主机名,然后使用您的 bootstrapPassword 登录到 Rancher。系统将指导您完成一个简短的设置过程。

2.3.3 安装 Elemental

安装 Rancher 后,接下来可以安装 Elemental Operator 和所需的 CRD。Elemental 的 Helm chart 作为 OCI 项目发布,因此其安装过程比其他 chart 略简单一些。可以通过您用来安装 Rancher 的同一外壳安装 Helm chart,也可以在浏览器中通过 Rancher 的外壳安装。

helm install --create-namespace -n cattle-elemental-system \
 elemental-operator-crds \
 oci://registry.suse.com/rancher/elemental-operator-crds-chart \
 --version 1.4.4

helm install --create-namespace -n cattle-elemental-system \
 elemental-operator \
 oci://registry.suse.com/rancher/elemental-operator-chart \
 --version 1.4.4

2.3.3.1 (可选)安装 Elemental UI 扩展

  1. 要使用 Elemental UI,请登录到您的 Rancher 实例,单击左上角的三点菜单:

    安装 Elemental 扩展 1
  2. 在此页面上的“Available”(可用)选项卡中,单击“Elemental”卡片上的“Install”(安装):

    安装 Elemental 扩展 2
  3. 确认您要安装该扩展:

    安装 Elemental 扩展 3
  4. 安装后,系统将提示您重新加载页面。

    安装 Elemental 扩展 4
  5. 重新加载后,可以通过“OS Management”(操作系统管理)全局应用程序访问 Elemental 扩展。

    访问 Elemental 扩展

2.3.3.2 配置 Elemental

为方便起见,我们建议将变量 $ELEM 设置为配置目录所在的完整路径:

export ELEM=$HOME/elemental
mkdir -p $ELEM

为了能够将计算机注册到 Elemental,我们需要在 fleet-default 名称空间中创建 MachineRegistration 对象。

我们来创建该对象的基本版本:

cat << EOF > $ELEM/registration.yaml
apiVersion: elemental.cattle.io/v1beta1
kind: MachineRegistration
metadata:
  name: ele-quickstart-nodes
  namespace: fleet-default
spec:
  machineName: "\${System Information/Manufacturer}-\${System Information/UUID}"
  machineInventoryLabels:
    manufacturer: "\${System Information/Manufacturer}"
    productName: "\${System Information/Product Name}"
EOF

kubectl apply -f $ELEM/registration.yaml
注意
注意

cat 命令使用反斜杠 (\) 将每个 $ 符号转义,以免 Bash 将其模板化。如果手动复制命令,请去除反斜杠。

创建该对象后,找到并记下分配的端点:

REGISURL=$(kubectl get machineregistration ele-quickstart-nodes -n fleet-default -o jsonpath='{.status.registrationURL}')

或者,可以在 UI 中执行此操作。

UI 扩展
  1. 在“OS Management”(操作系统管理)扩展中,单击“Create Registration Endpoint”(创建注册端点):

    单击“Create Registration”(创建注册)
  2. 为此配置命名。

    添加名称
    注意
    注意

    您可以忽略“Cloud Configuration”(云配置)字段,因为此处的数据将被 Edge Image Builder 中的后续步骤覆盖。

  3. 接下来,向下滚动并单击“Add Label”(添加标签),为注册计算机时创建的每个资源添加标签。标签可用于区分计算机。

    添加标签
  4. 最后,单击“Create”(创建)以保存配置。

    单击“Create”(创建)
UI 扩展

如果您刚刚创建了配置,则应会看到列出的注册 URL,可以单击“Copy”(复制)来复制该网址:

复制 URL
提示
提示

如果您退出了该屏幕,可以单击左侧菜单中的“Registration Endpoints”(注册端点),然后单击刚刚创建的端点的名称。

此 URL 将在下一步骤中使用。

2.3.4 构建安装媒体

虽然当前版本的 Elemental 提供了构建其自身安装媒体的方法,但在 SUSE Edge 3.0 中,我们会改用 Edge Image Builder 来构建安装媒体,因此最终构建的系统使用 SLE Micro 作为基础操作系统。

提示
提示

有关 Edge Image Builder 的更多细节,请查看相关入门指南(第 3 章 “使用 Edge Image Builder 配置独立群集)和组件文档(第 9 章 “Edge Image Builder)。

在装有 Podman 的 Linux 系统上,运行:

mkdir -p $ELEM/eib_quickstart/base-images
mkdir -p $ELEM/eib_quickstart/elemental
curl $REGISURL -o $ELEM/eib_quickstart/elemental/elemental_config.yaml
cat << EOF > $ELEM/eib_quickstart/eib-config.yaml
apiVersion: 1.0
image:
    imageType: iso
    arch: x86_64
    baseImage: SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM.install.iso
    outputImageName: elemental-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: \$6\$jHugJNNd3HElGsUZ\$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
EOF
注意
注意
  • 未编码的口令是 eib

  • cat 命令使用反斜杠 (\) 将每个 $ 符号转义,以免 Bash 将其模板化。如果手动复制命令,请去除反斜杠。

podman run --privileged --rm -it -v $ELEM/eib_quickstart/:/eib \
 registry.suse.com/edge/edge-image-builder:1.0.2 \
 build --definition-file eib-config.yaml

如果要引导物理设备,我们需要将映像刻录到 USB 闪存盘中。为此请使用以下命令:

sudo dd if=/eib_quickstart/elemental-image.iso of=/dev/<PATH_TO_DISK_DEVICE> status=progress

2.3.5 引导下游节点

现在我们已创建安装媒体,接下来可以用它来引导下游节点。

对于您要使用 Elemental 控制的每个系统,请添加安装媒体并引导设备。安装后,系统会重引导并自行注册。

如果您正在使用 UI 扩展,则应会看到您的节点出现在“Inventory of Machines”(计算机清单)中。

注意
注意

在出现登录提示之前,请勿移除安装媒体;在首次引导期间,仍需访问 USB 记忆棒上的文件。

2.3.6 创建下游群集

使用 Elemental 置备新群集时,需要创建两个对象。

  • Linux
  • UI 扩展

第一个对象是 MachineInventorySelectorTemplate。此对象用于指定群集与清单中计算机之间的映射。

  1. 创建一个选择器,用于根据标签匹配清单中的任何计算机:

    cat << EOF > $ELEM/selector.yaml
    apiVersion: elemental.cattle.io/v1beta1
    kind: MachineInventorySelectorTemplate
    metadata:
      name: location-123-selector
      namespace: fleet-default
    spec:
      template:
        spec:
          selector:
            matchLabels:
              locationID: '123'
    EOF
  2. 将资源应用于群集:

    kubectl apply -f $ELEM/selector.yaml
  3. 获取计算机名称并添加匹配标签:

    MACHINENAME=$(kubectl get MachineInventory -n fleet-default | awk 'NR>1 {print $1}')
    
    kubectl label MachineInventory -n fleet-default \
     $MACHINENAME locationID=123
  4. 创建简单的单节点 K3s 群集资源,并将其应用于群集:

    cat << EOF > $ELEM/cluster.yaml
    apiVersion: provisioning.cattle.io/v1
    kind: Cluster
    metadata:
      name: location-123
      namespace: fleet-default
    spec:
      kubernetesVersion: v1.28.9+k3s1
      rkeConfig:
        machinePools:
          - name: pool1
            quantity: 1
            etcdRole: true
            controlPlaneRole: true
            workerRole: true
            machineConfigRef:
              kind: MachineInventorySelectorTemplate
              name: location-123-selector
              apiVersion: elemental.cattle.io/v1beta1
    EOF
    
    kubectl apply -f $ELEM/cluster.yaml

创建这些对象后,您应会看到一个新的 Kubernetes 群集使用刚刚安装的新节点运行。

提示
提示

为了能够更轻松地将系统分组,可以添加一个启动脚本,用于在环境中查找已知在该位置独有的内容。

例如,如果您知道每个位置都有一个唯一的子网,则可以编写一个脚本来查找网络前缀,并为相应的 MachineInventory 添加标签。

通常需要根据您的系统设计自定义此脚本,如下所示:

INET=`ip addr show dev eth0 | grep "inet\ "`
elemental-register --label "network=$INET" \
 --label "network=$INET" /oem/registration

2.4 节点重置

SUSE Rancher Elemental 支持执行“节点重置”,从 Rancher 中删除整个群集、从群集中删除单个节点或者从计算机清单中手动删除某个节点时,可以选择性地触发该操作。当您想要重置和清理任何孤立资源,并希望自动将清理的节点放回计算机清单以便重复使用时,此功能非常有用。默认未启用此功能,因此不会清理任何已去除的系统(即,不会去除数据,任何 Kubernetes 群集资源将继续在下游群集上运行),并且需要手动干预才能擦除数据,并通过 Elemental 将计算机重新注册到 Rancher。

如果您希望默认启用此功能,则需要通过添加 config.elemental.reset.enabled: true,来确保 MachineRegistration 明确启用此功能,例如:

config:
  elemental:
    registration:
      auth: tpm
    reset:
      enabled: true

然后,所有使用此 MachineRegistration 注册的系统将自动在其配置中收到 elemental.cattle.io/resettable: 'true' 批注。如果您希望在各个节点上手动执行此操作(例如,您的现有 MachineInventory 没有此批注,或者您已部署节点),您可以修改 MachineInventory 并添加 resettable 配置,例如:

apiVersion: elemental.cattle.io/v1beta1
kind: MachineInventory
metadata:
  annotations:
    elemental.cattle.io/os.unmanaged: 'true'
    elemental.cattle.io/resettable: 'true'

在 SUSE Edge 3.0 中,Elemental Operator 会在操作系统上放置一个标记,该标记将自动触发清理过程;它会停止所有 Kubernetes 服务、去除所有永久数据、卸装所有 Kubernetes 服务、清理所有剩余 Kubernetes/Rancher 目录,并通过原始 Elemental MachineRegistration 配置强制重新注册到 Rancher。此过程会自动发生,无需任何手动干预。调用的脚本可以在 /opt/edge/elemental_node_cleanup.sh 中找到,将在放置标记后通过 systemd.path 触发,因此会立即执行。

警告
警告

使用 resettable 功能的假设条件是,从 Rancher 去除节点/群集时的所需行为是擦除数据并强制重新注册。在这种情况下,必然会丢失数据,因此,请仅在您确定要执行自动重置时才使用此功能。

2.5 后续步骤

下面是使用本指南后建议阅读的一些资源:

3 使用 Edge Image Builder 配置独立群集

Edge Image Builder (EIB) 工具可以简化为引导计算机生成自定义的、随时可引导 (CRB) 磁盘映像的过程,即使在完全隔离式方案中也能做到这一点。EIB 用于创建所有三个 SUSE Edge 部署空间中使用的部署映像,因为它足够灵活,可以提供最简单的自定义,例如通过提供全面配置的映像来添加用户或设置时区。例如,该映像可以设置复杂的网络配置、部署多节点 Kubernetes 群集、部署客户工作负载,并通过 Rancher/Elemental 和 SUSE Manager 注册到集中式管理平台。EIB 以容器映像的形式运行,因此具有极高的跨平台可移植性,可确保所有必需的依赖项都是独立的,对系统中安装的用于操作该工具的软件包的影响极小。

有关详细信息,请阅读 Edge Image Builder 简介(第 9 章 “Edge Image Builder)。

3.1 先决条件

  • 一台运行 SLES 15 SP5、openSUSE Leap 15.5 或 openSUSE Tumbleweed 的 x86_64 物理主机(或虚拟机)。

  • 一个可用的容器运行时(例如 Podman)

  • 最新 SLE Micro 5.5 SelfInstall“GM2”ISO 映像的下载副本,可在此处找到。

注意
注意

只要有兼容的容器运行时,其他操作系统就可以正常运行,但尚未在其他平台上进行广泛的测试。文档重点介绍 Podman,但 Docker 应该也能实现相同的功能。

3.1.1 获取 EIB 映像

EIB 容器映像已公开提供,可以通过在映像构建主机上运行以下命令从 SUSE Edge 注册表下载:

podman pull registry.suse.com/edge/edge-image-builder:1.0.2

3.2 创建映像配置目录

由于 EIB 在容器中运行,我们需要从主机挂载一个配置目录,以便能够指定所需的配置,并使 EIB 能够在构建过程中访问任何所需的输入文件和支持项目。此目录必须遵循特定的结构。我们在主目录中创建此目录,并将其命名为“eib”:

export CONFIG_DIR=$HOME/eib
mkdir -p $CONFIG_DIR/base-images

在上一步骤中,我们创建了“base-images”目录,用于托管 SLE Micro 5.5 输入映像,现在我们确保将下载的映像复制到配置目录:

cp /path/to/downloads/SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso $CONFIG_DIR/base-images/slemicro.iso
注意
注意

在 EIB 运行过程中,不会修改原始基础映像;在 EIB 配置目录的根目录中,会使用所需的配置创建新的自定义版本。

此时,配置目录应如下所示:

└── base-images/
    └── slemicro.iso

3.3 创建映像定义文件

定义文件描述 Edge Image Builder 支持的大多数可配置选项,可以在此处找到选项的完整示例,我们建议您查看上游构建映像指南,以获取比本文中更详细的示例。首先,我们需要为操作系统映像创建一个非常简单的定义文件:

cat << EOF > $CONFIG_DIR/iso-definition.yaml
apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
EOF

此定义指定我们要为基于 x86_64 的系统生成输出映像。用作基础的、要进一步修改的映像是名为 slemicro.isoiso 映像,其预期位置为 $CONFIG_DIR/base-images/slemicro.iso。此定义还概述了在 EIB 修改完映像后,输出映像将命名为 eib-image.iso,默认情况下,该输出映像驻留在 $CONFIG_DIR 中。

现在,我们的目录结构应如下所示:

├── iso-definition.yaml
└── base-images/
    └── slemicro.iso

下面的章节将演练几个常见操作的示例:

3.3.1 配置操作系统用户

EIB 允许您为用户预先配置登录信息(例如口令或 SSH 密钥),包括设置固定的 root 口令。作为此示例的一部分,我们将修复 root 口令,而第一步是使用 OpenSSL 创建一次性的已加密口令:

openssl passwd -6 SecurePassword

此命令将输出如下所示的内容:

$6$G392FCbxVgnLaFw1$Ujt00mdpJ3tDHxEg1snBU3GjujQf6f8kvopu7jiCBIhRbRvMmKUqwcmXAKggaSSKeUUOEtCP3ZUoZQY7zTXnC1

然后,我们可以在定义文件中添加一个名为 operatingSystem 的部分,其中包含 users 数组。生成的文件应如下所示:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$G392FCbxVgnLaFw1$Ujt00mdpJ3tDHxEg1snBU3GjujQf6f8kvopu7jiCBIhRbRvMmKUqwcmXAKggaSSKeUUOEtCP3ZUoZQY7zTXnC1
注意
注意

还可以添加其他用户、创建主目录、设置用户 ID、添加 ssh 密钥身份验证,以及修改组信息。请参见上游构建映像指南获取更多示例。

3.3.2 配置 RPM 软件包

EIB 的主要功能之一是提供一个机制来向映像添加更多软件包,以便在安装完成时,系统能够立即利用已安装的软件包。EIB 允许用户指定以下信息:

  • 映像定义中按名称列出的软件包

  • 要在其中搜索这些软件包的网络储存库

  • SUSE Customer Center (SCC) 身份凭证,用于在官方 SUSE 储存库中搜索列出的软件包

  • 通过 $CONFIG_DIR/rpms 目录侧载网络储存库中不存在的自定义 RPM

  • 通过同一目录 ($CONFIG_DIR/rpms/gpg-keys) 指定 GPG 密钥,以便可以验证第三方软件包

然后,EIB 将在映像构建时运行软件包解析过程,将基础映像用作输入,并尝试提取和安装所有提供的软件包(通过列表指定或在本地提供)。EIB 将所有软件包(包括所有依赖项)下载到输出映像中存在的储存库,并指示系统在首次引导过程中安装这些软件包。在映像构建期间执行此过程可确保在首次引导期间成功将软件包安装在所需平台(例如边缘节点)上。在您要将其他软件包植入映像,而不是在操作时通过网络提取软件包的环境(例如隔离环境或网络受限的环境)中,此行为也很有利。

我们通过一个简单的示例来演示这一点:我们将安装由第三方供应商支持的 NVIDIA 储存库中的 nvidia-container-toolkit RPM 软件包:

  packages:
    packageList:
      - nvidia-container-toolkit
    additionalRepos:
      - url: https://nvidia.github.io/libnvidia-container/stable/rpm/x86_64

生成的定义文件如下所示:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$G392FCbxVgnLaFw1$Ujt00mdpJ3tDHxEg1snBU3GjujQf6f8kvopu7jiCBIhRbRvMmKUqwcmXAKggaSSKeUUOEtCP3ZUoZQY7zTXnC1
  packages:
    packageList:
      - nvidia-container-toolkit
    additionalRepos:
      - url: https://nvidia.github.io/libnvidia-container/stable/rpm/x86_64

上面是一个简单的示例,但为了完整性,请在运行映像生成之前下载 NVIDIA 软件包签名密钥:

$ mkdir -p $CONFIG_DIR/rpms/gpg-keys
$ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey > rpms/gpg-keys/nvidia.gpg
警告
警告

通过此方法添加其他 RPM 的目的是添加受支持的第三方组件或用户提供(和维护)的软件包;请不要使用此机制来添加通常不受 SLE Micro 支持的软件包。如果使用此机制从 openSUSE 储存库(不受支持)添加组件,包括从较新的版本或服务包添加组件,那么,尽管最终系统看似能够按预期运行,但您最终得到的可能是一种不受支持的配置,尤其是当依赖项解析导致操作系统的核心部分被替换时。如果您不确定,请联系您的 SUSE 代表,以帮助确定所需配置的支持性。

注意
注意

上游安装软件包指南中可以找到更详细的指南和更多示例。

3.3.3 配置 Kubernetes 群集和用户工作负载

EIB 的另一个特点是,可以使用它来自动部署可“就地引导”(即,无需任何形式的集中式管理基础架构即可协调)的单节点和多节点高可用性 Kubernetes 群集。这种方法背后的主要推动因素是隔离式部署或网络受限的环境,但它也可以作为一种快速引导独立群集的方式,即使网络访问完全正常而不受限。

使用此方法不仅可以部署自定义的操作系统,还可以指定 Kubernetes 配置、通过 Helm chart 指定任何其他分层组件,以及通过提供的 Kubernetes 清单指定任何用户工作负载。但是,此方法幕后的设计原则是,我们默认假设用户想要隔离式部署,因此映像定义中指定的任何项目都将提取到映像中。这些项目包括用户提供的工作负载,在其中,EIB 将确保提供的定义所需的任何已发现映像都会在本地复制,并由最终部署的系统中的嵌入式映像注册表提供服务。

在下一个示例中,我们将采用现有的映像定义并指定 Kubernetes 配置(在本示例中,未列出系统及其角色,因此我们默认假设使用单节点群集),这会指示 EIB 置备单节点 RKE2 Kubernetes 群集。为了展示用户提供的工作负载(通过清单)和分层组件(通过 Helm)部署的自动化,我们将通过 SUSE Edge Helm chart 安装 KubeVirt,并通过 Kubernetes 清单安装 NGINX。需要追加到现有映像定义的附加配置如下:

kubernetes:
  version: v1.28.9+rke2r1
  manifests:
    urls:
      - https://k8s.io/examples/application/nginx-app.yaml
  helm:
    charts:
      - name: kubevirt-chart
        version: 0.2.4
        repositoryName: suse-edge
    repositories:
      - name: suse-edge
        url: oci://registry.suse.com/edge

生成的完整定义文件现在应如下所示:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$G392FCbxVgnLaFw1$Ujt00mdpJ3tDHxEg1snBU3GjujQf6f8kvopu7jiCBIhRbRvMmKUqwcmXAKggaSSKeUUOEtCP3ZUoZQY7zTXnC1
  packages:
    packageList:
      - nvidia-container-toolkit
    additionalRepos:
      - url: https://nvidia.github.io/libnvidia-container/stable/rpm/x86_64
kubernetes:
  version: v1.28.9+rke2r1
  manifests:
    urls:
      - https://k8s.io/examples/application/nginx-app.yaml
  helm:
    charts:
      - name: kubevirt-chart
        version: 0.2.4
        repositoryName: suse-edge
    repositories:
      - name: suse-edge
        url: oci://registry.suse.com/edge
注意
注意

上游文档中可以找到多节点部署、自定义网络等选项和 Helm chart 选项/值的更多示例。

3.3.4 配置网络

在本快速入门的最后一个示例中,我们来配置在使用 EIB 生成的映像置备系统时启动的网络。请务必知道,除非提供网络配置,否则默认模型是在引导时发现的所有接口上使用的 DHCP。但是,这种配置并非都很理想,特别是当 DHCP 不可用,并且您需要提供静态配置时、需要设置更复杂的网络结构(例如绑定、LACP 和 VLAN)或者需要覆盖某些参数(例如主机名、DNS 服务器和路由)时。

EIB 能够提供每个节点的配置(其中的相关系统由其 MAC 地址唯一标识),或者为每台计算机提供相同配置的覆盖值,这在系统 MAC 地址未知时更有用。EIB 使用一个称为 Network Manager Configurator(简称为 nmc)的附加工具,这是 SUSE Edge 团队构建的工具,用于基于 nmstate.io 声明式网络纲要应用自定义网络配置,在引导时识别其正在引导的节点,并在任何服务启动之前应用所需的网络配置。

我们现在通过在所需 network 目录中特定于节点的文件中(基于所需主机名)描述所需网络状态,为使用单一接口的系统应用静态网络配置:

mkdir $CONFIG_DIR/network

cat << EOF > $CONFIG_DIR/network/host1.local.yaml
routes:
  config:
  - destination: 0.0.0.0/0
    metric: 100
    next-hop-address: 192.168.122.1
    next-hop-interface: eth0
    table-id: 254
  - destination: 192.168.122.0/24
    metric: 100
    next-hop-address:
    next-hop-interface: eth0
    table-id: 254
dns-resolver:
  config:
    server:
    - 192.168.122.1
    - 8.8.8.8
interfaces:
- name: eth0
  type: ethernet
  state: up
  mac-address: 34:8A:B1:4B:16:E7
  ipv4:
    address:
    - ip: 192.168.122.50
      prefix-length: 24
    dhcp: false
    enabled: true
  ipv6:
    enabled: false
EOF
警告
警告

上述示例是针对默认 192.168.122.0/24 子网设置的,假设测试在虚拟机上执行,请根据您的环境进行调整,不要忘记设置 MAC 地址。由于可以使用同一映像来置备多个节点,EIB(通过 nmc)配置的网络取决于它是否能够根据其 MAC 地址唯一标识节点,因此在引导期间 nmc 将向每台计算机应用正确的网络配置。这意味着,您需要知道所要安装到的系统的 MAC 地址。或者,默认行为是依赖 DHCP,但您可以利用 configure-network.sh 挂钩将通用配置应用于所有节点 - 有关更多细节,请参见网络指南(第 10 章 “边缘网络)。

生成的文件结构应如下所示:

├── iso-definition.yaml
├── base-images/
│   └── slemicro.iso
└── network/
    └── host1.local.yaml

我们刚刚创建的网络配置将被分析,必要的 NetworkManager 连接文件将自动生成并插入到 EIB 要创建的新安装映像中。这些文件将在主机置备期间应用,从而生成完整的网络配置。

注意
注意

有关上述配置的更详细解释以及此功能的示例,请参见“边缘网络”组件(第 10 章 “边缘网络)。

3.4 构建映像

获得基础映像和可供 EIB 使用的映像定义后,接下来我们需要构建映像。为此,只需使用 podman 结合“build”命令调用 EIB 容器,并指定定义文件:

podman run --rm -it --privileged -v $CONFIG_DIR:/eib \
registry.suse.com/edge/edge-image-builder:1.0.2 \
build --definition-file iso-definition.yaml

该命令应输出如下所示的内容:

Setting up Podman API listener...
Generating image customization components...
Identifier ................... [SUCCESS]
Custom Files ................. [SKIPPED]
Time ......................... [SKIPPED]
Network ...................... [SUCCESS]
Groups ....................... [SKIPPED]
Users ........................ [SUCCESS]
Proxy ........................ [SKIPPED]
Resolving package dependencies...
Rpm .......................... [SUCCESS]
Systemd ...................... [SKIPPED]
Elemental .................... [SKIPPED]
Suma ......................... [SKIPPED]
Downloading file: dl-manifest-1.yaml 100%  (498/498 B, 5.9 MB/s)
Populating Embedded Artifact Registry... 100%  (3/3, 11 it/min)
Embedded Artifact Registry ... [SUCCESS]
Keymap ....................... [SUCCESS]
Configuring Kubernetes component...
The Kubernetes CNI is not explicitly set, defaulting to 'cilium'.
Downloading file: rke2_installer.sh
Downloading file: rke2-images-core.linux-amd64.tar.zst 100% (782/782 MB, 98 MB/s)
Downloading file: rke2-images-cilium.linux-amd64.tar.zst 100% (367/367 MB, 100 MB/s)
Downloading file: rke2.linux-amd64.tar.gz 100%  (34/34 MB, 101 MB/s)
Downloading file: sha256sum-amd64.txt 100%  (3.9/3.9 kB, 1.5 MB/s)
Downloading file: dl-manifest-1.yaml 100%  (498/498 B, 7.2 MB/s)
Kubernetes ................... [SUCCESS]
Certificates ................. [SKIPPED]
Building ISO image...
Kernel Params ................ [SKIPPED]
Image build complete!

构建的 ISO 映像存储在 $CONFIG_DIR/eib-image.iso 中:

├── iso-definition.yaml
├── eib-image.iso
├── _build
│   └── cache/
│       └── ...
│   └── build-<timestamp>/
│       └── ...
├── base-images/
│   └── slemicro.iso
└── network/
    └── host1.local.yaml

每次构建都会在 $CONFIG_DIR/_build/ 中创建一个带时间戳的文件夹,其中包含构建日志、构建期间使用的项目以及 combustionartefacts 目录,这两个目录包含添加到 CRB 映像的所有脚本和项目。

此目录的内容如下所示:

├── build-<timestamp>/
│   │── combustion/
│   │   ├── 05-configure-network.sh
│   │   ├── 10-rpm-install.sh
│   │   ├── 12-keymap-setup.sh
│   │   ├── 13b-add-users.sh
│   │   ├── 20-k8s-install.sh
│   │   ├── 26-embedded-registry.sh
│   │   ├── 48-message.sh
│   │   ├── network/
│   │   │   ├── host1.local/
│   │   │   │   └── eth0.nmconnection
│   │   │   └── host_config.yaml
│   │   ├── nmc
│   │   └── script
│   │── artefacts/
│   │   │── registry/
│   │   │   ├── hauler
│   │   │   ├── nginx:1.14.2-registry.tar.zst
│   │   │   ├── rancher_kubectl:v1.28.7-registry.tar.zst
│   │   │   └── registry.suse.com_suse_sles_15.5_virt-operator:1.1.1-150500.8.12.1-registry.tar.zst
│   │   │── rpms/
│   │   │   └── rpm-repo
│   │   │       ├── addrepo0
│   │   │       │   └── x86_64
│   │   │       │       ├── nvidia-container-toolkit-1.15.0-1.x86_64.rpm
│   │   │       │       ├── ...
│   │   │       ├── repodata
│   │   │       │   ├── ...
│   │   │       └── zypper-success
│   │   └── kubernetes/
│   │       ├── rke2_installer.sh
│   │       ├── registries.yaml
│   │       ├── server.yaml
│   │       ├── images/
│   │       │   ├── rke2-images-cilium.linux-amd64.tar.zst
│   │       │   └── rke2-images-core.linux-amd64.tar.zst
│   │       ├── install/
│   │       │   ├── rke2.linux-amd64.tar.gz
│   │       │   └── sha256sum-amd64.txt
│   │       └── manifests/
│   │           ├── dl-manifest-1.yaml
│   │           └── kubevirt-chart.yaml
│   ├── createrepo.log
│   ├── eib-build.log
│   ├── embedded-registry.log
│   ├── helm
│   │   └── kubevirt-chart
│   │       └── kubevirt-0.2.4.tgz
│   ├── helm-pull.log
│   ├── helm-template.log
│   ├── iso-build.log
│   ├── iso-build.sh
│   ├── iso-extract
│   │   └── ...
│   ├── iso-extract.log
│   ├── iso-extract.sh
│   ├── modify-raw-image.sh
│   ├── network-config.log
│   ├── podman-image-build.log
│   ├── podman-system-service.log
│   ├── prepare-resolver-base-tarball-image.log
│   ├── prepare-resolver-base-tarball-image.sh
│   ├── raw-build.log
│   ├── raw-extract
│   │   └── ...
│   └── resolver-image-build
│       └──...
└── cache
    └── ...

如果构建失败,首先会在 eib-build.log 中记录相关信息。该日志会指出哪个组件构建失败,方便您进行调试。

此时,您应该有了一个随时可用的映像,它可以:

  1. 部署 SLE Micro 5.5

  2. 配置 root 口令

  3. 安装 nvidia-container-toolkit 软件包

  4. 配置嵌入式容器注册表以在本地处理内容

  5. 安装单节点 RKE2

  6. 配置静态网络

  7. 安装 KubeVirt

  8. 部署用户提供的清单

3.5 调试映像构建过程

如果映像构建过程失败,请参见上游调试指南

3.6 测试新构建的映像

有关如何测试新构建的 CRB 映像的说明,请参见上游映像测试指南

第 II 部分 使用的组件

Edge 的组件列表

  • 4 Rancher
  • 请参见 https://ranchermanager.docs.rancher.com 上的 Rancher 上游文档。

  • 5 Rancher 仪表板扩展
  • 用户、开发人员、合作伙伴及客户可以使用扩展来扩展和增强 Rancher UI。SUSE Edge 3.0 提供 KubeVirt 和 Akri 仪表板扩展。

  • 6 Fleet
  • Fleet 是一个容器管理和部署引擎,旨在让用户更好地控制本地群集,并通过 GitOps 进行持续监控。Fleet 不仅注重缩放能力,而且还为用户提供很高的控制度和可见性,以准确监控群集上安装的组件。

  • 7 SLE Micro
  • 请参见 SLE Micro 官方文档

  • 8 Metal3
  • Metal3 是一个 CNCF 项目,它为 Kubernetes 提供裸机基础架构管理功能。

  • 9 Edge Image Builder
  • 请参见官方储存库

  • 10 边缘网络
  • 本章介绍 SUSE Edge 解决方案中的网络配置方法。我们将展示如何以声明方式在 SLE Micro 上配置 NetworkManager,并说明如何集成相关的工具。

  • 11 Elemental
  • Elemental 是一个软件堆栈,可用于通过 Kubernetes 实现集中式云原生操作系统全面管理。Elemental 堆栈由驻留在 Rancher 本身或边缘节点上的许多组件构成。核心组件包括:

  • 12 Akri
  • Akri 是一个 CNCF 沙箱项目,旨在发现叶设备并将其呈现为 Kubernetes 原生资源。它还允许为每个发现的设备调度一个 Pod 或作业。设备可以在节点本地,也可以联网,并可以使用多种协议。

  • 13 K3s
  • K3s 是高度可用的、经过认证的 Kubernetes 发行版,专为无人照管、资源受限的远程位置或物联网设备内的生产工作负载而设计。

  • 14 RKE2
  • 请参见 RKE2 官方文档

  • 15 Longhorn
  • Longhorn 是专为 Kubernetes 设计的可靠且用户友好的轻量级分布式块存储系统。作为一个开源项目,Longhorn 最初由 Rancher Labs 开发,目前正在由 CNCF 孵化。

  • 16 NeuVector
  • NeuVector 是适用于 Kubernetes 的安全解决方案,它在统一的软件包中提供 L7 网络安全性、运行时安全性、供应链安全性与合规性检查。

  • 17 MetalLB
  • 请参见 MetalLB 官方文档

  • 18 边缘虚拟化
  • 本章介绍如何使用边缘虚拟化在边缘节点上运行虚拟机。必须指出的是,边缘虚拟化并非全面的解决方案,其功能有限;它会尝试解决需要基本虚拟机功能的轻量级虚拟化的要求。SUSE 通过 Harvester 提供更全面的虚拟化(和超融合基础架构)解决方案。

4 Rancher

请参见 https://ranchermanager.docs.rancher.com 上的 Rancher 上游文档。

Rancher 是一个功能强大的开源 Kubernetes 管理平台,可以简化跨多个环境的 Kubernetes 群集的部署、操作和监控。无论您是在本地、云中还是边缘管理群集,Rancher 都能提供统一且集中的平台来满足您的所有 Kubernetes 需求。

4.1 Rancher 的主要功能

  • 多群集管理:Rancher 的直观界面让您可以从任何位置(公有云、专用数据中心和边缘位置)管理 Kubernetes 群集。

  • 安全性与合规性:Rancher 在您的 Kubernetes 环境中实施安全策略、基于角色的访问控制 (RBAC) 与合规性标准。

  • 简化的群集操作:Rancher 可自动执行群集置备、升级和查错,并为各种规模的团队简化 Kubernetes 操作。

  • 集中式应用程序目录:Rancher 应用程序目录提供多种 Helm chart 和 Kubernetes 操作器,使容器化应用程序的部署和管理变得简单。

  • 持续交付:Rancher 支持 GitOps 和 CI/CD 管道,可以自动化和简化应用程序交付过程。

4.2 Rancher 在 SUSE Edge 中的使用

Rancher 为 SUSE Edge 堆栈提供多项核心功能:

4.2.1 集中式 Kubernetes 管理

在采用大量分布式群集的典型边缘部署中,Rancher 充当中心控制平面来管理这些 Kubernetes 群集。它提供统一的界面用于置备、升级、监控和查错、简化操作并确保一致性。

4.2.2 简化的群集部署

Rancher 简化了轻量级 SLE Micro (SUSE Linux Enterprise Micro) 操作系统上的 Kubernetes 群集创建,并通过稳健的 Kubernetes 功能简化了边缘基础架构的部署。

4.2.3 应用程序部署和管理

集成的 Rancher 应用程序目录可以简化跨 SUSE Edge 群集的容器化应用程序的部署和管理,实现无缝的边缘工作负载部署。

4.2.4 安全性和策略实施

Rancher 提供基于策略的治理工具、基于角色的访问控制 (RBAC),以及与外部身份验证提供程序的集成。这有助于 SUSE Edge 部署保持安全且合规,在分布式环境中,这一点至关重要。

4.3 最佳实践

4.3.1 GitOps

Rancher 包含内置组件 Fleet。使用 Fleet 可以通过 git 中存储的代码管理群集配置和应用程序部署。

4.3.2 可观测性

Rancher 包含 Prometheus 和 Grafana 等内置监控和日志记录工具,可提供群集健康状况和性能的综合深入信息。

4.4 使用 Edge Image Builder 进行安装

SUSE Edge 使用第 9 章 “Edge Image Builder来自定义基础 SLE Micro 操作系统映像。请按照第 21.6 节 “Rancher 安装”中所述,在 EIB 置备的 Kubernetes 群集上进行 Rancher 隔离式安装。

4.5 其他资源

5 Rancher 仪表板扩展

用户、开发人员、合作伙伴及客户可以使用扩展来扩展和增强 Rancher UI。SUSE Edge 3.0 提供 KubeVirt 和 Akri 仪表板扩展。

有关 Rancher 仪表板扩展的一般信息,请参见 Rancher 文档

5.1 先决条件

要启用扩展,需按照 Rancher 的要求安装 ui-plugin 操作器。使用 Rancher 仪表板 UI 时,导航到左侧 Configuration(配置)导航部分中的 Extensions(扩展)。如果未安装 ui-plugin 操作器,系统会提示您按此处所述启用扩展支持。

也可以使用 Helm 安装该操作器:

helm repo add rancher-charts https://charts.rancher.io/
helm upgrade --create-namespace -n cattle-ui-plugin-system \
  --install ui-plugin-operator rancher-charts/ui-plugin-operator
helm upgrade --create-namespace -n cattle-ui-plugin-system \
  --install ui-plugin-operator-crd rancher-charts/ui-plugin-operator-crd

或者,可以在 Fleet 中创建专用的 GitRepo 资源。有关详细信息,请参见 Fleet 一章和 fleet-examples 储存库。

5.2 安装

所有 SUSE Edge 3.0 组件(包括仪表板扩展)均作为 OCI 项目分发。Rancher 仪表板 Apps/Marketplace 目前不支持基于 OCI 的 Helm 储存库。因此,要安装 SUSE Edge 扩展,可以使用 Helm 或 Fleet:

5.2.1 使用 Helm 进行安装

# KubeVirt extension
helm install kubevirt-dashboard-extension oci://registry.suse.com/edge/kubevirt-dashboard-extension-chart --version 1.0.0 --namespace cattle-ui-plugin-system

# Akri extension
helm install akri-dashboard-extension oci://registry.suse.com/edge/akri-dashboard-extension-chart --version 1.0.0 --namespace cattle-ui-plugin-system
注意
注意

扩展需安装在 cattle-ui-plugin-system 名称空间中。

注意
注意

安装扩展后,需要重新加载 Rancher 仪表板 UI。

5.2.2 使用 Fleet 进行安装

使用 Fleet 安装仪表板扩展需要定义一个 gitRepo 资源,该资源指向包含自定义 fleet.yaml 捆绑包配置文件的 Git 储存库。

# KubeVirt extension fleet.yaml
defaultNamespace: cattle-ui-plugin-system
helm:
  releaseName: kubevirt-dashboard-extension
  chart: oci://registry.suse.com/edge/akri-dashboard-extension-chart
  version: "1.0.0"
# Akri extension fleet.yaml
defaultNamespace: cattle-ui-plugin-system
helm:
  releaseName: akri-dashboard-extension
  chart: oci://registry.suse.com/edge/akri-dashboard-extension-chart
  version: "1.0.0"
注意
注意

releaseName 属性是必需的,它需要与扩展名称匹配,才能让 ui-plugin-operator 正确安装扩展。

cat <<- EOF | kubectl apply -f -
apiVersion: fleet.cattle.io/v1alpha1
metadata:
  name: edge-dashboard-extensions
  namespace: fleet-local
spec:
  repo: https://github.com/suse-edge/fleet-examples.git
  branch: main
  paths:
  - fleets/kubevirt-dashboard-extension/
  - fleets/akri-dashboard-extension/
EOF

有关详细信息,请参见 Fleet 一章和 fleet-examples 储存库。

安装扩展后,它们将列在 Installed(已安装)选项卡下的 Extensions(扩展)部分中。由于它们不是通过 Apps/Marketplace 安装的,因此带有 Third-Party(第三方)标签。

已安装的仪表板扩展

5.3 KubeVirt 仪表板扩展

KubeVirt 扩展为 Rancher 仪表板 UI 提供基本虚拟机管理。边缘虚拟化中介绍了其功能。

5.4 Akri 仪表板扩展

Akri 是一个 Kubernetes 资源接口,让您可以轻松地将异构叶设备(例如 IP 摄像头和 USB 设备)公开为 Kubernetes 群集中的资源,同时还支持公开 GPU 和 FPGA 等嵌入式硬件资源。Akri 会持续检测有权访问这些设备的节点,并根据这些节点调度工作负载。

Akri 仪表板扩展允许您使用 Rancher 仪表板用户界面来管理和监控叶设备,并在发现这些设备后运行工作负载。

Akri 一章中更详细地介绍了扩展功能。

6 Fleet

Fleet 是一个容器管理和部署引擎,旨在让用户更好地控制本地群集,并通过 GitOps 进行持续监控。Fleet 不仅注重缩放能力,而且还为用户提供很高的控制度和可见性,以准确监控群集上安装的组件。

Fleet 可以管理通过原始 Kubernetes YAML、Helm chart、Kustomize 的 Git 软件包或这三者的任意组合完成的部署。无论源是什么,所有资源都会动态转换为 Helm chart,并使用 Helm 作为引擎在群集中部署所有资源。因此,用户可以享受很高的群集控制度、一致性和可审计性。

有关 Fleet 工作原理的信息,请参见此处

6.1 使用 Helm 安装 Fleet

Fleet 已内置于 Rancher 中,但您也可以使用 Helm 将 Fleet 安装为任何 Kubernetes 群集上的独立应用程序。

6.2 使用 Rancher 中的 Fleet

Rancher 使用 Fleet 在受管群集中部署应用程序。Fleet 的持续交付功能引入了大规模 GitOps,旨在管理在大量群集上运行的应用程序。

作为 Rancher 中不可或缺的组成部分,Fleet 的作用令人瞩目。使用 Rancher 管理的群集会在安装/导入过程中自动由 Fleet 代理部署,并且群集立即可由 Fleet 管理。

6.3 在 Rancher UI 中访问 Fleet

Fleet 已预装在 Rancher 中,可以通过 Rancher UI 中的 Continuous Delivery(持续交付)选项进行管理。有关“Continuous Delivery”(持续交付)和其他 Fleet 查错提示的更多信息,请参见此处

Fleet 仪表板

“Continuous Delivery”(持续交付)部分包括以下项目:

6.3.1 Dashboard(仪表板)

所有工作空间中所有 GitOps 储存库的概览页面。仅显示包含储存库的工作空间。

6.3.2 Git repos(Git 储存库)

所选工作空间中的 GitOps 储存库列表。使用页面顶部的下拉列表选择活动工作空间。

6.3.3 Clusters(群集)

受管群集列表。默认情况下,Rancher 管理的所有群集都会添加到 fleet-default 工作空间。fleet-local 工作空间包含本地(管理)群集。在此处可以暂停强制更新群集,或者将群集移动到另一个工作空间。可以通过编辑群集来更新用于群集分组的标签和批注。

6.3.4 Cluster groups(群集组)

在此部分,可以使用选择器对工作空间内的群集进行自定义分组。

6.3.5 Advanced(高级)

在“Advanced”(高级)部分可以管理工作空间和其他相关 Fleet 资源。

6.4 使用 Rancher 仪表板通过 Rancher 和 Fleet 安装 KubeVirt 的示例

  1. 创建包含 fleet.yaml 文件的 Git 储存库:

    defaultNamespace: kubevirt
    helm:
      chart: "oci://registry.suse.com/edge/kubevirt-chart"
      version: "0.2.4"
      # kubevirt namespace is created by kubevirt as well, we need to take ownership of it
      takeOwnership: true
  2. 在 Rancher 仪表板中,导航到 ☰ > Continuous Delivery(持续交付)> Git repos(Git 储存库),然后单击 Add Repository(添加储存库)。

  3. 储存库创建向导将指导您完成 Git 储存库创建步骤。提供名称储存库 URL(引用上一步骤中创建的 Git 储存库),并选择适当的分支或修订版。对于较复杂的储存库,请指定路径以便在单个储存库中使用多个目录。

    Fleet - 创建储存库 1
  4. 单击 Next(下一步)。

  5. 在下一步骤中,可以定义工作负载的部署位置。在群集选择方面,可以使用多个基本选项:可以不选择任何群集、选择所有群集,或者直接选择特定的受管群集或群集组(如果已定义)。“Advanced”(高级)选项允许通过 YAML 直接编辑选择器。

    Fleet - 创建储存库 2
  6. 单击 Create(创建)。随即会创建储存库。从现在起,工作负载将在与储存库定义匹配的群集上安装并保持同步。

6.5 调试和查错

“Advanced”(高级)导航部分提供了较低级 Fleet 资源的概览。捆绑包是一个内部资源,用于编排 Git 中的资源。扫描 Git 储存库时,会生成一个或多个捆绑包。

要查找与特定储存库相关的捆绑包,请转到 Git 储存库细节页面,并单击 Bundles(捆绑包)选项卡。

Fleet 储存库捆绑包

对于每个群集,捆绑包将应用于创建的 BundleDeployment 资源。要查看 BundleDeployment 细节,请单击 Git 储存库细节页面右上角的 Graph(图表)按钮。随即会加载 Repo(储存库)> Bundles(捆绑包)> BundleDeployment 图表。在图表中单击相应 BundleDeployment 可查看其细节,单击 ID 可查看 BundleDeployment YAML。

Fleet 储存库图表

有关 Fleet 查错提示的更多信息,请参见此处

6.6 Fleet 示例

Edge 团队维护的一个储存库包含了有关使用 Fleet 安装 Edge 项目的示例。

Fleet 项目包含 fleet-examples 储存库,其中涵盖了 Git 储存库结构的所有用例。

7 SLE Micro

请参见 SLE Micro 官方文档

SUSE Linux Enterprise Micro 是一个安全的轻量级边缘操作系统。它将 SUSE Linux Enterprise 的企业强化组件与开发人员需要的各种功能融入一套不可变的新式操作系统,从而形成一个可靠的基础架构平台,不仅具有同类最佳的合规性,而且易于使用。

7.1 SUSE Edge 如何使用 SLE Micro?

我们使用 SLE Micro 作为平台堆栈的基础操作系统。它为我们提供了安全、稳定且精简的构建基础。

SLE Micro 的独特之处在于使用文件系统 (Btrfs) 快照,因此如果在升级期间出错,我们就可以轻松回滚。这样,在出现问题时,即使无法进行物理访问,也可以对整个平台安全地进行远程升级。

7.2 最佳实践

7.2.1 安装媒体

SUSE Edge 使用 Edge Image Builder(第 9 章 “Edge Image Builder)来预配置 SLE Micro 自行安装映像。

7.2.2 本地管理

SLE Micro 附带 Cockpit,让您可以通过 Web 应用程序对主机进行本地管理。

此服务默认已禁用,但可以通过启用 systemd 服务 cockpit.socket 来启动。

7.3 已知问题

  • SLE Micro 目前不提供桌面环境,但正在开发容器化解决方案。

8 Metal3

Metal3 是一个 CNCF 项目,它为 Kubernetes 提供裸机基础架构管理功能。

Metal3 提供 Kubernetes 原生资源来管理裸机服务器的生命周期,支持通过 Redfish 等带外协议进行管理。

它还为群集 API (CAPI) 提供成熟的支持,允许通过广泛采用的不区分供应商的 API 来管理跨多个基础架构提供商的基础架构资源。

8.1 SUSE Edge 如何使用 Metal3?

此方法非常适合用于目标硬件支持带外管理,并且需要全自动化基础架构管理流程的方案。

此方法提供声明性 API 来对裸机服务器进行清单和状态管理,包括自动检查、清理和置备/取消置备。

8.2 已知问题

  • 上游 IP 地址管理控制器目前不受支持,因为它与我们选择的网络配置工具尚不兼容。

  • 相关的 IPAM 资源和 Metal3DataTemplate networkData 字段也不受支持。

  • 目前仅支持通过 redfish-virtualmedia 进行部署。

9 Edge Image Builder

请参见官方储存库

Edge Image Builder (EIB) 工具可以简化为引导计算机生成自定义的、随时可引导 (CRB) 磁盘映像的过程。使用其中的一个映像就能实现整个 SUSE 软件堆栈的端到端部署。

虽然 EIB 可为所有置备方案创建 CRB 映像,但 EIB 在网络受限或完全隔离的隔离式部署中展示了巨大价值。

9.1 SUSE Edge 如何使用 Edge Image Builder?

SUSE Edge 使用 EIB 来简化和快速配置自定义 SLE Micro 映像,以适应各种方案。这些方案包括通过以下方式引导虚拟机和裸机:

  • K3s/RKE2 Kubernetes 的完全隔离式部署(单节点和多节点)

  • 完全隔离式 Helm chart和 Kubernetes 清单部署

  • 通过 Elemental API 注册到 Rancher

  • Metal3

  • 自定义网络(例如静态 IP、主机名、VLAN、绑定等)

  • 自定义操作系统配置(例如用户、组、口令、SSH 密钥、代理、NTP、自定义 SSL 证书等)

  • 主机级和侧载 RPM 软件包的隔离式安装(包括依赖项解析)

  • 注册到 SUSE Manager 进行操作系统管理

  • 嵌入式容器映像

  • 内核命令行参数

  • 引导时启用/禁用的 Systemd 单元

  • 用于任何手动任务的自定义脚本和文件

9.2 入门

有关 Edge Image Builder 用法和测试的综合文档可在此处找到。

此处还提供了 Edge Image Builder 的快速入门指南(第 3 章 “使用 Edge Image Builder 配置独立群集),其中包括基本部署方案。

9.3 已知问题

  • EIB 通过模板化 Helm chart 并分析模板中的所有映像来隔离 Helm chart。如果 Helm chart 未将其所有映像保留在模板中,而是侧载映像,则 EIB 将无法自动隔离这些映像。此问题的解决方法是手动将任何未检测到的映像添加到定义文件的 embeddedArtifactRegistry 部分。

10 边缘网络

本章介绍 SUSE Edge 解决方案中的网络配置方法。我们将展示如何以声明方式在 SLE Micro 上配置 NetworkManager,并说明如何集成相关的工具。

10.1 NetworkManager 概述

NetworkManager 是用于管理主网络连接和其他连接接口的工具。

NetworkManager 将网络配置存储为包含所需状态的连接文件。这些连接以文件的形式存储在 /etc/NetworkManager/system-connections/ 目录中。

有关 NetworkManager 的细节,请参见上游 SLE Micro 文档

10.2 nmstate 概述

nmstate 是广泛采用的库(附带 CLI 工具),它提供声明性 API 用于通过预定义的纲要进行网络配置。

有关 nmstate 的细节,请参见上游文档

10.3 NetworkManager Configurator (nmc) 概述

SUSE Edge 中提供的网络自定义选项是通过一个称为 NetworkManager Configurator(简称为 nmc)的 CLI 工具实现的。此工具利用 nmstate 库提供的功能,因此完全能够配置静态 IP 地址、DNS 服务器、VLAN、绑定、网桥等。我们可以使用此工具从预定义的所需状态生成网络配置,并自动将这些配置应用于许多不同的节点。

有关 NetworkManager Configurator (nmc) 的细节,请参见上游储存库

10.4 SUSE Edge 如何使用 NetworkManager Configurator?

SUSE Edge 利用 nmc 在各种不同的置备模型中进行网络自定义:

10.5 使用 Edge Image Builder 进行配置

Edge Image Builder (EIB) 是可用于通过单个操作系统映像配置多个主机的工具。本节将介绍如何使用声明性方法来描述所需网络状态,如何将这些状态转换为相应的 NetworkManager 连接,然后在置备过程中应用这些连接。

10.5.1 先决条件

如果您要学习本指南,事先需要做好以下准备:

  • 一台运行 SLES 15 SP5 或 openSUSE Leap 15.5 的 x86_64 物理主机(或虚拟机)

  • 一个可用的容器运行时(例如 Podman)

  • SLE Micro 5.5 RAW 映像的副本,可在此处找到

10.5.2 获取 Edge Image Builder 容器映像

EIB 容器映像已公开提供,可以通过运行以下命令从 SUSE Edge 注册表下载:

podman pull registry.suse.com/edge/edge-image-builder:1.0.2

10.5.3 创建映像配置目录

我们来开始创建配置目录:

export CONFIG_DIR=$HOME/eib
mkdir -p $CONFIG_DIR/base-images

确保下载的基础映像副本已移动到配置目录:

mv /path/to/downloads/SLE-Micro.x86_64-5.5.0-Default-GM.raw $CONFIG_DIR/base-images/
注意
注意

EIB 永远不会修改基础映像输入。

此时,配置目录应如下所示:

└── base-images/
    └── SLE-Micro.x86_64-5.5.0-Default-GM.raw

10.5.4 创建映像定义文件

定义文件描述了 Edge Image Builder 支持的大多数可配置选项。

首先,我们为操作系统映像创建一个非常简单的定义文件:

cat << EOF > $CONFIG_DIR/definition.yaml
apiVersion: 1.0
image:
  arch: x86_64
  imageType: raw
  baseImage: SLE-Micro.x86_64-5.5.0-Default-GM.raw
  outputImageName: modified-image.raw
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$jHugJNNd3HElGsUZ$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
EOF

image 部分是必需的,它指定输入映像、输入映像的体系结构和类型,以及输出映像的名称。operatingSystem 部分是可选的,其中包含的配置可用于通过 root/eib 用户名/口令登录到置备的系统。

注意
注意

您可以运行 openssl passwd -6 <password> 任意使用自己的已加密口令。

此时,配置目录应如下所示:

├── definition.yaml
└── base-images/
    └── SLE-Micro.x86_64-5.5.0-Default-GM.raw

10.5.5 定义网络配置

所需网络配置不是我们刚刚创建的映像定义文件的一部分。现在我们在特殊的 network/ 目录下填充这些配置。我们来创建该目录:

mkdir -p $CONFIG_DIR/network

如前所述,NetworkManager Configurator (nmc) 工具要求提供预定义纲要形式的输入。您可以在上游 NMState 示例文档中了解如何设置各种不同的网络选项。

本指南将介绍如何在三个不同的节点上配置网络:

  • 使用两个以太网接口的节点

  • 使用网络绑定的节点

  • 使用网桥的节点

警告
警告

不建议在生产构建中使用完全不同的网络设置,尤其是在配置 Kubernetes 群集时。网络配置通常应在节点之间或至少在给定群集内的角色之间保持同质。本指南包含的各种不同选项仅供参考。

注意
注意

以下示例采用 IP 地址范围为 192.168.122.1/24 的默认 libvirt 网络。如果您的环境与此不同,请相应地进行调整。

我们来为第一个节点(名为 node1.suse.com)创建所需状态:

cat << EOF > $CONFIG_DIR/network/node1.suse.com.yaml
routes:
  config:
    - destination: 0.0.0.0/0
      metric: 100
      next-hop-address: 192.168.122.1
      next-hop-interface: eth0
      table-id: 254
    - destination: 192.168.122.0/24
      metric: 100
      next-hop-address:
      next-hop-interface: eth0
      table-id: 254
dns-resolver:
  config:
    server:
      - 192.168.122.1
      - 8.8.8.8
interfaces:
  - name: eth0
    type: ethernet
    state: up
    mac-address: 34:8A:B1:4B:16:E1
    ipv4:
      address:
        - ip: 192.168.122.50
          prefix-length: 24
      dhcp: false
      enabled: true
    ipv6:
      enabled: false
  - name: eth3
    type: ethernet
    state: down
    mac-address: 34:8A:B1:4B:16:E2
    ipv4:
      address:
        - ip: 192.168.122.55
          prefix-length: 24
      dhcp: false
      enabled: true
    ipv6:
      enabled: false
EOF

在此示例中,我们将定义两个以太网接口(eth0 和 eth3)的所需状态、其请求 IP 地址、路由和 DNS 解析。

警告
警告

必须确保列出了所有以太网接口的 MAC 地址。这些地址在置备过程中用作节点的标识符,用于确定要应用哪些配置。这就是我们使用单个 ISO 或 RAW 映像配置多个节点的方式。

接下来对第二个节点(名为 node2.suse.com)进行操作,该节点使用网络绑定:

cat << EOF > $CONFIG_DIR/network/node2.suse.com.yaml
routes:
  config:
    - destination: 0.0.0.0/0
      metric: 100
      next-hop-address: 192.168.122.1
      next-hop-interface: bond99
      table-id: 254
    - destination: 192.168.122.0/24
      metric: 100
      next-hop-address:
      next-hop-interface: bond99
      table-id: 254
dns-resolver:
  config:
    server:
      - 192.168.122.1
      - 8.8.8.8
interfaces:
  - name: bond99
    type: bond
    state: up
    ipv4:
      address:
        - ip: 192.168.122.60
          prefix-length: 24
      enabled: true
    link-aggregation:
      mode: balance-rr
      options:
        miimon: '140'
      port:
        - eth0
        - eth1
  - name: eth0
    type: ethernet
    state: up
    mac-address: 34:8A:B1:4B:16:E3
    ipv4:
      enabled: false
    ipv6:
      enabled: false
  - name: eth1
    type: ethernet
    state: up
    mac-address: 34:8A:B1:4B:16:E4
    ipv4:
      enabled: false
    ipv6:
      enabled: false
EOF

在此示例中,我们将定义两个未启用 IP 寻址的以太网接口(eth0 和 eth1)的所需状态,以及采用轮替策略的绑定及其用于转发网络流量的相应地址。

最后,我们将创建第三个(也是最后一个)所需状态文件,该文件利用网桥,我们将其命名为 node3.suse.com

cat << EOF > $CONFIG_DIR/network/node3.suse.com.yaml
routes:
  config:
    - destination: 0.0.0.0/0
      metric: 100
      next-hop-address: 192.168.122.1
      next-hop-interface: linux-br0
      table-id: 254
    - destination: 192.168.122.0/24
      metric: 100
      next-hop-address:
      next-hop-interface: linux-br0
      table-id: 254
dns-resolver:
  config:
    server:
      - 192.168.122.1
      - 8.8.8.8
interfaces:
  - name: eth0
    type: ethernet
    state: up
    mac-address: 34:8A:B1:4B:16:E5
    ipv4:
      enabled: false
    ipv6:
      enabled: false
  - name: linux-br0
    type: linux-bridge
    state: up
    ipv4:
      address:
        - ip: 192.168.122.70
          prefix-length: 24
      dhcp: false
      enabled: true
    bridge:
      options:
        group-forward-mask: 0
        mac-ageing-time: 300
        multicast-snooping: true
        stp:
          enabled: true
          forward-delay: 15
          hello-time: 2
          max-age: 20
          priority: 32768
      port:
        - name: eth0
          stp-hairpin-mode: false
          stp-path-cost: 100
          stp-priority: 32
EOF

此时,配置目录应如下所示:

├── definition.yaml
├── network/
│   │── node1.suse.com.yaml
│   │── node2.suse.com.yaml
│   └── node3.suse.com.yaml
└── base-images/
    └── SLE-Micro.x86_64-5.5.0-Default-GM.raw
注意
注意

network/ 目录中的文件是有意命名的。它们对应于在置备过程中要设置的主机名。

10.5.6 构建操作系统映像

完成所有必要配置后,接下来我们只需运行以下命令来构建映像:

podman run --rm -it -v $CONFIG_DIR:/eib registry.suse.com/edge/edge-image-builder:1.0.2 build --definition-file definition.yaml

输出应如下所示:

Generating image customization components...
Identifier ................... [SUCCESS]
Custom Files ................. [SKIPPED]
Time ......................... [SKIPPED]
Network ...................... [SUCCESS]
Groups ....................... [SKIPPED]
Users ........................ [SUCCESS]
Proxy ........................ [SKIPPED]
Rpm .......................... [SKIPPED]
Systemd ...................... [SKIPPED]
Elemental .................... [SKIPPED]
Suma ......................... [SKIPPED]
Embedded Artifact Registry ... [SKIPPED]
Keymap ....................... [SUCCESS]
Kubernetes ................... [SKIPPED]
Certificates ................. [SKIPPED]
Building RAW image...
Kernel Params ................ [SKIPPED]
Image build complete!

以上输出片段告诉我们网络组件已成功配置,我们可以继续置备边缘节点。

注意
注意

可以在运行映像的带时间戳目录下生成的 _build 目录中,检查日志文件 (network-config.log) 和相应的 NetworkManager 连接文件。

10.5.7 置备边缘节点

我们来复制生成的 RAW 映像:

mkdir edge-nodes && cd edge-nodes
for i in {1..4}; do cp $CONFIG_DIR/modified-image.raw node$i.raw; done

您会发现,我们复制了构建的映像四次,但仅指定了三个节点的网络配置。这是因为,我们还想展示当置备的节点与任何所需配置都不匹配时会发生什么。

注意
注意

本指南将为节点置备示例使用虚拟化。请确保在 BIOS 中启用必要的扩展(有关细节,请参见此处)。

我们将运行 virt-install 使用复制的原始磁盘来创建虚拟机。每个虚拟机使用 10 GB RAM 和 6 个 vCPU。

10.5.7.1 置备第一个节点

我们来创建虚拟机:

virt-install --name node1 --ram 10000 --vcpus 6 --disk path=node1.raw,format=raw --osinfo detect=on,name=sle-unknown --graphics none --console pty,target_type=serial --network default,mac=34:8A:B1:4B:16:E1 --network default,mac=34:8A:B1:4B:16:E2 --virt-type kvm --import
注意
注意

要创建的网络接口的 MAC 地址必须与上述所需状态中使用的 MAC 地址相同。

操作完成后,我们将看到如下所示的输出:

Starting install...
Creating domain...

Running text console command: virsh --connect qemu:///system console node1
Connected to domain 'node1'
Escape character is ^] (Ctrl + ])


Welcome to SUSE Linux Enterprise Micro 5.5  (x86_64) - Kernel 5.14.21-150500.55.19-default (ttyS0).

SSH host key: SHA256:XN/R5Tw43reG+QsOw480LxCnhkc/1uqMdwlI6KUBY70 (RSA)
SSH host key: SHA256:/96yGrPGKlhn04f1rb9cXv/2WJt4TtrIN5yEcN66r3s (DSA)
SSH host key: SHA256:Dy/YjBQ7LwjZGaaVcMhTWZNSOstxXBsPsvgJTJq5t00 (ECDSA)
SSH host key: SHA256:TNGqY1LRddpxD/jn/8dkT/9YmVl9hiwulqmayP+wOWQ (ED25519)
eth0: 192.168.122.50
eth1:


Configured with the Edge Image Builder
Activate the web console with: systemctl enable --now cockpit.socket

node1 login:

现在我们可以使用 root:eib 身份凭证对登录。如果需要,我们也可以通过 SSH 连接到主机,而不是如此处所示使用 virsh 控制台进行连接。

登录后,我们需要确认是否正确完成了所有设置。

校验是否正确设置了主机名:

node1:~ # hostnamectl
 Static hostname: node1.suse.com
 ...

校验是否正确配置了路由:

node1:~ # ip r
default via 192.168.122.1 dev eth0 proto static metric 100
192.168.122.0/24 dev eth0 proto static scope link metric 100
192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.50 metric 100

校验互联网连接是否可用:

node1:~ # ping google.com
PING google.com (142.250.72.78) 56(84) bytes of data.
64 bytes from den16s09-in-f14.1e100.net (142.250.72.78): icmp_seq=1 ttl=56 time=13.2 ms
64 bytes from den16s09-in-f14.1e100.net (142.250.72.78): icmp_seq=2 ttl=56 time=13.4 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 13.248/13.304/13.361/0.056 ms

校验是否刚好配置了两个以太网接口,并且只有其中的一个接口处于活动状态:

node1:~ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 34:8a:b1:4b:16:e1 brd ff:ff:ff:ff:ff:ff
    altname enp0s2
    altname ens2
    inet 192.168.122.50/24 brd 192.168.122.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 34:8a:b1:4b:16:e2 brd ff:ff:ff:ff:ff:ff
    altname enp0s3
    altname ens3

node1:~ # nmcli -f NAME,UUID,TYPE,DEVICE,FILENAME con show
NAME  UUID                                  TYPE      DEVICE  FILENAME
eth0  dfd202f5-562f-5f07-8f2a-a7717756fb70  ethernet  eth0    /etc/NetworkManager/system-connections/eth0.nmconnection
eth1  7e211aea-3d14-59cf-a4fa-be91dac5dbba  ethernet  --      /etc/NetworkManager/system-connections/eth1.nmconnection

您会发现,在所需网络状态中,第二个接口是 eth1,而不是预定义的 eth3。之所以出现这种情况,是因为 NetworkManager Configurator (nmc) 能够检测到操作系统为 MAC 地址为 34:8a:b1:4b:16:e2 的 NIC 指定了不同的名称,并相应地调整了其设置。

通过检查置备的 Combustion 阶段来校验是否确实发生了这种情况:

node1:~ # journalctl -u combustion | grep nmc
Apr 23 09:20:19 localhost.localdomain combustion[1360]: [2024-04-23T09:20:19Z INFO  nmc::apply_conf] Identified host: node1.suse.com
Apr 23 09:20:19 localhost.localdomain combustion[1360]: [2024-04-23T09:20:19Z INFO  nmc::apply_conf] Set hostname: node1.suse.com
Apr 23 09:20:19 localhost.localdomain combustion[1360]: [2024-04-23T09:20:19Z INFO  nmc::apply_conf] Processing interface 'eth0'...
Apr 23 09:20:19 localhost.localdomain combustion[1360]: [2024-04-23T09:20:19Z INFO  nmc::apply_conf] Processing interface 'eth3'...
Apr 23 09:20:19 localhost.localdomain combustion[1360]: [2024-04-23T09:20:19Z INFO  nmc::apply_conf] Using interface name 'eth1' instead of the preconfigured 'eth3'
Apr 23 09:20:19 localhost.localdomain combustion[1360]: [2024-04-23T09:20:19Z INFO  nmc] Successfully applied config

我们现在将置备其余节点,但只会显示最终配置中的差异。您可以随意对即将置备的所有节点应用上述任意检查或所有检查。

10.5.7.2 置备第二个节点

我们来创建虚拟机:

virt-install --name node2 --ram 10000 --vcpus 6 --disk path=node2.raw,format=raw --osinfo detect=on,name=sle-unknown --graphics none --console pty,target_type=serial --network default,mac=34:8A:B1:4B:16:E3 --network default,mac=34:8A:B1:4B:16:E4 --virt-type kvm --import

虚拟机启动并运行后,我们可以确认此节点是否正在使用绑定的接口:

node2:~ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond99 state UP group default qlen 1000
    link/ether 34:8a:b1:4b:16:e3 brd ff:ff:ff:ff:ff:ff
    altname enp0s2
    altname ens2
3: eth1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond99 state UP group default qlen 1000
    link/ether 34:8a:b1:4b:16:e3 brd ff:ff:ff:ff:ff:ff permaddr 34:8a:b1:4b:16:e4
    altname enp0s3
    altname ens3
4: bond99: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 34:8a:b1:4b:16:e3 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.60/24 brd 192.168.122.255 scope global noprefixroute bond99
       valid_lft forever preferred_lft forever

确认路由是否正在使用绑定:

node2:~ # ip r
default via 192.168.122.1 dev bond99 proto static metric 100
192.168.122.0/24 dev bond99 proto static scope link metric 100
192.168.122.0/24 dev bond99 proto kernel scope link src 192.168.122.60 metric 300

确保正确利用静态连接文件:

node2:~ # nmcli -f NAME,UUID,TYPE,DEVICE,FILENAME con show
NAME    UUID                                  TYPE      DEVICE  FILENAME
bond99  4a920503-4862-5505-80fd-4738d07f44c6  bond      bond99  /etc/NetworkManager/system-connections/bond99.nmconnection
eth0    dfd202f5-562f-5f07-8f2a-a7717756fb70  ethernet  eth0    /etc/NetworkManager/system-connections/eth0.nmconnection
eth1    0523c0a1-5f5e-5603-bcf2-68155d5d322e  ethernet  eth1    /etc/NetworkManager/system-connections/eth1.nmconnection

10.5.7.3 置备第三个节点

我们来创建虚拟机:

virt-install --name node3 --ram 10000 --vcpus 6 --disk path=node3.raw,format=raw --osinfo detect=on,name=sle-unknown --graphics none --console pty,target_type=serial --network default,mac=34:8A:B1:4B:16:E5 --virt-type kvm --import

虚拟机启动并运行后,我们可以确认此节点是否正在使用网桥:

node3:~ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master linux-br0 state UP group default qlen 1000
    link/ether 34:8a:b1:4b:16:e5 brd ff:ff:ff:ff:ff:ff
    altname enp0s2
    altname ens2
3: linux-br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 34:8a:b1:4b:16:e5 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.70/24 brd 192.168.122.255 scope global noprefixroute linux-br0
       valid_lft forever preferred_lft forever

确认路由是否正在使用网桥:

node3:~ # ip r
default via 192.168.122.1 dev linux-br0 proto static metric 100
192.168.122.0/24 dev linux-br0 proto static scope link metric 100
192.168.122.0/24 dev linux-br0 proto kernel scope link src 192.168.122.70 metric 425

确保正确利用静态连接文件:

node3:~ # nmcli -f NAME,UUID,TYPE,DEVICE,FILENAME con show
NAME       UUID                                  TYPE      DEVICE     FILENAME
linux-br0  1f8f1469-ed20-5f2c-bacb-a6767bee9bc0  bridge    linux-br0  /etc/NetworkManager/system-connections/linux-br0.nmconnection
eth0       dfd202f5-562f-5f07-8f2a-a7717756fb70  ethernet  eth0       /etc/NetworkManager/system-connections/eth0.nmconnection

10.5.7.4 置备第四个节点

最后,我们将置备 MAC 地址与任何预定义配置都不匹配的节点。在这种情况下,我们将默认使用 DHCP 来配置网络接口。

我们来创建虚拟机:

virt-install --name node4 --ram 10000 --vcpus 6 --disk path=node4.raw,format=raw --osinfo detect=on,name=sle-unknown --graphics none --console pty,target_type=serial --network default --virt-type kvm --import

虚拟机启动并运行后,我们可以确认此节点是否正在为其网络接口使用随机 IP 地址:

localhost:~ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:56:63:71 brd ff:ff:ff:ff:ff:ff
    altname enp0s2
    altname ens2
    inet 192.168.122.86/24 brd 192.168.122.255 scope global dynamic noprefixroute eth0
       valid_lft 3542sec preferred_lft 3542sec
    inet6 fe80::5054:ff:fe56:6371/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

校验 nmc 是否无法为此节点应用静态配置:

localhost:~ # journalctl -u combustion | grep nmc
Apr 23 12:15:45 localhost.localdomain combustion[1357]: [2024-04-23T12:15:45Z ERROR nmc] Applying config failed: None of the preconfigured hosts match local NICs

校验是否通过 DHCP 配置了以太网接口:

localhost:~ # journalctl | grep eth0
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7801] manager: (eth0): new Ethernet device (/org/freedesktop/NetworkManager/Devices/2)
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7802] device (eth0): state change: unmanaged -> unavailable (reason 'managed', sys-iface-state: 'external')
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7929] device (eth0): carrier: link connected
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7931] device (eth0): state change: unavailable -> disconnected (reason 'carrier-changed', sys-iface-state: 'managed')
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7944] device (eth0): Activation: starting connection 'Wired Connection' (300ed658-08d4-4281-9f8c-d1b8882d29b9)
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7945] device (eth0): state change: disconnected -> prepare (reason 'none', sys-iface-state: 'managed')
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7947] device (eth0): state change: prepare -> config (reason 'none', sys-iface-state: 'managed')
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7953] device (eth0): state change: config -> ip-config (reason 'none', sys-iface-state: 'managed')
Apr 23 12:15:29 localhost.localdomain NetworkManager[704]: <info>  [1713874529.7964] dhcp4 (eth0): activation: beginning transaction (timeout in 90 seconds)
Apr 23 12:15:33 localhost.localdomain NetworkManager[704]: <info>  [1713874533.1272] dhcp4 (eth0): state changed new lease, address=192.168.122.86

localhost:~ # nmcli -f NAME,UUID,TYPE,DEVICE,FILENAME con show
NAME              UUID                                  TYPE      DEVICE  FILENAME
Wired Connection  300ed658-08d4-4281-9f8c-d1b8882d29b9  ethernet  eth0    /var/run/NetworkManager/system-connections/default_connection.nmconnection

10.5.8 统一节点配置

有时我们无法依赖已知的 MAC 地址。在这种情况下,我们可以选择所谓的统一配置,这样就可以在 _all.yaml 文件中指定设置,然后将这些设置应用于所有已置备的节点。

我们将使用不同的配置结构来构建和置备边缘节点。请按照从第 10.5.3 节 “创建映像配置目录”第 10.5.5 节 “定义网络配置”的所有步骤进行操作。

在此示例中,我们将定义两个以太网接口(eth0 和 eth1)的所需状态 - 一个接口使用 DHCP,另一个接口使用静态 IP 地址。

mkdir -p $CONFIG_DIR/network

cat <<- EOF > $CONFIG_DIR/network/_all.yaml
interfaces:
- name: eth0
  type: ethernet
  state: up
  ipv4:
    dhcp: true
    enabled: true
  ipv6:
    enabled: false
- name: eth1
  type: ethernet
  state: up
  ipv4:
    address:
    - ip: 10.0.0.1
      prefix-length: 24
    enabled: true
    dhcp: false
  ipv6:
    enabled: false
EOF

我们来构建映像:

podman run --rm -it -v $CONFIG_DIR:/eib registry.suse.com/edge/edge-image-builder:1.0.2 build --definition-file definition.yaml

成功构建映像后,我们将使用它来创建虚拟机:

virt-install --name node1 --ram 10000 --vcpus 6 --disk path=$CONFIG_DIR/modified-image.raw,format=raw --osinfo detect=on,name=sle-unknown --graphics none --console pty,target_type=serial --network default --network default --virt-type kvm --import

置备过程可能需要几分钟时间。完成后,使用提供的身份凭证登录到系统。

校验是否正确配置了路由:

localhost:~ # ip r
default via 192.168.122.1 dev eth0 proto dhcp src 192.168.122.100 metric 100
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.1 metric 101
192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.100 metric 100

校验互联网连接是否可用:

localhost:~ # ping google.com
PING google.com (142.250.72.46) 56(84) bytes of data.
64 bytes from den16s08-in-f14.1e100.net (142.250.72.46): icmp_seq=1 ttl=56 time=14.3 ms
64 bytes from den16s08-in-f14.1e100.net (142.250.72.46): icmp_seq=2 ttl=56 time=14.2 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 14.196/14.260/14.324/0.064 ms

校验以太网接口是否已配置并处于活动状态:

localhost:~ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:26:44:7a brd ff:ff:ff:ff:ff:ff
    altname enp1s0
    inet 192.168.122.100/24 brd 192.168.122.255 scope global dynamic noprefixroute eth0
       valid_lft 3505sec preferred_lft 3505sec
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:ec:57:9e brd ff:ff:ff:ff:ff:ff
    altname enp7s0
    inet 10.0.0.1/24 brd 10.0.0.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever

localhost:~ # nmcli -f NAME,UUID,TYPE,DEVICE,FILENAME con show
NAME  UUID                                  TYPE      DEVICE  FILENAME
eth0  dfd202f5-562f-5f07-8f2a-a7717756fb70  ethernet  eth0    /etc/NetworkManager/system-connections/eth0.nmconnection
eth1  0523c0a1-5f5e-5603-bcf2-68155d5d322e  ethernet  eth1    /etc/NetworkManager/system-connections/eth1.nmconnection

localhost:~ # cat /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
autoconnect=true
autoconnect-slaves=-1
id=eth0
interface-name=eth0
type=802-3-ethernet
uuid=dfd202f5-562f-5f07-8f2a-a7717756fb70

[ipv4]
dhcp-client-id=mac
dhcp-send-hostname=true
dhcp-timeout=2147483647
ignore-auto-dns=false
ignore-auto-routes=false
method=auto
never-default=false

[ipv6]
addr-gen-mode=0
dhcp-timeout=2147483647
method=disabled

localhost:~ # cat /etc/NetworkManager/system-connections/eth1.nmconnection
[connection]
autoconnect=true
autoconnect-slaves=-1
id=eth1
interface-name=eth1
type=802-3-ethernet
uuid=0523c0a1-5f5e-5603-bcf2-68155d5d322e

[ipv4]
address0=10.0.0.1/24
dhcp-timeout=2147483647
method=manual

[ipv6]
addr-gen-mode=0
dhcp-timeout=2147483647
method=disabled

10.5.9 自定义网络配置

我们已介绍 Edge Image Builder 的依赖于 NetworkManager Configurator 的默认网络配置。但是,还可以选择通过自定义脚本来修改这种配置。虽然这种方法非常灵活而且不依赖于 MAC 地址,但它的局限性在于,在使用单个映像引导多个节点时,这种方法不太方便。

注意
注意

建议通过 /network 目录下描述所需网络状态的文件来使用默认网络配置。请仅在该行为不适用于您的用例时,才选择自定义脚本。

我们将使用不同的配置结构来构建和置备边缘节点。请按照从第 10.5.3 节 “创建映像配置目录”第 10.5.5 节 “定义网络配置”的所有步骤进行操作。

在此示例中,我们将创建一个自定义脚本来对所有已置备节点上的 eth0 接口应用静态配置,同时去除并禁用 NetworkManager 自动创建的有线连接。如果您想要确保群集中每个节点都采用相同的网络配置,则这种做法非常有利,这样,您就不需要在创建映像之前考虑每个节点的 MAC 地址。

首先,我们将连接文件存储在 /custom/files 目录中:

mkdir -p $CONFIG_DIR/custom/files

cat << EOF > $CONFIG_DIR/custom/files/eth0.nmconnection
[connection]
autoconnect=true
autoconnect-slaves=-1
autoconnect-retries=1
id=eth0
interface-name=eth0
type=802-3-ethernet
uuid=dfd202f5-562f-5f07-8f2a-a7717756fb70
wait-device-timeout=60000

[ipv4]
dhcp-timeout=2147483647
method=auto

[ipv6]
addr-gen-mode=eui64
dhcp-timeout=2147483647
method=disabled
EOF

创建静态配置后,我们再创建自定义网络脚本:

mkdir -p $CONFIG_DIR/network

cat << EOF > $CONFIG_DIR/network/configure-network.sh
#!/bin/bash
set -eux

# Remove and disable wired connections
mkdir -p /etc/NetworkManager/conf.d/
printf "[main]\nno-auto-default=*\n" > /etc/NetworkManager/conf.d/no-auto-default.conf
rm -f /var/run/NetworkManager/system-connections/* || true

# Copy pre-configured network configuration files into NetworkManager
mkdir -p /etc/NetworkManager/system-connections/
cp eth0.nmconnection /etc/NetworkManager/system-connections/
chmod 600 /etc/NetworkManager/system-connections/*.nmconnection
EOF

chmod a+x $CONFIG_DIR/network/configure-network.sh
注意
注意

默认情况下仍会包含 nmc 二进制文件,因此如果需要,也可以在 configure-network.sh 脚本中使用它。

警告
警告

必须始终在配置目录中的 /network/configure-network.sh 下提供自定义脚本。将忽略存在的所有其他文件。无法同时使用 YAML 格式的静态配置和自定义脚本来配置网络。

此时,配置目录应如下所示:

├── definition.yaml
├── custom/
│   └── files/
│       └── eth0.nmconnection
├── network/
│   └── configure-network.sh
└── base-images/
    └── SLE-Micro.x86_64-5.5.0-Default-GM.raw

我们来构建映像:

podman run --rm -it -v $CONFIG_DIR:/eib registry.suse.com/edge/edge-image-builder:1.0.2 build --definition-file definition.yaml

成功构建映像后,我们将使用它来创建虚拟机:

virt-install --name node1 --ram 10000 --vcpus 6 --disk path=$CONFIG_DIR/modified-image.raw,format=raw --osinfo detect=on,name=sle-unknown --graphics none --console pty,target_type=serial --network default --virt-type kvm --import

置备过程可能需要几分钟时间。完成后,使用提供的身份凭证登录到系统。

校验是否正确配置了路由:

localhost:~ # ip r
default via 192.168.122.1 dev eth0 proto dhcp src 192.168.122.185 metric 100
192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.185 metric 100

校验互联网连接是否可用:

localhost:~ # ping google.com
PING google.com (142.250.72.78) 56(84) bytes of data.
64 bytes from den16s09-in-f14.1e100.net (142.250.72.78): icmp_seq=1 ttl=56 time=13.6 ms
64 bytes from den16s09-in-f14.1e100.net (142.250.72.78): icmp_seq=2 ttl=56 time=13.6 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 13.592/13.599/13.606/0.007 ms

校验是否使用连接文件静态配置了以太网接口,并且该接口处于活动状态:

localhost:~ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:31:d0:1b brd ff:ff:ff:ff:ff:ff
    altname enp0s2
    altname ens2
    inet 192.168.122.185/24 brd 192.168.122.255 scope global dynamic noprefixroute eth0

localhost:~ # nmcli -f NAME,UUID,TYPE,DEVICE,FILENAME con show
NAME  UUID                                  TYPE      DEVICE  FILENAME
eth0  dfd202f5-562f-5f07-8f2a-a7717756fb70  ethernet  eth0    /etc/NetworkManager/system-connections/eth0.nmconnection

localhost:~ # cat  /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
autoconnect=true
autoconnect-slaves=-1
autoconnect-retries=1
id=eth0
interface-name=eth0
type=802-3-ethernet
uuid=dfd202f5-562f-5f07-8f2a-a7717756fb70
wait-device-timeout=60000

[ipv4]
dhcp-timeout=2147483647
method=auto

[ipv6]
addr-gen-mode=eui64
dhcp-timeout=2147483647
method=disabled

11 Elemental

Elemental 是一个软件堆栈,可用于通过 Kubernetes 实现集中式云原生操作系统全面管理。Elemental 堆栈由驻留在 Rancher 本身或边缘节点上的许多组件构成。核心组件包括:

  • elemental-operator - 驻留在 Rancher 上的核心操作器,用于处理来自客户端的注册请求。

  • elemental-register - 在边缘节点上运行的客户端,支持通过 elemental-operator 进行注册。

  • elemental-system-agent - 驻留在边缘节点上的代理;其配置由 elemental-register 馈送,接收用于配置 rancher-system-agent计划

  • rancher-system-agent - 完全注册边缘节点后,此组件将接管 elemental-system-agent,并等待 Rancher Manager 接下来的计划(例如 Kubernetes 安装)。

有关 Elemental 及其与 Rancher 的关系的完整信息,请参见 Elemental 上游文档

11.1 SUSE Edge 如何使用 Elemental?

我们将使用 Elemental 的部分功能来管理无法使用 Metal3 的远程设备(例如,没有 BMC 的设备,或者设备位于 NAT 网关后面)。在知道设备何时运送或运送到何处之前,操作员可以使用此工具在实验室中引导其设备。也就是说,我们利用 elemental-registerelemental-system-agent 组件将 SLE Micro 主机初始配置到 Rancher,以支持“电告总部”网络置备用例。使用 Edge Image Builder (EIB) 创建部署映像时,可以通过在 EIB 的配置目录中指定注册配置,来使用 Elemental 通过 Rancher 完成自动注册。

注意
注意

在 SUSE Edge 3.0 中,我们不会利用 Elemental 的操作系统管理功能,因此无法通过 Rancher 管理操作系统修补。SUSE Edge 不会使用 Elemental 工具来构建部署映像,而是使用 Edge Image Builder 工具,而后者利用注册配置。

11.2 最佳实践

11.2.1 安装媒体

SUSE Edge 建议的、可以在“电告总部网络置备”部署空间中利用 Elemental 注册到 Rancher 的部署映像构建方法是,遵循有关使用 Elemental 进行远程主机初始配置(第 2 章 “使用 Elemental 进行远程主机初始配置)快速入门中详述的说明。

11.2.2 标签

Elemental 使用 MachineInventory CRD 跟踪其清单,并提供选择清单的方法,例如,根据标签选择要将 Kubernetes 群集部署到的计算机。这样,用户就可以在购买硬件之前,预定义其大部分(甚至所有)基础架构需求。另外,由于节点可以在其相应清单对象上添加/去除标签(结合附加标志 --label "FOO=BAR" 重新运行 elemental-register),我们可以编写脚本来发现节点的引导位置并告诉 Rancher。

11.3 已知问题

  • Elemental UI 目前不知道如何构建安装媒体或更新非“Elemental Teal”操作系统。此问题在将来的版本中应会得到解决。

12 Akri

Akri 是一个 CNCF 沙箱项目,旨在发现叶设备并将其呈现为 Kubernetes 原生资源。它还允许为每个发现的设备调度一个 Pod 或作业。设备可以在节点本地,也可以联网,并可以使用多种协议。

https://docs.akri.sh 上提供了 Akri 的上游文档

12.1 SUSE Edge 如何使用 Akri?

警告
警告

Akri 目前在 SUSE Edge 堆栈中以技术预览的形式提供。

每当需要发现叶设备以及针对叶设备调度工作负载时,都可以使用 Edge 堆栈中包含的 Akri。

12.1.1 安装 Akri

Akri 在 Edge Helm 储存库中作为 Helm chart 提供。建议的 Akri 配置方法是使用给定的 Helm chart 部署不同的组件(代理、控制器、发现处理程序),然后使用您偏好的部署机制部署 Akri 的配置 CRD。

12.1.2 配置 Akri

使用 akri.sh/Configuration 对象来配置 Akri,该对象包含有关如何发现设备,以及发现了匹配的设备时要执行哪种操作的所有信息。

下面列出了示例配置的明细,其中解释了所有字段:

apiVersion: akri.sh/v0
kind: Configuration
metadata:
  name: sample-configuration
spec:

此部分描述发现处理程序的配置,您必须指定处理程序的名称(作为 Akri chart 一部分提供的处理程序包括 udevopcuaonvif)。discoveryDetails 与特定的处理程序相关,有关其配置方法,请参见处理程序的文档。

  discoveryHandler:
    name: debugEcho
    discoveryDetails: |+
      descriptions:
        - "foo"
        - "bar"

此部分定义要为每个已发现设备部署的工作负载。该示例显示了 brokerPodSpecPod 配置的最低版本,在此处可以使用 Pod 规范的所有常规字段。其中还显示了 resources 部分中用于请求设备的 Akri 特定语法。

您也可以使用作业来代替 Pod,方法是改用 brokerJobSpec 键,并在其中提供作业的规范部分。

  brokerSpec:
    brokerPodSpec:
      containers:
      - name: broker-container
        image: rancher/hello-world
        resources:
          requests:
            "{{PLACEHOLDER}}" : "1"
          limits:
            "{{PLACEHOLDER}}" : "1"

这两个部分显示如何配置 Akri 以便为每个中介程序部署一个服务 (instanceService),或指向所有中介程序 (configurationService)。这些部分包含与常规服务相关的所有元素。

  instanceServiceSpec:
    type: ClusterIp
    ports:
    - name: http
      port: 80
      protocol: tcp
      targetPort: 80
  configurationServiceSpec:
    type: ClusterIp
    ports:
    - name: https
      port: 443
      protocol: tcp
      targetPort: 443

brokerProperties 字段是一个键/值存储,它将作为附加环境变量公开给请求已发现设备的任何 Pod。

capacity 是已发现设备的并发用户的允许数量。

  brokerProperties:
    key: value
  capacity: 1

12.1.3 编写和部署更多发现处理程序

如果现有的发现处理程序无法涵盖您的设备使用的协议,您可以遵循此指南编写自己的发现处理程序。

12.1.4 Akri Rancher 仪表板扩展

Akri 仪表板扩展允许您使用 Rancher 仪表板用户界面来管理和监控叶设备,并在发现这些设备后运行工作负载。

安装扩展后,您可以使用群集资源管理器导航到任何已启用 Akri 的受管群集。在 Akri 导航组下,可以看到“Configurations”(配置)和“Instances”(实例)部分。

Akri 扩展配置

配置列表提供了有关配置发现处理程序和实例数量的信息。单击名称会打开配置细节页面。

Akri 扩展配置细节

您还可以编辑或创建新的配置。扩展允许您选择发现处理程序、设置中介程序 Pod 或作业、配置配置和实例服务,以及设置配置容量。

Akri 扩展配置编辑

实例列表中会列出已发现的设备。

Akri 扩展实例列表

单击实例名称会打开细节页面,在其中可以查看工作负载和实例服务。

Akri 扩展实例细节

13 K3s

K3s 是高度可用的、经过认证的 Kubernetes 发行版,专为无人照管、资源受限的远程位置或物联网设备内的生产工作负载而设计。

它打包为单个较小二进制文件,因此可以快速轻松地安装和更新。

13.1 SUSE Edge 如何使用 K3s

K3s 可用作支持 SUSE Edge 堆栈的 Kubernetes 发行版。它适合安装在 SLE Micro 操作系统上。

仅当用作后端的 etcd 不能满足您的约束条件时,才建议使用 K3s 作为 SUSE Edge 堆栈 Kubernetes 发行版。如果 etcd 可用作后端,则最好使用 RKE2(第 14 章 “RKE2)。

13.2 最佳实践

13.2.1 安装

将 K3s 安装为 SUSE Edge 堆栈一部分的建议方法是使用 Edge Image Builder (EIB)。有关如何配置 EIB 来部署 K3s 的更多细节,请参见其文档(第 9 章 “Edge Image Builder)。

K3s 原生支持 HA 设置以及 Elemental 设置。

13.2.2 用于 GitOps 工作流程的 Fleet

SUSE Edge 堆栈使用 Fleet 作为其首选 GitOps 工具。有关 Fleet 安装和用法的详细信息,请参见本文档中的“Fleet”一章(第 6 章 “Fleet)。

13.2.3 存储管理

K3s 预配置了本地路径存储,这种存储适用于单节点群集。对于跨多个节点的群集,我们建议使用 Longhorn(第 15 章 “Longhorn)。

13.2.4 负载平衡和 HA

如果您使用 EIB 安装了 K3s,请参见 EIB 文档中的“HA”一章,其中已介绍本节所述的内容。

否则,您需要按照 MetalLB 文档(第 19 章 “K3s 上的 MetalLB(使用 L2))安装和配置 MetalLB。

14 RKE2

请参见 RKE2 官方文档

RKE2 是注重安全性与合规性的完全符合规范的 Kubernetes 发行版,因为它可以:

  • 提供默认设置和配置选项,使群集能够在操作员极少干预的情况下通过 CIS Kubernetes 基准 v1.6 或 v1.23

  • 实现 FIPS 140-2 合规

  • 在 RKE2 构建管道中使用 trivy 定期扫描组件中存在的 CVE

RKE2 将控制平面组件作为 kubelet 管理的静态 Pod 进行启动。嵌入式容器运行时为 containerd。

注意:RKE2 也称为 RKE 政府版,表示它目前面向另一种用例和市场领域。

14.1 RKE2 与 K3s 的比较

K3s 是完全合规的轻量级 Kubernetes 发行版,主要用于 Edge、IoT 和 ARM,在无法精通 K8s 群集学的情况下也可以使用它。

RKE2 结合了 1.x 版 RKE(后文称为 RKE1)和 K3s 的最大优点。

它承袭了 K3s 的易用性、易操作性和部署模型。

它承袭了 RKE1 与上游 Kubernetes 的紧密一致性。在某些地方,K3s 与上游 Kubernetes 有所不同,目的是针对边缘部署进行优化,但 RKE1 和 RKE2 可以与上游保持紧密一致性。

14.2 SUSE Edge 如何使用 RKE2?

RKE2 是 SUSE Edge 堆栈的根本性组成部分。它位于 SUSE Linux Micro(第 7 章 “SLE Micro)的顶层,提供部署 Edge 工作负载所需的标准 Kubernetes 接口,且占用的空间极小。

14.3 最佳实践

14.3.1 安装

将 RKE2 安装为 SUSE Edge 堆栈一部分的建议方法是使用 Edge Image Builder (EIB)。有关如何配置 EIB 来部署 RKE2 的更多细节,请参见 EIB 文档(第 9 章 “Edge Image Builder)。

EIB 足够灵活,支持 RKE2 所需的任何参数(例如指定 RKE2 版本、服务器代理配置),涵盖所有 Edge 用例。

对于涉及 Metal3 的其他用例,也可以使用和安装 RKE2。在这种特殊情况下,群集 API 提供程序 RKE2 会自动在使用 Edge Stack 通过 Metal3 置备的群集上部署 RKE2。

在这种情况下,必须在涉及的不同 CRD 上应用 RKE2 配置。以下示例说明如何使用 RKE2ControlPlane CRD 提供不同的 CNI:

apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: RKE2ControlPlane
metadata:
  name: single-node-cluster
  namespace: default
spec:
  serverConfig:
    cni: calico
    cniMultusEnable: true
...

有关 Metal3 用例的详细信息,请参见第 8 章 “Metal3

14.3.2 高可用性

对于 HA 部署,EIB 会自动部署并配置 MetalLB(第 17 章 “MetalLB)和 Endpoint Copier Operator,以向外部公开 RKE2 API 端点。

14.3.3 网络

Edge Stack 支持的 CNI 为 Cilium,您可选择性地添加元插件 Multus,但 RKE2 也支持其他几个插件

14.3.4 存储

RKE2 不提供任何类型的永久存储类或操作器。对于跨多个节点的群集,建议使用 Longhorn(第 15 章 “Longhorn)。

15 Longhorn

Longhorn 是专为 Kubernetes 设计的可靠且用户友好的轻量级分布式块存储系统。作为一个开源项目,Longhorn 最初由 Rancher Labs 开发,目前正在由 CNCF 孵化。

15.1 先决条件

如果您要学习本指南,事先需要做好以下准备:

  • 至少一台装有 SLE Micro 5.5 的主机,可以是物理主机,也可以是虚拟主机

  • 已安装一个 Kubernetes 群集,可以是 K3s 或 RKE2

  • Helm

15.2 手动安装 Longhorn

15.2.1 安装 Open-iSCSI

要部署并使用 Longhorn,需满足的一项核心要求是安装 open-iscsi 软件包并在所有 Kubernetes 节点上运行 iscsid 守护程序。之所以有此要求,是因为 Longhorn 依赖于主机上的 iscsiadm 来为 Kubernetes 提供永久卷。

我们来安装此软件包:

transactional-update pkg install open-iscsi

请务必注意,在操作完成后,该软件包只会安装到新快照中,因为 SLE Micro 是不可变的操作系统。要加载该软件包并让 iscsid 守护程序开始运行,我们必须重引导至刚刚创建的新快照。准备就绪后,发出 reboot 命令:

reboot
提示
提示

在安装 open-iscsi 时如需更多帮助,请参见官方 Longhorn 文档

15.2.2 安装 Longhorn

可通过多种方式在 Kubernetes 群集上安装 Longhorn。本指南将介绍如何通过 Helm 安装,但如果您想要采用其他方法,请按照官方文档操作。

  1. 添加 Longhorn Helm 储存库:

    helm repo add longhorn https://charts.longhorn.io
  2. 从储存库提取最新的 chart:

    helm repo update
  3. 在 longhorn-system 名称空间中安装 Longhorn:

    helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace --version 1.6.1
  4. 确认部署是否成功:

    kubectl -n longhorn-system get pods
    localhost:~ # kubectl -n longhorn-system get pod
    NAMESPACE         NAME                                                READY   STATUS      RESTARTS        AGE
    longhorn-system   longhorn-ui-5fc9fb76db-z5dc9                        1/1     Running     0               90s
    longhorn-system   longhorn-ui-5fc9fb76db-dcb65                        1/1     Running     0               90s
    longhorn-system   longhorn-manager-wts2v                              1/1     Running     1 (77s ago)     90s
    longhorn-system   longhorn-driver-deployer-5d4f79ddd-fxgcs            1/1     Running     0               90s
    longhorn-system   instance-manager-a9bf65a7808a1acd6616bcd4c03d925b   1/1     Running     0               70s
    longhorn-system   engine-image-ei-acb7590c-htqmp                      1/1     Running     0               70s
    longhorn-system   csi-attacher-5c4bfdcf59-j8xww                       1/1     Running     0               50s
    longhorn-system   csi-provisioner-667796df57-l69vh                    1/1     Running     0               50s
    longhorn-system   csi-attacher-5c4bfdcf59-xgd5z                       1/1     Running     0               50s
    longhorn-system   csi-provisioner-667796df57-dqkfr                    1/1     Running     0               50s
    longhorn-system   csi-attacher-5c4bfdcf59-wckt8                       1/1     Running     0               50s
    longhorn-system   csi-resizer-694f8f5f64-7n2kq                        1/1     Running     0               50s
    longhorn-system   csi-snapshotter-959b69d4b-rp4gk                     1/1     Running     0               50s
    longhorn-system   csi-resizer-694f8f5f64-r6ljc                        1/1     Running     0               50s
    longhorn-system   csi-resizer-694f8f5f64-k7429                        1/1     Running     0               50s
    longhorn-system   csi-snapshotter-959b69d4b-5k8pg                     1/1     Running     0               50s
    longhorn-system   csi-provisioner-667796df57-n5w9s                    1/1     Running     0               50s
    longhorn-system   csi-snapshotter-959b69d4b-x7b7t                     1/1     Running     0               50s
    longhorn-system   longhorn-csi-plugin-bsc8c                           3/3     Running     0               50s

15.3 创建 Longhorn 卷

Longhorn 利用名为 StorageClass 的 Kubernetes 资源来自动为 Pod 置备 PersistentVolume 对象。可以将 StorageClass 视为管理员描述其提供的存储配置文件的一种方式。

我们需要创建一个采用默认选项的 StorageClass

kubectl apply -f - <<EOF
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: longhorn-example
provisioner: driver.longhorn.io
allowVolumeExpansion: true
parameters:
  numberOfReplicas: "3"
  staleReplicaTimeout: "2880" # 48 hours in minutes
  fromBackup: ""
  fsType: "ext4"
EOF

创建 StorageClass 后,我们需要提供一个 PersistentVolumeClaim 来引用它。PersistentVolumeClaim (PVC) 是用户发出的存储请求。PVC 使用 PersistentVolume 资源。声明可以请求特定的大小和访问模式(例如,可以以读/写模式挂载声明一次,或以只读模式挂载声明多次)。

我们来创建 PersistentVolumeClaim

kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: longhorn-volv-pvc
  namespace: longhorn-system
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn-example
  resources:
    requests:
      storage: 2Gi
EOF

大功告成!创建 PersistentVolumeClaim 后,我们可以继续将其挂接到 Pod。部署 Pod 时,如果有可用存储,Kubernetes 会创建 Longhorn 卷并将其绑定到 Pod

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: volume-test
  namespace: longhorn-system
spec:
  containers:
  - name: volume-test
    image: nginx:stable-alpine
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: volv
      mountPath: /data
    ports:
    - containerPort: 80
  volumes:
  - name: volv
    persistentVolumeClaim:
      claimName: longhorn-volv-pvc
EOF
提示
提示

Kubernetes 中的存储概念是一个复杂但又重要的主题。我们简单地提及了一些最常见的 Kubernetes 资源,不过建议您熟悉 Longhorn 提供的术语文档

对于此示例,结果应如下所示:

localhost:~ # kubectl get storageclass
NAME                 PROVISIONER          RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
longhorn (default)   driver.longhorn.io   Delete          Immediate           true                   12m
longhorn-example     driver.longhorn.io   Delete          Immediate           true                   24s

localhost:~ # kubectl get pvc -n longhorn-system
NAME                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       AGE
longhorn-volv-pvc   Bound    pvc-f663a92e-ac32-49ae-b8e5-8a6cc29a7d1e   2Gi        RWO            longhorn-example   54s

localhost:~ # kubectl get pods -n longhorn-system
NAME                                                READY   STATUS    RESTARTS      AGE
csi-attacher-5c4bfdcf59-qmjtz                       1/1     Running   0             14m
csi-attacher-5c4bfdcf59-s7n65                       1/1     Running   0             14m
csi-attacher-5c4bfdcf59-w9xgs                       1/1     Running   0             14m
csi-provisioner-667796df57-fmz2d                    1/1     Running   0             14m
csi-provisioner-667796df57-p7rjr                    1/1     Running   0             14m
csi-provisioner-667796df57-w9fdq                    1/1     Running   0             14m
csi-resizer-694f8f5f64-2rb8v                        1/1     Running   0             14m
csi-resizer-694f8f5f64-z9v9x                        1/1     Running   0             14m
csi-resizer-694f8f5f64-zlncz                        1/1     Running   0             14m
csi-snapshotter-959b69d4b-5dpvj                     1/1     Running   0             14m
csi-snapshotter-959b69d4b-lwwkv                     1/1     Running   0             14m
csi-snapshotter-959b69d4b-tzhwc                     1/1     Running   0             14m
engine-image-ei-5cefaf2b-hvdv5                      1/1     Running   0             14m
instance-manager-0ee452a2e9583753e35ad00602250c5b   1/1     Running   0             14m
longhorn-csi-plugin-gd2jx                           3/3     Running   0             14m
longhorn-driver-deployer-9f4fc86-j6h2b              1/1     Running   0             15m
longhorn-manager-z4lnl                              1/1     Running   0             15m
longhorn-ui-5f4b7bbf69-bln7h                        1/1     Running   3 (14m ago)   15m
longhorn-ui-5f4b7bbf69-lh97n                        1/1     Running   3 (14m ago)   15m
volume-test                                         1/1     Running   0             26s

15.4 访问 UI

如果您使用 kubectl 或 Helm 安装了 Longhorn,则需要设置入口控制器,使外部流量能够进入群集。默认不会启用身份验证。如果使用了 Rancher 目录应用程序,Rancher 已自动创建一个提供访问控制的入口控制器 (rancher-proxy)。

  1. 获取 Longhorn 的外部服务 IP 地址:

    kubectl -n longhorn-system get svc
  2. 检索到 longhorn-frontend IP 地址后,您可以通过在浏览器中导航到该前端来开始使用 UI。

15.5 使用 Edge Image Builder 进行安装

SUSE Edge 使用第 9 章 “Edge Image Builder来自定义基础 SLE Micro 操作系统映像。本节将演示如何执行自定义操作,以置备 RKE2 群集并在其上安装 Longhorn。

我们来创建定义文件:

export CONFIG_DIR=$HOME/eib
mkdir -p $CONFIG_DIR

cat << EOF > $CONFIG_DIR/iso-definition.yaml
apiVersion: 1.0
image:
  imageType: iso
  baseImage: SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso
  arch: x86_64
  outputImageName: eib-image.iso
kubernetes:
  version: v1.28.9+rke2r1
  helm:
    charts:
      - name: longhorn
        version: 1.6.1
        repositoryName: longhorn
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
    repositories:
      - name: longhorn
        url: https://charts.longhorn.io
operatingSystem:
  packages:
    sccRegistrationCode: <reg-code>
    packageList:
      - open-iscsi
  users:
  - username: root
    encryptedPassword: \$6\$jHugJNNd3HElGsUZ\$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
EOF
注意
注意

可以通过 helm.charts[].valuesFile 下提供的独立文件自定义任何 Helm chart 值。有关细节,请参见上游文档

我们来构建映像:

podman run --rm --privileged -it -v $CONFIG_DIR:/eib registry.suse.com/edge/edge-image-builder:1.0.2 build --definition-file $CONFIG_DIR/iso-definition.yaml

构建映像后,可以使用它在物理主机或虚拟主机上安装操作系统。置备完成后,可以使用 root:eib 身份凭证对登录到系统。

确保 Longhorn 已成功部署:

localhost:~ # /var/lib/rancher/rke2/bin/kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml -n longhorn-system get pods
NAME                                                READY   STATUS    RESTARTS        AGE
csi-attacher-5c4bfdcf59-qmjtz                       1/1     Running   0               103s
csi-attacher-5c4bfdcf59-s7n65                       1/1     Running   0               103s
csi-attacher-5c4bfdcf59-w9xgs                       1/1     Running   0               103s
csi-provisioner-667796df57-fmz2d                    1/1     Running   0               103s
csi-provisioner-667796df57-p7rjr                    1/1     Running   0               103s
csi-provisioner-667796df57-w9fdq                    1/1     Running   0               103s
csi-resizer-694f8f5f64-2rb8v                        1/1     Running   0               103s
csi-resizer-694f8f5f64-z9v9x                        1/1     Running   0               103s
csi-resizer-694f8f5f64-zlncz                        1/1     Running   0               103s
csi-snapshotter-959b69d4b-5dpvj                     1/1     Running   0               103s
csi-snapshotter-959b69d4b-lwwkv                     1/1     Running   0               103s
csi-snapshotter-959b69d4b-tzhwc                     1/1     Running   0               103s
engine-image-ei-5cefaf2b-hvdv5                      1/1     Running   0               109s
instance-manager-0ee452a2e9583753e35ad00602250c5b   1/1     Running   0               109s
longhorn-csi-plugin-gd2jx                           3/3     Running   0               103s
longhorn-driver-deployer-9f4fc86-j6h2b              1/1     Running   0               2m28s
longhorn-manager-z4lnl                              1/1     Running   0               2m28s
longhorn-ui-5f4b7bbf69-bln7h                        1/1     Running   3 (2m7s ago)    2m28s
longhorn-ui-5f4b7bbf69-lh97n                        1/1     Running   3 (2m10s ago)   2m28s
注意
注意

此安装不适用于完全隔离的环境。对于这种情况,请参见第 21.8 节 “Longhorn 安装”

16 NeuVector

NeuVector 是适用于 Kubernetes 的安全解决方案,它在统一的软件包中提供 L7 网络安全性、运行时安全性、供应链安全性与合规性检查。

NeuVector 部署为由多个容器组成的平台,这些容器通过各种端口和接口相互通讯。部署的各种容器如下:

  • 管理器:提供基于 Web 的控制台的无状态容器。通常只需一个,可在任何位置运行。管理器发生故障不会影响控制器或执行器的任何操作。但是,某些通知(事件)和最近的连接数据将由管理器缓存在内存中,因此查看这些信息会受到影响。

  • 控制器:NeuVector 的“控制平面”必须部署在 HA 配置中,这样,配置就不会在节点发生故障时丢失。这些容器可在任何位置运行,不过,由于它们的重要性,客户通常会将它们放在“管理”节点、主节点或基础架构节点上。

  • 执行器:此容器部署为 DaemonSet,因此每个要保护的节点上都有一个执行器。通常会部署到每个工作节点,但可为主节点和基础架构节点启用调度,以便将这些容器同时部署到这些节点。注意:如果执行器不在群集节点上,并且连接来自该节点上的 Pod,则 NeuVector 会将这些容器标记为“不受管”工作负载。

  • 扫描器:根据控制器的指示,使用内置 CVE 数据库执行漏洞扫描。可以部署多个扫描器来提高扫描能力。扫描器可在任何位置运行,但通常在运行控制器的节点上运行。请参见下文了解扫描器节点的大小调整注意事项。在用于构建阶段的扫描时,还可以独立调用扫描器,例如,在触发扫描、检索结果和停止扫描器的管道中。扫描器包含最新的 CVE 数据库,因此应每日更新。

  • 更新器:需要更新 CVE 数据库时,更新器会通过 Kubernetes cron 作业触发扫描器的更新。请务必根据您的环境配置此设置。

此处可以找到更深入的 NeuVector 初始配置信息和最佳实践文档。

16.1 SUSE Edge 如何使用 NeuVector?

SUSE Edge 提供了精简的 NeuVector 配置作为边缘部署的着手点。

此处可到找到 NeuVector 配置更改。

16.2 重要注意事项

  • 扫描器容器必须有足够的内存,以便能够将要扫描的映像提取到内存并对其进行扩展。要扫描 1 GB 以上的映像,请将扫描器的内存增加至略高于最大预期映像大小。

  • 在保护模式下需要高速网络连接。处于保护(内联防火墙阻止)模式的执行器需要占用 CPU 和内存来保持和检查连接以及可能的有效负载 (DLP)。增加内存并专门分配一个 CPU 核心供执行器使用可确保拥有足够的包过滤能力。

16.3 使用 Edge Image Builder 进行安装

SUSE Edge 使用第 9 章 “Edge Image Builder来自定义基础 SLE Micro 操作系统映像。请按照第 21.7 节 “NeuVector 安装”中所述,在 EIB 置备的 Kubernetes 群集上进行 NeuVector 隔离式安装。

17 MetalLB

请参见 MetalLB 官方文档

MetalLB 是使用标准路由协议的裸机 Kubernetes 群集的负载平衡器实现。

在裸机环境中,设置网络负载平衡器比在云环境中要复杂得多。与云设置中的直接 API 调用不同,裸机需要通过专用网络设备或者负载平衡器和虚拟 IP (VIP) 配置的组合,来管理高可用性 (HA) 或解决单节点负载平衡器固有的潜在单一故障点 (SPOF)。这些配置不容易自动化,在组件会动态扩展和缩减的 Kubernetes 部署中带来了挑战。

MetalLB 可以解决这些挑战,因为它利用 Kubernetes 模型创建 LoadBalancer 类型的服务,就如同这些服务是在云环境中运行一样,即使在裸机设置中,也能做到这一点。

为此可以采用两种不同的方法:通过 L2 模式(使用 ARP 技巧)或通过 BGP。大体而言,L2 不需要任何特殊网络设备,但 BGP 通常效果更好。使用哪种方法取决于用例。

17.1 SUSE Edge 如何使用 MetalLB?

SUSE Edge 通过两种主要方式使用 MetalLB:

  • 作为负载平衡器解决方案:MetalLB 充当裸机的负载平衡器解决方案。

  • 对于 HA K3s/RKE2 设置:MetalLB 允许使用虚拟 IP 地址对 Kubernetes API 进行负载平衡。

注意
注意

为了能够公开 API,会使用 endpoint-copier-operator 将 K8s API 端点从“kubernetes”服务同步到“kubernetes-vip”LoadBalancer 服务。

17.2 最佳实践

MetalLB 指南(第 19 章 “K3s 上的 MetalLB(使用 L2))中详细介绍了 L2 模式的 MetalLB 安装。

有关在 kube-api-server 前面安装 MetalLB 以实现 HA 设置的指南,请参见“Kubernetes API 服务器前面的 MetalLB”(第 20 章 “Kubernetes API 服务器前面的 MetalLB)教程。

17.3 已知问题

  • K3S 负载平衡器解决方案:K3S 附带负载平衡器解决方案 Klipper。要使用 MetalLB,必须禁用 Klipper。为此,可以按照 K3s 文档中所述,使用 --disable servicelb 选项启动 K3s 服务器。

18 边缘虚拟化

本章介绍如何使用边缘虚拟化在边缘节点上运行虚拟机。必须指出的是,边缘虚拟化并非全面的解决方案,其功能有限;它会尝试解决需要基本虚拟机功能的轻量级虚拟化的要求。SUSE 通过 Harvester 提供更全面的虚拟化(和超融合基础架构)解决方案。

SUSE 边缘虚拟化支持两种虚拟机运行方法:

  1. 在主机级别通过 libvirt+qemu-kvm 手动部署虚拟机

  2. 部署 KubeVirt 操作器来实现基于 Kubernetes 的虚拟机管理

这两种方法都有效,但下面仅介绍第二种方法。如果您要使用 SLE Micro 现成提供的标准虚拟化机制,可在此处找到详细的指南,尽管该指南主要是针对 SUSE Linux Enterprise Server 编写的,但概念几乎相同。

本指南首先介绍如何将其他虚拟化组件部署到已预先部署的系统,然后使用一个章节介绍如何通过 Edge Image Builder 将此配置嵌入到初始部署中。如果您不想了解基础知识并想要手动完成设置,请直接跳到该章节。

18.1 KubeVirt 概述

KubeVirt 让您可以通过 Kubernetes 管理虚拟机及其他容器化工作负载。它通过在容器中运行 Linux 虚拟化堆栈的用户空间部分来实现此目的。这样可以最大程度地降低对主机系统的要求,从而简化设置和管理。

有关 KubeVirt 体系结构的细节,请参见上游文档

18.2 先决条件

如果您要学习本指南,事先需要做好以下准备:

  • 至少有一台装有 SLE Micro 5.5+ 的物理主机,并且在 BIOS 中启用了虚拟化扩展(有关细节,请参见此处)。

  • 已在您的节点中部署了 K3s/RKE2 Kubernetes 群集,并提供了相应的 kubeconfig,使超级用户能够访问该群集。

  • root 用户访问权限 — 本章中的说明假设您是 root 用户,而不是通过 sudo 提升了的特权。

  • 已在本地安装 Helm 并建立了速度够快的网络连接,以便可以将配置推送到 Kubernetes 群集和下载所需的映像。

18.3 手动安装边缘虚拟化

本指南不会指导您完成 Kubernetes 的部署过程,而是假设您已安装适用于 SUSE Edge 的 K3sRKE2 版本,并已相应地配置了 kubeconfig,以便能够以超级用户身份执行标准的 kubectl 命令。假设您的节点构成单节点群集,不过,此过程与多节点部署预期不会有太大的差异。

具体而言,将通过以下三个独立的 Helm chart 来部署 SUSE 边缘虚拟化:

  • KubeVirt:核心虚拟化组件,即 Kubernetes CRD、操作器,以及使 Kubernetes 能够部署和管理虚拟机的其他组件。

  • KubeVirt 仪表板扩展:可选的 Rancher UI 扩展,用于实现基本的虚拟机管理,例如启动/停止虚拟机以及访问控制台。

  • Containerized Data Importer (CDI):一个附加组件,可为 KubeVirt 实现永久存储集成,使虚拟机能够使用现有 Kubernetes 存储后端来存储数据,同时使用户能够导入或克隆虚拟机的数据卷。

其中的每个 Helm chart 将根据您当前使用的 SUSE Edge 版本进行版本控制。对于生产/支持的用途,请采用 SUSE 注册表中提供的项目。

首先,请确保可以正常进行 kubectl 访问:

$ kubectl get nodes

此命令应会显示如下所示的输出:

NAME                   STATUS   ROLES                       AGE     VERSION
node1.edge.rdo.wales   Ready    control-plane,etcd,master   4h20m   v1.28.9+rke2r1
node2.edge.rdo.wales   Ready    control-plane,etcd,master   4h15m   v1.28.9+rke2r1
node3.edge.rdo.wales   Ready    control-plane,etcd,master   4h15m   v1.28.9+rke2r1

现在您可以继续安装 KubeVirtContainerized Data Importer (CDI) Helm chart:

$ helm install kubevirt oci://registry.suse.com/edge/kubevirt-chart --namespace kubevirt-system --create-namespace
$ helm install cdi oci://registry.suse.com/edge/cdi-chart --namespace cdi-system --create-namespace

几分钟后,所有 KubeVirt 和 CDI 组件应会部署完成。您可以通过检查 kubevirt-systemcdi-system 名称空间中部署的所有资源进行验证。

校验 KubeVirt 资源:

$ kubectl get all -n kubevirt-system

此命令应会显示如下所示的输出:

NAME                                   READY   STATUS    RESTARTS      AGE
pod/virt-operator-5fbcf48d58-p7xpm     1/1     Running   0             2m24s
pod/virt-operator-5fbcf48d58-wnf6s     1/1     Running   0             2m24s
pod/virt-handler-t594x                 1/1     Running   0             93s
pod/virt-controller-5f84c69884-cwjvd   1/1     Running   1 (64s ago)   93s
pod/virt-controller-5f84c69884-xxw6q   1/1     Running   1 (64s ago)   93s
pod/virt-api-7dfc54cf95-v8kcl          1/1     Running   1 (59s ago)   118s

NAME                                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubevirt-prometheus-metrics   ClusterIP   None            <none>        443/TCP   2m1s
service/virt-api                      ClusterIP   10.43.56.140    <none>        443/TCP   2m1s
service/kubevirt-operator-webhook     ClusterIP   10.43.201.121   <none>        443/TCP   2m1s
service/virt-exportproxy              ClusterIP   10.43.83.23     <none>        443/TCP   2m1s

NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/virt-handler   1         1         1       1            1           kubernetes.io/os=linux   93s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/virt-operator     2/2     2            2           2m24s
deployment.apps/virt-controller   2/2     2            2           93s
deployment.apps/virt-api          1/1     1            1           118s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/virt-operator-5fbcf48d58     2         2         2       2m24s
replicaset.apps/virt-controller-5f84c69884   2         2         2       93s
replicaset.apps/virt-api-7dfc54cf95          1         1         1       118s

NAME                            AGE     PHASE
kubevirt.kubevirt.io/kubevirt   2m24s   Deployed

校验 CDI 资源:

$ kubectl get all -n cdi-system

此命令应会显示如下所示的输出:

NAME                                   READY   STATUS    RESTARTS   AGE
pod/cdi-operator-55c74f4b86-692xb      1/1     Running   0          2m24s
pod/cdi-apiserver-db465b888-62lvr      1/1     Running   0          2m21s
pod/cdi-deployment-56c7d74995-mgkfn    1/1     Running   0          2m21s
pod/cdi-uploadproxy-7d7b94b968-6kxc2   1/1     Running   0          2m22s

NAME                             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/cdi-uploadproxy          ClusterIP   10.43.117.7    <none>        443/TCP    2m22s
service/cdi-api                  ClusterIP   10.43.20.101   <none>        443/TCP    2m22s
service/cdi-prometheus-metrics   ClusterIP   10.43.39.153   <none>        8080/TCP   2m21s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cdi-operator      1/1     1            1           2m24s
deployment.apps/cdi-apiserver     1/1     1            1           2m22s
deployment.apps/cdi-deployment    1/1     1            1           2m21s
deployment.apps/cdi-uploadproxy   1/1     1            1           2m22s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/cdi-operator-55c74f4b86      1         1         1       2m24s
replicaset.apps/cdi-apiserver-db465b888      1         1         1       2m21s
replicaset.apps/cdi-deployment-56c7d74995    1         1         1       2m21s
replicaset.apps/cdi-uploadproxy-7d7b94b968   1         1         1       2m22s

要校验是否已部署 VirtualMachine 自定义资源定义 (CRD),请使用以下命令:

$ kubectl explain virtualmachine

此命令应会列显 VirtualMachine 对象的定义,如下所示:

GROUP:      kubevirt.io
KIND:       VirtualMachine
VERSION:    v1

DESCRIPTION:
    VirtualMachine handles the VirtualMachines that are not running or are in a
    stopped state The VirtualMachine contains the template to create the
    VirtualMachineInstance. It also mirrors the running state of the created
    VirtualMachineInstance in its status.
(snip)

18.4 部署虚拟机

部署 KubeVirt 和 CDI 后,我们需要基于 openSUSE Tumbleweed 定义一个简单的虚拟机。此虚拟机采用最简单的配置,与任何其他 Pod 一样使用标准的“Pod 网络”进行网络配置。与任何没有 PVC 的容器一样,它也采用非永久存储,因此可确保存储是临时性的。

$ kubectl apply -f - <<EOF
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: tumbleweed
  namespace: default
spec:
  runStrategy: Always
  template:
    spec:
      domain:
        devices: {}
        machine:
          type: q35
        memory:
          guest: 2Gi
        resources: {}
      volumes:
      - containerDisk:
          image: registry.opensuse.org/home/roxenham/tumbleweed-container-disk/containerfile/cloud-image:latest
        name: tumbleweed-containerdisk-0
      - cloudInitNoCloud:
          userDataBase64: I2Nsb3VkLWNvbmZpZwpkaXNhYmxlX3Jvb3Q6IGZhbHNlCnNzaF9wd2F1dGg6IFRydWUKdXNlcnM6CiAgLSBkZWZhdWx0CiAgLSBuYW1lOiBzdXNlCiAgICBncm91cHM6IHN1ZG8KICAgIHNoZWxsOiAvYmluL2Jhc2gKICAgIHN1ZG86ICBBTEw9KEFMTCkgTk9QQVNTV0Q6QUxMCiAgICBsb2NrX3Bhc3N3ZDogRmFsc2UKICAgIHBsYWluX3RleHRfcGFzc3dkOiAnc3VzZScK
        name: cloudinitdisk
EOF

此命令列显的输出应会指出已创建 VirtualMachine

virtualmachine.kubevirt.io/tumbleweed created

VirtualMachine 定义极其简洁,几乎未指定配置信息。它只是概括性地指明,此计算机的类型为“q35”,具有 2 GB 内存,使用基于临时 containerDisk 的磁盘映像(即,存储在远程映像储存库中某个容器映像内的磁盘映像)。此定义还指定了一个 base64 编码的 cloudInit 磁盘,该磁盘仅用于在引导时创建用户和执行口令(可使用 base64-d 对其进行解码)。

注意
注意

此虚拟机映像仅用于测试。该映像不受官方支持,仅用作文档示例。

此虚拟机需要几分钟时间才能完成引导,因为它需要下载 openSUSE Tumbleweed 磁盘映像,但一旦完成此过程,您可以通过检查虚拟机信息来查看有关该虚拟机的更多细节:

$ kubectl get vmi

此命令应会列显启动虚拟机的节点以及虚拟机的 IP 地址。请记住,由于它使用 Pod 网络,因此报告的 IP 地址与任何其他 Pod 一样并且可路由:

NAME         AGE     PHASE     IP           NODENAME               READY
tumbleweed   4m24s   Running   10.42.2.98   node3.edge.rdo.wales   True

在使用 CNI(例如 Cilium)将流量直接路由到 Pod 的情况下,在 Kubernetes 群集节点本身上运行这些命令时,您应该可以通过 ssh 直接连接到该虚拟机本身。请将下面的 IP 地址替换为分配给您的虚拟机的 IP 地址:

$ ssh suse@10.42.2.98
(password is "suse")

进入此虚拟机后,可对其进行任意操作,但请记住,它的资源有限,磁盘空间只有 1 GB。完成后,请按 Ctrl-D 或输入 exit 断开连接 SSH 会话。

虚拟机进程仍包装在标准 Kubernetes Pod 中。VirtualMachine CRD 代表所需的虚拟机,但与任何其他应用程序一样,实际启动虚拟机的过程是通过 virt-launcher Pod(标准 Kubernetes Pod)进行的。对于启动的每个虚拟机,都有一个对应的 virt-launcher Pod:

$ kubectl get pods

此命令应会针对我们定义的 Tumbleweed 虚拟机显示一个 virt-launcher Pod:

NAME                             READY   STATUS    RESTARTS   AGE
virt-launcher-tumbleweed-8gcn4   3/3     Running   0          10m

如果深入查看这个 virt-launcher Pod,您会看到它正在执行 libvirtqemu-kvm 进程。我们可以进入该 Pod 本身并查看其内部工作。请注意您需要根据自己的 Pod 名称修改以下命令:

$ kubectl exec -it virt-launcher-tumbleweed-8gcn4 -- bash

进入 Pod 后,尝试运行 virsh 命令并查看进程。您会看到 qemu-system-x86_64 二进制文件正在运行,以及用于监控虚拟机的某些进程。您还会看到磁盘映像的位置以及网络(作为 tap 设备)的插接方式:

qemu@tumbleweed:/> ps ax
  PID TTY      STAT   TIME COMMAND
    1 ?        Ssl    0:00 /usr/bin/virt-launcher-monitor --qemu-timeout 269s --name tumbleweed --uid b9655c11-38f7-4fa8-8f5d-bfe987dab42c --namespace default --kubevirt-share-dir /var/run/kubevirt --ephemeral-disk-dir /var/run/kubevirt-ephemeral-disks --container-disk-dir /var/run/kube
   12 ?        Sl     0:01 /usr/bin/virt-launcher --qemu-timeout 269s --name tumbleweed --uid b9655c11-38f7-4fa8-8f5d-bfe987dab42c --namespace default --kubevirt-share-dir /var/run/kubevirt --ephemeral-disk-dir /var/run/kubevirt-ephemeral-disks --container-disk-dir /var/run/kubevirt/con
   24 ?        Sl     0:00 /usr/sbin/virtlogd -f /etc/libvirt/virtlogd.conf
   25 ?        Sl     0:01 /usr/sbin/virtqemud -f /var/run/libvirt/virtqemud.conf
   83 ?        Sl     0:31 /usr/bin/qemu-system-x86_64 -name guest=default_tumbleweed,debug-threads=on -S -object {"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/run/kubevirt-private/libvirt/qemu/lib/domain-1-default_tumbleweed/master-key.aes"} -machine pc-q35-7.1,usb
  286 pts/0    Ss     0:00 bash
  320 pts/0    R+     0:00 ps ax

qemu@tumbleweed:/> virsh list --all
 Id   Name                 State
------------------------------------
 1    default_tumbleweed   running

qemu@tumbleweed:/> virsh domblklist 1
 Target   Source
---------------------------------------------------------------------------------------------
 sda      /var/run/kubevirt-ephemeral-disks/disk-data/tumbleweed-containerdisk-0/disk.qcow2
 sdb      /var/run/kubevirt-ephemeral-disks/cloud-init-data/default/tumbleweed/noCloud.iso

qemu@tumbleweed:/> virsh domiflist 1
 Interface   Type       Source   Model                     MAC
------------------------------------------------------------------------------
 tap0        ethernet   -        virtio-non-transitional   e6:e9:1a:05:c0:92

qemu@tumbleweed:/> exit
exit

最后,我们需要删除此虚拟机以清理资源:

$ kubectl delete vm/tumbleweed
virtualmachine.kubevirt.io "tumbleweed" deleted

18.5 使用 virtctl

除了标准的 Kubernetes CLI 工具 kubectl 之外,KubeVirt 还附带了 CLI 实用程序用于与群集连接,这种连接方式可以弥合虚拟化领域与 Kubernetes 适用领域之间的差距。例如,virtctl 工具提供管理虚拟机生命周期(启动、停止、重启动等)的功能,可用于访问虚拟控制台、上载虚拟机映像,以及与 Kubernetes 构造(例如服务)连接,而无需直接使用 API 或 CRD。

我们来下载最新的稳定版 virtctl 工具:

$ export VERSION=v1.1.0
$ wget https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-linux-amd64

如果您使用的是其他体系结构或非 Linux 计算机,可在此处找到其他版本。需要先将其转换为可执行文件才能继续,将其移动到 $PATH 中的某个位置可能会有帮助:

$ mv virtctl-${VERSION}-linux-amd64 /usr/local/bin/virtctl
$ chmod a+x /usr/local/bin/virtctl

然后,可以使用 virtctl 命令行工具创建虚拟机。我们来复制前面创建的虚拟机,请注意我们会通过管道将输出直接传入 kubectl apply

$ virtctl create vm --name virtctl-example --memory=1Gi \
    --volume-containerdisk=src:registry.opensuse.org/home/roxenham/tumbleweed-container-disk/containerfile/cloud-image:latest \
    --cloud-init-user-data "I2Nsb3VkLWNvbmZpZwpkaXNhYmxlX3Jvb3Q6IGZhbHNlCnNzaF9wd2F1dGg6IFRydWUKdXNlcnM6CiAgLSBkZWZhdWx0CiAgLSBuYW1lOiBzdXNlCiAgICBncm91cHM6IHN1ZG8KICAgIHNoZWxsOiAvYmluL2Jhc2gKICAgIHN1ZG86ICBBTEw9KEFMTCkgTk9QQVNTV0Q6QUxMCiAgICBsb2NrX3Bhc3N3ZDogRmFsc2UKICAgIHBsYWluX3RleHRfcGFzc3dkOiAnc3VzZScK" | kubectl apply -f -

此命令应会显示虚拟机正在运行(由于容器映像将被缓存,因此这一次虚拟机的启动速度更快一些):

$ kubectl get vmi
NAME              AGE   PHASE     IP           NODENAME               READY
virtctl-example   52s   Running   10.42.2.29   node3.edge.rdo.wales   True

现在我们可以使用 virtctl 直接连接到该虚拟机:

$ virtctl ssh suse@virtctl-example
(password is "suse" - Ctrl-D to exit)

virtctl 还可以使用其他许多命令。例如,如果网络出现故障,您可以使用 virtctl console 访问串行控制台;可以使用 virtctl guestosinfo 获取详细的操作系统信息,前提是已在 Guest 上安装并运行 qemu-guest-agent

最后,我们需要暂停再恢复该虚拟机:

$ virtctl pause vm virtctl-example
VMI virtctl-example was scheduled to pause

您会发现,VirtualMachine 对象显示为 Paused,而 VirtualMachineInstance 对象则显示为 Running,但同时显示了 READY=False

$ kubectl get vm
NAME              AGE     STATUS   READY
virtctl-example   8m14s   Paused   False

$ kubectl get vmi
NAME              AGE     PHASE     IP           NODENAME               READY
virtctl-example   8m15s   Running   10.42.2.29   node3.edge.rdo.wales   False

您还会发现不再可以连接到该虚拟机:

$ virtctl ssh suse@virtctl-example
can't access VMI virtctl-example: Operation cannot be fulfilled on virtualmachineinstance.kubevirt.io "virtctl-example": VMI is paused

我们需要恢复该虚拟机并重试:

$ virtctl unpause vm virtctl-example
VMI virtctl-example was scheduled to unpause

现在我们应该可以重新建立连接:

$ virtctl ssh suse@virtctl-example
suse@vmi/virtctl-example.default's password:
suse@virtctl-example:~> exit
logout

最后,我们需要去除该虚拟机:

$ kubectl delete vm/virtctl-example
virtualmachine.kubevirt.io "virtctl-example" deleted

18.6 简单入口网络

本节介绍如何将虚拟机公开为标准 Kubernetes 服务,并通过 Kubernetes 入口服务(例如 RKE2 中的 NGINXK3s 中的 Traefik)来提供这些虚拟机。本文档假设已正确配置这些组件,并且有一个适当的 DNS 指针指向 Kubernetes 服务器节点或入口虚拟 IP(例如通过通配符来指向),以正确解析入口。

注意
注意

在 SUSE Edge 3.0+ 中,如果您在多服务器节点配置中使用 K3s,则可能需要为入口配置基于 MetalLB 的 VIP;对于 RKE2 则不需要这样做。

在示例环境中,部署了另一个 openSUSE Tumbleweed 虚拟机,cloud-init 用于在引导时将 NGINX 安装为简单 Web 服务器,此外,已配置为返回一条简单讯息,以校验在发出调用时该虚拟机是否按预期工作。要了解如何执行此操作,只需对以下输出中的 cloud-init 部分运行 base64 -d 即可。

现在我们来创建此虚拟机:

$ kubectl apply -f - <<EOF
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: ingress-example
  namespace: default
spec:
  runStrategy: Always
  template:
    metadata:
      labels:
        app: nginx
    spec:
      domain:
        devices: {}
        machine:
          type: q35
        memory:
          guest: 2Gi
        resources: {}
      volumes:
      - containerDisk:
          image: registry.opensuse.org/home/roxenham/tumbleweed-container-disk/containerfile/cloud-image:latest
        name: tumbleweed-containerdisk-0
      - cloudInitNoCloud:
          userDataBase64: I2Nsb3VkLWNvbmZpZwpkaXNhYmxlX3Jvb3Q6IGZhbHNlCnNzaF9wd2F1dGg6IFRydWUKdXNlcnM6CiAgLSBkZWZhdWx0CiAgLSBuYW1lOiBzdXNlCiAgICBncm91cHM6IHN1ZG8KICAgIHNoZWxsOiAvYmluL2Jhc2gKICAgIHN1ZG86ICBBTEw9KEFMTCkgTk9QQVNTV0Q6QUxMCiAgICBsb2NrX3Bhc3N3ZDogRmFsc2UKICAgIHBsYWluX3RleHRfcGFzc3dkOiAnc3VzZScKcnVuY21kOgogIC0genlwcGVyIGluIC15IG5naW54CiAgLSBzeXN0ZW1jdGwgZW5hYmxlIC0tbm93IG5naW54CiAgLSBlY2hvICJJdCB3b3JrcyEiID4gL3Nydi93d3cvaHRkb2NzL2luZGV4Lmh0bQo=
        name: cloudinitdisk
EOF

此虚拟机成功启动后,我们可以使用 virtctl 命令公开 VirtualMachineInstance,其外部端口为 8080,目标端口为 80(NGINX 默认侦听此端口)。此处我们之所以使用 virtctl 命令,是因为它能够识别虚拟机对象与 Pod 之间的映射。这为我们创建了新服务:

$ virtctl expose vmi ingress-example --port=8080 --target-port=80 --name=ingress-example
Service ingress-example successfully exposed for vmi ingress-example

然后会自动创建一个适当的服务:

$ kubectl get svc/ingress-example
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                         AGE
ingress-example   ClusterIP      10.43.217.19    <none>            8080/TCP                        9s

接下来,如果您使用 kubectl create ingress,则可以创建一个指向此服务的 ingress 对象。此处请根据您的 DNS 配置修改 URL(在 ingress 对象中称为“host”),并确保将其指向端口 8080

$ kubectl create ingress ingress-example --rule=ingress-example.suse.local/=ingress-example:8080

正确配置 DNS 后,可以立即对 URL 运行 curl 命令:

$ curl ingress-example.suse.local
It works!

我们来通过去除此虚拟机及其服务和入口资源进行清理:

$ kubectl delete vm/ingress-example svc/ingress-example ingress/ingress-example
virtualmachine.kubevirt.io "ingress-example" deleted
service "ingress-example" deleted
ingress.networking.k8s.io "ingress-example" deleted

18.7 使用 Rancher UI 扩展

SUSE 边缘虚拟化为 Rancher Manager 提供了 UI 扩展,让您可以使用 Rancher 仪表板 UI 进行基本的虚拟机管理。

18.7.1 安装

请参见 Rancher 仪表板扩展的相关章节获取安装指导。

18.7.2 使用 KubeVirt Rancher 仪表板扩展

该扩展在群集资源管理器中引入了新的 KubeVirt 部分。此部分已添加到装有 KubeVirt 的任何受管群集。

使用该扩展可以直接与以下两个 KubeVirt 资源交互:

  1. 虚拟机实例 — 代表单个正在运行的虚拟机实例的资源。

  2. 虚拟机 — 用于管理虚拟机生命周期的资源。

18.7.2.1 创建虚拟机

  1. 单击左侧导航栏中已启用 KubeVirt 的受管群集,导航到 Cluster Explorer(群集资源管理器)。

  2. 导航到 KubeVirt > Virtual Machines(虚拟机)页面,然后单击屏幕右上角的 Create from YAML(从 YAML 创建)。

  3. 填写或粘贴虚拟机定义,然后按 Create(创建)。使用“部署虚拟机”一节中创建的虚拟机定义作为灵感来源。

虚拟机页面

18.7.2.2 启动和停止虚拟机

使用操作菜单(可通过每个虚拟机右侧的 下拉列表访问)来启动和停止虚拟机,或者选择虚拟机并使用列表顶部的组操作对其执行操作。

只能对定义了 spec.running 属性的虚拟机运行启动和停止操作。如果使用了 spec.runStrategy,则无法直接启动和停止此类计算机。有关详细信息,请参见 KubeVirt 文档

18.7.2.3 访问虚拟机控制台

“Virtual machines”(虚拟机)列表提供了控制台下拉列表,用于通过 VNC 或串行控制台连接到虚拟机。此操作仅适用于正在运行的虚拟机。

在某些情况下,需要等待一段时间才能在全新启动的虚拟机上访问控制台。

VNC 控制台 UI

18.8 使用 Edge Image Builder 进行安装

SUSE Edge 使用第 9 章 “Edge Image Builder来自定义基础 SLE Micro 操作系统映像。请按照第 21.9 节 “KubeVirt 和 CDI 安装”中所述,在 EIB 置备的 Kubernetes 群集上进行 KubeVirt 和 CDI 隔离式安装。

第 III 部分 操作指南

操作指南和最佳实践

  • 19 K3s 上的 MetalLB(使用 L2)
  • MetalLB 是使用标准路由协议的裸机 Kubernetes 群集的负载平衡器实现。

  • 20 Kubernetes API 服务器前面的 MetalLB
  • 本指南演示如何使用 MetalLB 服务在包含三个控制平面节点的 HA K3s 群集上向外部公开 K3s API。为此,需要手动创建类型为 LoadBalancer 的 Kubernetes 服务,并创建端点。端点保留群集中所有控制平面节点的 IP。为了使端点与群集中发生的事件(添加/去除节点或节点脱机)持续保持同步,需要部署 Endpoint Copier Operator。该操作器监控默认 kubernetes 端点中发生的事件,并自动更新受管服务以使其保持同步。由于受管服务的类型为 LoadBalancer,因此 MetalLB 为其分配了静态 ExternalIP。此 External…

  • 21 使用 Edge Image Builder 进行隔离式部署
  • 本指南将介绍如何使用 Edge Image Builder (EIB)(第 9 章 “Edge Image Builder)在 SLE Micro 5.5 上以完全隔离的方式部署多个 SUSE Edge 组件。使用此方法可以引导至 EIB 所创建的自定义的、随时可引导 (CRB) 的映像,并在 RKE2 或 K3s 群集上部署指定的组件,而无需连接到互联网,也无需执行任何手动步骤。对于想要将部署所需的所有项目预先植入其操作系统映像的客户而言,此配置非常理想,这样就可以在引导时立即使用这些项目。

19 K3s 上的 MetalLB(使用 L2)

MetalLB 是使用标准路由协议的裸机 Kubernetes 群集的负载平衡器实现。

本指南演示如何以第 2 层模式部署 MetalLB。

19.1 为何使用此方法

在第 2 层模式下,一个节点负责向本地网络播发服务。从网络的角度看,似乎为该计算机的网络接口分配了多个 IP 地址。

第 2 层模式的主要优势在于其通用性:它可以在任何以太网上正常工作,不需要任何特殊硬件,甚至不需要各种形式的路由器。

19.2 K3s 上的 MetalLB(使用 L2)

本快速入门将使用 L2 模式,这意味着我们不需要任何特殊网络设备,而只需设置网络范围内的几个可用 IP(最好是 DHCP 池以外的 IP,因为这些 IP 尚未分配)。

在此示例中,192.168.122.0/24 网络的 DHCP 池为 192.168.122.100-192.168.122.200(是的,有三个 IP,有关出现额外 IP 的原因,请参见“Traefik 和 MetalLB”一节(第 19.3.3 节 “Traefik 和 MetalLB”)),因此可以使用此范围以外的任何 IP(对于网关和其他可能已运行的主机也是如此!)

19.3 先决条件

  • 要在其中部署 MetalLB 的 K3s 群集。

警告
警告

K3S 附带自身的服务负载平衡器(名为 Klipper)。需要禁用 Klipper 才能运行 MetalLB。要禁用 Klipper,需使用 ‑‑disable=servicelb 标志安装 K3s。

  • Helm

  • 我们的网络范围内有少量多个可用 IP,在本例中为 192.168.122.10-192.168.122.12

19.3.1 部署

MetalLB 利用 Helm(及其他方法),因此请运行:

helm repo add metallb https://metallb.github.io/metallb
helm install --create-namespace -n metallb-system metallb metallb/metallb

while ! kubectl wait --for condition=ready -n metallb-system $(kubectl get\
 pods -n metallb-system -l app.kubernetes.io/component=controller -o name)\
 --timeout=10s; do
 sleep 2
done

19.3.2 配置

安装现已完成。接下来请使用示例值进行配置

cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: ip-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.122.10/32
  - 192.168.122.11/32
  - 192.168.122.12/32
EOF
cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: ip-pool-l2-adv
  namespace: metallb-system
spec:
  ipAddressPools:
  - ip-pool
EOF

现在,MetalLB 可供您使用。可以自定义 L2 模式的许多设置,例如:

还可以对 BGP 进行其他许多自定义设置。

19.3.3 Traefik 和 MetalLB

默认情况下,Traefik 会随 K3s 一起部署(可以使用 --disable=traefik 禁用 Traefik),并作为 LoadBalancer 公开(与 Klipper 一起使用)。但是,由于需要禁用 Klipper,用于入口的 Traefik 服务仍是 LoadBalancer 类型。因此在部署 MetalLB 的那一刻,第一个 IP 将自动分配给 Traefik 入口。

# Before deploying MetalLB
kubectl get svc -n kube-system traefik
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
traefik   LoadBalancer   10.43.44.113   <pending>     80:31093/TCP,443:32095/TCP   28s
# After deploying MetalLB
kubectl get svc -n kube-system traefik
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                      AGE
traefik   LoadBalancer   10.43.44.113   192.168.122.10   80:31093/TCP,443:32095/TCP   3m10s

我们将在稍后的过程(第 19.4 节 “MetalLB 的入口”)中应用此操作。

19.3.4 用法

我们来创建示例部署:

cat <<- EOF | kubectl apply -f -
---
apiVersion: v1
kind: Namespace
metadata:
  name: hello-kubernetes
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: hello-kubernetes
  template:
    metadata:
      labels:
        app.kubernetes.io/name: hello-kubernetes
    spec:
      serviceAccountName: hello-kubernetes
      containers:
        - name: hello-kubernetes
          image: "paulbouwer/hello-kubernetes:1.10"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          env:
          - name: HANDLER_PATH_PREFIX
            value: ""
          - name: RENDER_PATH_PREFIX
            value: ""
          - name: KUBERNETES_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: KUBERNETES_POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: KUBERNETES_NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: CONTAINER_IMAGE
            value: "paulbouwer/hello-kubernetes:1.10"
EOF

最后创建服务:

cat <<- EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: hello-kubernetes
EOF

我们来看看此示例的实际效果:

kubectl get svc -n hello-kubernetes
NAME               TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
hello-kubernetes   LoadBalancer   10.43.127.75   192.168.122.11   80:31461/TCP   8s

curl http://192.168.122.11
<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>

  <div class="main">
    <img src="/images/kubernetes.png"/>
    <div class="content">
      <div id="message">
  Hello world!
</div>
<div id="info">
  <table>
    <tr>
      <th>namespace:</th>
      <td>hello-kubernetes</td>
    </tr>
    <tr>
      <th>pod:</th>
      <td>hello-kubernetes-7c8575c848-2c6ps</td>
    </tr>
    <tr>
      <th>node:</th>
      <td>allinone (Linux 5.14.21-150400.24.46-default)</td>
    </tr>
  </table>
</div>
<div id="footer">
  paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
    </div>
  </div>

</body>
</html>

19.4 MetalLB 的入口

由于 Traefik 已用作入口控制器,我们可以通过 Ingress 对象公开任何 HTTP / HTTPS 流量,例如:

IP=$(kubectl get svc -n kube-system traefik -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
cat <<- EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  namespace: hello-kubernetes
spec:
  rules:
  - host: hellok3s.${IP}.sslip.io
    http:
      paths:
        - path: "/"
          pathType: Prefix
          backend:
            service:
              name: hello-kubernetes
              port:
                name: http
EOF

然后运行:

curl http://hellok3s.${IP}.sslip.io
<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>

  <div class="main">
    <img src="/images/kubernetes.png"/>
    <div class="content">
      <div id="message">
  Hello world!
</div>
<div id="info">
  <table>
    <tr>
      <th>namespace:</th>
      <td>hello-kubernetes</td>
    </tr>
    <tr>
      <th>pod:</th>
      <td>hello-kubernetes-7c8575c848-fvqm2</td>
    </tr>
    <tr>
      <th>node:</th>
      <td>allinone (Linux 5.14.21-150400.24.46-default)</td>
    </tr>
  </table>
</div>
<div id="footer">
  paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
    </div>
  </div>

</body>
</html>

另外,要校验 MetalLB 是否正常工作,可如下所示使用 arping

arping hellok3s.${IP}.sslip.io

预期结果:

ARPING 192.168.64.210
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=0 time=1.169 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=1 time=2.992 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=2 time=2.884 msec

在以上示例中,流量的流动方式如下:

  1. hellok3s.${IP}.sslip.io 解析为实际 IP。

  2. 然后,流量由 metallb-speaker Pod 处理。

  3. metallb-speaker 将流量重定向到 traefik 控制器。

  4. 最后,Traefik 将请求转发到 hello-kubernetes 服务。

20 Kubernetes API 服务器前面的 MetalLB

本指南演示如何使用 MetalLB 服务在包含三个控制平面节点的 HA K3s 群集上向外部公开 K3s API。为此,需要手动创建类型为 LoadBalancer 的 Kubernetes 服务,并创建端点。端点保留群集中所有控制平面节点的 IP。为了使端点与群集中发生的事件(添加/去除节点或节点脱机)持续保持同步,需要部署 Endpoint Copier Operator。该操作器监控默认 kubernetes 端点中发生的事件,并自动更新受管服务以使其保持同步。由于受管服务的类型为 LoadBalancer,因此 MetalLB 为其分配了静态 ExternalIP。此 ExternalIP 用于与 API 服务器通讯。

20.1 先决条件

  • 要在其上部署 K3s 的三台主机。

    • 请确保这些主机的主机名不同。

    • 对于测试目的,这些主机可以是虚拟机

  • 网络中至少有 2 个可用 IP(一个用于 Traefik,另一个用于受管服务)。

  • Helm

20.2 安装 K3s

注意
注意

如果您不想创建新群集,而是想要使用现有群集,请跳过此步骤并转到下一步。

首先,必须在网络中预留一个可用 IP,该 IP 稍后将用作受管服务的 ExternalIP

通过 SSH 连接到第一台主机并以群集模式安装 K3s,如下所示:

# Export the free IP mentioned above
export VIP_SERVICE_IP=<ip>
export INSTALL_K3S_SKIP_START=false

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --cluster-init \
 --disable=servicelb --write-kubeconfig-mode=644 --tls-san=${VIP_SERVICE_IP} \
 --tls-san=https://${VIP_SERVICE_IP}.sslip.io" K3S_TOKEN=foobar sh -
注意
注意

确保在 k3s server 命令中提供 --disable=servicelb 标志。

重要
重要

从现在开始,应在本地计算机上运行命令。

要从外部访问 API 服务器,需使用 K3s VM 的 IP。

# Replace <node-ip> with the actual IP of the machine
export NODE_IP=<node-ip>
scp ${NODE_IP}:/etc/rancher/k3s/k3s.yaml ~/.kube/config && sed \
 -i '' "s/127.0.0.1/${NODE_IP}/g" ~/.kube/config && chmod 600 ~/.kube/config

20.3 配置现有的 K3s 群集

注意
注意

仅当您要使用现有的 K3s 群集时,此步骤才有效。

要使用现有的 K3s 群集,应禁用 servicelb LB 并修改 tls-san 标志。

要更改 K3s 标志,应在群集中的所有 VM 上修改 /etc/systemd/system/k3s.service

标志应插入到 ExecStart 中。例如:

# Replace the <vip-service-ip> with the actual ip
ExecStart=/usr/local/bin/k3s \
    server \
        '--cluster-init' \
        '--write-kubeconfig-mode=644' \
        '--disable=servicelb' \
        '--tls-san=<vip-service-ip>' \
        '--tls-san=https://<vip-service-ip>.sslip.io' \

然后应执行以下命令,让 K3s 加载新配置:

systemctl daemon-reload
systemctl restart k3s

20.4 安装 MetalLB

要部署 MetalLB,可以使用 K3s 上的 MetalLB 指南。

注意:确保 ip-pool IPAddressPool 的 IP 地址不与先前为 LoadBalancer 服务选择的 IP 地址重叠。

单独创建一个仅供受管服务使用的 IpAddressPool

# Export the VIP_SERVICE_IP on the local machine
# Replace with the actual IP
export VIP_SERVICE_IP=<ip>

cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: kubernetes-vip-ip-pool
  namespace: metallb-system
spec:
  addresses:
  - ${VIP_SERVICE_IP}/32
  serviceAllocation:
    priority: 100
    namespaces:
      - default
EOF
cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: ip-pool-l2-adv
  namespace: metallb-system
spec:
  ipAddressPools:
  - ip-pool
  - kubernetes-vip-ip-pool
EOF

20.5 安装 Endpoint Copier Operator

helm repo add endpoint-copier-operator \
 https://suse-edge.github.io/endpoint-copier-operator

helm install --create-namespace -n endpoint-copier-operator \
 endpoint-copier-operator endpoint-copier-operator/endpoint-copier-operator

以上命令将在群集中部署三个不同的资源:

  1. 包含两个复本的 endpoint-copier-operator 操作器部署。其中一个复本是领导者,另一个复本在需要时接管领导者角色。

  2. default 名称空间中名为 kubernetes-vip 的 Kubernetes 服务,它是 kubernetes 服务的副本,但类型为 LoadBalancer

  3. default 名称空间中名为 kubernetes-vip 的端点资源,它是 kubernetes 端点的副本。

校验 kubernetes-vip 服务是否使用正确的 IP 地址:

kubectl get service kubernetes-vip -n default \
 -o=jsonpath='{.status.loadBalancer.ingress[0].ip}'

确保 default 名称空间中的 kubernetes-vipkubernetes 端点资源指向相同的 IP。

kubectl get endpoints kubernetes kubernetes-vip

如果所有设置正确,剩下的最后一项操作就是在 Kubeconfig 中使用 VIP_SERVICE_IP

sed -i '' "s/${NODE_IP}/${VIP_SERVICE_IP}/g" ~/.kube/config

从现在开始,所有 kubectl 命令都将通过 kubernetes-vip 服务运行。

20.6 添加控制平面节点

要监控整个过程,可以打开另外两个终端选项卡。

第一个终端:

watch kubectl get nodes

第二个终端:

watch kubectl get endpoints

现在,在第二和第三个节点上执行以下命令。

# Export the VIP_SERVICE_IP in the VM
# Replace with the actual IP
export VIP_SERVICE_IP=<ip>
export INSTALL_K3S_SKIP_START=false

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server \
 --server https://${VIP_SERVICE_IP}:6443 --disable=servicelb \
 --write-kubeconfig-mode=644" K3S_TOKEN=foobar sh -

21 使用 Edge Image Builder 进行隔离式部署

21.1 简介

本指南将介绍如何使用 Edge Image Builder (EIB)(第 9 章 “Edge Image Builder)在 SLE Micro 5.5 上以完全隔离的方式部署多个 SUSE Edge 组件。使用此方法可以引导至 EIB 所创建的自定义的、随时可引导 (CRB) 的映像,并在 RKE2 或 K3s 群集上部署指定的组件,而无需连接到互联网,也无需执行任何手动步骤。对于想要将部署所需的所有项目预先植入其操作系统映像的客户而言,此配置非常理想,这样就可以在引导时立即使用这些项目。

本指南将介绍以下组件的隔离式安装:

警告
警告

EIB 将分析并预先下载提供的 Helm chart 和 Kubernetes 清单中引用的所有映像。但是,其中一些操作可能会尝试提取容器映像并在运行时基于这些映像创建 Kubernetes 资源。在这种情况下,如果我们想要设置完全隔离的环境,则必须在定义文件中手动指定所需的映像。

21.2 先决条件

我们假设本指南的读者已事先熟悉 EIB(第 9 章 “Edge Image Builder)。如果您不熟悉,请阅读快速入门指南(第 3 章 “使用 Edge Image Builder 配置独立群集)来更好地理解以下实践中所述的概念。

21.3 Libvirt 网络配置

注意
注意

为了演示隔离式部署,本指南将使用模拟的 libvirt 隔离网络,并根据该网络定制以下配置。对于您自己的部署,可能需要修改下一步骤中将介绍的 host1.local.yaml 配置。

如果您要使用相同的 libvirt 网络配置,请继续阅读。否则请跳到第 21.4 节 “基础目录配置”

我们来为 DHCP 创建 IP 地址范围为 192.168.100.2/24 的隔离网络配置:

cat << EOF > isolatednetwork.xml
<network>
  <name>isolatednetwork</name>
  <bridge name='virbr1' stp='on' delay='0'/>
  <ip address='192.168.100.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.100.2' end='192.168.100.254'/>
    </dhcp>
  </ip>
</network>
EOF

现在,唯一剩下的操作就是创建并启动网络:

virsh net-define isolatednetwork.xml
virsh net-start isolatednetwork

21.4 基础目录配置

基础目录配置在所有组件中是相同的,现在我们就设置此配置。

首先创建所需的子目录:

export CONFIG_DIR=$HOME/config
mkdir -p $CONFIG_DIR/base-images
mkdir -p $CONFIG_DIR/network
mkdir -p $CONFIG_DIR/kubernetes/helm/values

请确保将您要使用的任何基础映像添加到 base-images 目录中。本指南将重点介绍此处提供的自行安装 ISO 映像。

我们来复制已下载的映像:

cp SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso $CONFIG_DIR/base-images/slemicro.iso
注意
注意

EIB 永远不会修改基础映像输入。

我们来创建一个包含所需网络配置的文件:

cat << EOF > $CONFIG_DIR/network/host1.local.yaml
routes:
  config:
  - destination: 0.0.0.0/0
    metric: 100
    next-hop-address: 192.168.100.1
    next-hop-interface: eth0
    table-id: 254
  - destination: 192.168.100.0/24
    metric: 100
    next-hop-address:
    next-hop-interface: eth0
    table-id: 254
dns-resolver:
  config:
    server:
    - 192.168.100.1
    - 8.8.8.8
interfaces:
- name: eth0
  type: ethernet
  state: up
  mac-address: 34:8A:B1:4B:16:E7
  ipv4:
    address:
    - ip: 192.168.100.50
      prefix-length: 24
    dhcp: false
    enabled: true
  ipv6:
    enabled: false
EOF

此配置确保置备的系统上存在以下设置(使用指定的 MAC 地址):

  • 采用静态 IP 地址的以太网接口

  • 路由

  • DNS

  • 主机名 (host1.local)

生成的文件结构现在应如下所示:

├── kubernetes/
│   └── helm/
│       └── values/
├── base-images/
│   └── slemicro.iso
└── network/
    └── host1.local.yaml

21.5 基础定义文件

Edge Image Builder 使用定义文件来修改 SLE Micro 映像。这些文件包含大部分可配置选项。其中的许多选项将在不同的组件部分中重复出现,因此下面列出并解释了这些选项。

提示
提示

定义文件中自定义选项的完整列表可以在上游文档中找到

我们来看看所有定义文件中的以下字段:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$jHugJNNd3HElGsUZ$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
kubernetes:
  version: v1.28.9+rke2r1
embeddedArtifactRegistry:
  images:
    - ...

image 部分是必需的,用于指定输入映像、输入映像的体系结构和类型,以及输出映像的名称。

operatingSystem 部分是可选的,其中包含的配置可用于通过 root/eib 用户名/口令登录到置备的系统。

kubernetes 部分是可选的,用于定义 Kubernetes 类型和版本。我们默认将使用 Kubernetes 1.28.9 和 RKE2。如果需要 K3s,请改用 kubernetes.version: v1.28.9+k3s1。除非通过 kubernetes.nodes 字段明确配置,否则本指南中引导的所有群集都是单节点群集。

embeddedArtifactRegistry 部分包含仅在运行时为特定组件引用和提取的所有映像。

21.6 Rancher 安装

注意
注意

为便于演示,我们将大幅精简演示用的 Rancher(第 4 章 “Rancher)部署。对于实际部署,可能需要根据您的配置添加其他项目。

Rancher v2.8.4 版本资产包含 rancher-images.txt 文件,其中列出了隔离式安装所需的所有映像。

总共有大约 602 个容器映像,这意味着,生成的 CRB 映像的大小约为 28GB 以上。对于我们的 Rancher 安装,我们将精简该列表,使之与最小有效配置相当。在该列表中,可以重新添加部署所需的任何映像。

创建定义文件并在其中包含精简的映像列表:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$jHugJNNd3HElGsUZ$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
kubernetes:
  version: v1.28.9+rke2r1
  network:
    apiVIP: 192.168.100.151
  manifests:
    urls:
    - https://github.com/cert-manager/cert-manager/releases/download/v1.14.2/cert-manager.crds.yaml
  helm:
    charts:
      - name: rancher
        version: 2.8.4
        repositoryName: rancher-prime
        valuesFile: rancher-values.yaml
        targetNamespace: cattle-system
        createNamespace: true
        installationNamespace: kube-system
      - name: cert-manager
        installationNamespace: kube-system
        createNamespace: true
        repositoryName: jetstack
        targetNamespace: cert-manager
        version: 1.14.2
    repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      - name: rancher-prime
        url:  https://charts.rancher.com/server-charts/prime
embeddedArtifactRegistry:
  images:
    - name: registry.rancher.com/rancher/backup-restore-operator:v4.0.2
    - name: registry.rancher.com/rancher/calico-cni:v3.27.0-rancher1
    - name: registry.rancher.com/rancher/cis-operator:v1.0.13
    - name: registry.rancher.com/rancher/coreos-kube-state-metrics:v1.9.7
    - name: registry.rancher.com/rancher/coreos-prometheus-config-reloader:v0.38.1
    - name: registry.rancher.com/rancher/coreos-prometheus-operator:v0.38.1
    - name: registry.rancher.com/rancher/flannel-cni:v0.3.0-rancher9
    - name: registry.rancher.com/rancher/fleet-agent:v0.9.4
    - name: registry.rancher.com/rancher/fleet:v0.9.4
    - name: registry.rancher.com/rancher/gitjob:v0.9.7
    - name: registry.rancher.com/rancher/grafana-grafana:7.1.5
    - name: registry.rancher.com/rancher/hardened-addon-resizer:1.8.20-build20240410
    - name: registry.rancher.com/rancher/hardened-calico:v3.27.3-build20240423
    - name: registry.rancher.com/rancher/hardened-cluster-autoscaler:v1.8.10-build20240124
    - name: registry.rancher.com/rancher/hardened-cni-plugins:v1.4.1-build20240325
    - name: registry.rancher.com/rancher/hardened-coredns:v1.11.1-build20240305
    - name: registry.rancher.com/rancher/hardened-dns-node-cache:1.22.28-build20240125
    - name: registry.rancher.com/rancher/hardened-etcd:v3.5.9-k3s1-build20240418
    - name: registry.rancher.com/rancher/hardened-flannel:v0.25.1-build20240423
    - name: registry.rancher.com/rancher/hardened-k8s-metrics-server:v0.7.1-build20240401
    - name: registry.rancher.com/rancher/hardened-kubernetes:v1.28.9-rke2r1-build20240416
    - name: registry.rancher.com/rancher/hardened-multus-cni:v4.0.2-build20240208
    - name: registry.rancher.com/rancher/hardened-node-feature-discovery:v0.14.1-build20230926
    - name: registry.rancher.com/rancher/hardened-whereabouts:v0.6.3-build20240208
    - name: registry.rancher.com/rancher/helm-project-operator:v0.2.1
    - name: registry.rancher.com/rancher/istio-kubectl:1.5.10
    - name: registry.rancher.com/rancher/jimmidyson-configmap-reload:v0.3.0
    - name: registry.rancher.com/rancher/k3s-upgrade:v1.28.9-k3s1
    - name: registry.rancher.com/rancher/klipper-helm:v0.8.3-build20240228
    - name: registry.rancher.com/rancher/klipper-lb:v0.4.7
    - name: registry.rancher.com/rancher/kube-api-auth:v0.2.1
    - name: registry.rancher.com/rancher/kubectl:v1.28.7
    - name: registry.rancher.com/rancher/library-nginx:1.19.2-alpine
    - name: registry.rancher.com/rancher/local-path-provisioner:v0.0.26
    - name: registry.rancher.com/rancher/machine:v0.15.0-rancher112
    - name: registry.rancher.com/rancher/mirrored-cluster-api-controller:v1.4.4
    - name: registry.rancher.com/rancher/nginx-ingress-controller:nginx-1.9.6-rancher1
    - name: registry.rancher.com/rancher/pause:3.6
    - name: registry.rancher.com/rancher/prom-alertmanager:v0.21.0
    - name: registry.rancher.com/rancher/prom-node-exporter:v1.0.1
    - name: registry.rancher.com/rancher/prom-prometheus:v2.18.2
    - name: registry.rancher.com/rancher/prometheus-auth:v0.2.2
    - name: registry.rancher.com/rancher/prometheus-federator:v0.3.4
    - name: registry.rancher.com/rancher/pushprox-client:v0.1.0-rancher2-client
    - name: registry.rancher.com/rancher/pushprox-proxy:v0.1.0-rancher2-proxy
    - name: registry.rancher.com/rancher/rancher-agent:v2.8.4
    - name: registry.rancher.com/rancher/rancher-csp-adapter:v3.0.1
    - name: registry.rancher.com/rancher/rancher-webhook:v0.4.5
    - name: registry.rancher.com/rancher/rancher:v2.8.4
    - name: registry.rancher.com/rancher/rke-tools:v0.1.96
    - name: registry.rancher.com/rancher/rke2-cloud-provider:v1.29.3-build20240412
    - name: registry.rancher.com/rancher/rke2-runtime:v1.28.9-rke2r1
    - name: registry.rancher.com/rancher/rke2-upgrade:v1.28.9-rke2r1
    - name: registry.rancher.com/rancher/security-scan:v0.2.15
    - name: registry.rancher.com/rancher/shell:v0.1.24
    - name: registry.rancher.com/rancher/system-agent-installer-k3s:v1.28.9-k3s1
    - name: registry.rancher.com/rancher/system-agent-installer-rke2:v1.28.9-rke2r1
    - name: registry.rancher.com/rancher/system-agent:v0.3.6-suc
    - name: registry.rancher.com/rancher/system-upgrade-controller:v0.13.1
    - name: registry.rancher.com/rancher/ui-plugin-catalog:1.3.0
    - name: registry.rancher.com/rancher/ui-plugin-operator:v0.1.1
    - name: registry.rancher.com/rancher/webhook-receiver:v0.2.5
    - name: registry.rancher.com/rancher/kubectl:v1.20.2

与包含 602 个容器映像的完整列表相比,此精简版本仅包含 62 个容器映像,因此新 CRB 映像的大小只有大约 7GB。

我们还需要为 Rancher 创建 Helm values 文件:

cat << EOF > $CONFIG_DIR/kubernetes/helm/values/rancher-values.yaml
hostname: 192.168.100.50.sslip.io
replicas: 1
bootstrapPassword: "adminadminadmin"
systemDefaultRegistry: registry.rancher.com
useBundledSystemChart: true
EOF
警告
警告

systemDefaultRegistry 设置为 registry.rancher.com 可让 Rancher 在引导时,在 CRB 映像内启动的嵌入式项目注册表中自动查找映像。省略此字段可能会导致无法在节点上找到容器映像。

我们来构建映像:

podman run --rm -it --privileged -v $CONFIG_DIR:/eib \
registry.suse.com/edge/edge-image-builder:1.0.2 \
build --definition-file eib-iso-definition.yaml

输出应如下所示:

Generating image customization components...
Identifier ................... [SUCCESS]
Custom Files ................. [SKIPPED]
Time ......................... [SKIPPED]
Network ...................... [SUCCESS]
Groups ....................... [SKIPPED]
Users ........................ [SUCCESS]
Proxy ........................ [SKIPPED]
Rpm .......................... [SKIPPED]
Systemd ...................... [SKIPPED]
Elemental .................... [SKIPPED]
Suma ......................... [SKIPPED]
Downloading file: dl-manifest-1.yaml 100% (437/437 kB, 17 MB/s)
Populating Embedded Artifact Registry... 100% (69/69, 26 it/min)
Embedded Artifact Registry ... [SUCCESS]
Keymap ....................... [SUCCESS]
Configuring Kubernetes component...
The Kubernetes CNI is not explicitly set, defaulting to 'cilium'.
Downloading file: rke2_installer.sh
Downloading file: rke2-images-core.linux-amd64.tar.zst 100% (780/780 MB, 115 MB/s)
Downloading file: rke2-images-cilium.linux-amd64.tar.zst 100% (367/367 MB, 108 MB/s)
Downloading file: rke2.linux-amd64.tar.gz 100% (34/34 MB, 117 MB/s)
Downloading file: sha256sum-amd64.txt 100% (3.9/3.9 kB, 34 MB/s)
Downloading file: dl-manifest-1.yaml 100% (437/437 kB, 106 MB/s)
Kubernetes ................... [SUCCESS]
Certificates ................. [SKIPPED]
Building ISO image...
Kernel Params ................ [SKIPPED]
Image build complete!

置备使用构建映像的节点后,可以校验 Rancher 安装:

/var/lib/rancher/rke2/bin/kubectl get all -A --kubeconfig /etc/rancher/rke2/rke2.yaml

输出应类似于以下内容,这表明已成功部署所有组件:

NAMESPACE                         NAME                                                        READY   STATUS      RESTARTS   AGE
cattle-fleet-local-system         pod/fleet-agent-68f4d5d5f7-tdlk7                            1/1     Running     0          34s
cattle-fleet-system               pod/fleet-controller-85564cc978-pbtvk                       1/1     Running     0          5m51s
cattle-fleet-system               pod/gitjob-9dc58fb5b-7cwsw                                  1/1     Running     0          5m51s
cattle-provisioning-capi-system   pod/capi-controller-manager-5c57b4b8f7-wlp5k                1/1     Running     0          4m52s
cattle-system                     pod/helm-operation-4fk5c                                    0/2     Completed   0          37s
cattle-system                     pod/helm-operation-6zgbq                                    0/2     Completed   0          4m54s
cattle-system                     pod/helm-operation-cjds5                                    0/2     Completed   0          5m37s
cattle-system                     pod/helm-operation-kt5c2                                    0/2     Completed   0          5m21s
cattle-system                     pod/helm-operation-ppgtw                                    0/2     Completed   0          5m30s
cattle-system                     pod/helm-operation-tvcwk                                    0/2     Completed   0          5m54s
cattle-system                     pod/helm-operation-wpxd4                                    0/2     Completed   0          53s
cattle-system                     pod/rancher-58575f9575-svrg2                                1/1     Running     0          6m34s
cattle-system                     pod/rancher-webhook-5c6556f7ff-vgmkt                        1/1     Running     0          5m19s
cert-manager                      pod/cert-manager-6c69f9f796-fkm8f                           1/1     Running     0          7m14s
cert-manager                      pod/cert-manager-cainjector-584f44558c-wg7p6                1/1     Running     0          7m14s
cert-manager                      pod/cert-manager-webhook-76f9945d6f-lv2nv                   1/1     Running     0          7m14s
endpoint-copier-operator          pod/endpoint-copier-operator-58964b659b-l64dk               1/1     Running     0          7m16s
endpoint-copier-operator          pod/endpoint-copier-operator-58964b659b-z9t9d               1/1     Running     0          7m16s
kube-system                       pod/cilium-fht55                                            1/1     Running     0          7m32s
kube-system                       pod/cilium-operator-558bbf6cfd-gwfwf                        1/1     Running     0          7m32s
kube-system                       pod/cilium-operator-558bbf6cfd-qsxb5                        0/1     Pending     0          7m32s
kube-system                       pod/cloud-controller-manager-host1.local                    1/1     Running     0          7m21s
kube-system                       pod/etcd-host1.local                                        1/1     Running     0          7m8s
kube-system                       pod/helm-install-cert-manager-fvbtt                         0/1     Completed   0          8m12s
kube-system                       pod/helm-install-endpoint-copier-operator-5kkgw             0/1     Completed   0          8m12s
kube-system                       pod/helm-install-metallb-zfphb                              0/1     Completed   0          8m12s
kube-system                       pod/helm-install-rancher-nc4nt                              0/1     Completed   2          8m12s
kube-system                       pod/helm-install-rke2-cilium-7wq87                          0/1     Completed   0          8m12s
kube-system                       pod/helm-install-rke2-coredns-nl4gc                         0/1     Completed   0          8m12s
kube-system                       pod/helm-install-rke2-ingress-nginx-svjqd                   0/1     Completed   0          8m12s
kube-system                       pod/helm-install-rke2-metrics-server-gqgqz                  0/1     Completed   0          8m12s
kube-system                       pod/helm-install-rke2-snapshot-controller-crd-r6b5p         0/1     Completed   0          8m12s
kube-system                       pod/helm-install-rke2-snapshot-controller-ss9v4             0/1     Completed   1          8m12s
kube-system                       pod/helm-install-rke2-snapshot-validation-webhook-vlkpn     0/1     Completed   0          8m12s
kube-system                       pod/kube-apiserver-host1.local                              1/1     Running     0          7m29s
kube-system                       pod/kube-controller-manager-host1.local                     1/1     Running     0          7m30s
kube-system                       pod/kube-proxy-host1.local                                  1/1     Running     0          7m30s
kube-system                       pod/kube-scheduler-host1.local                              1/1     Running     0          7m42s
kube-system                       pod/rke2-coredns-rke2-coredns-6c8d9bb6d-qlwc8               1/1     Running     0          7m31s
kube-system                       pod/rke2-coredns-rke2-coredns-autoscaler-55fb4bbbcf-j5r2z   1/1     Running     0          7m31s
kube-system                       pod/rke2-ingress-nginx-controller-4h2mm                     1/1     Running     0          7m3s
kube-system                       pod/rke2-metrics-server-544c8c66fc-lsrc6                    1/1     Running     0          7m15s
kube-system                       pod/rke2-snapshot-controller-59cc9cd8f4-4wx75               1/1     Running     0          7m14s
kube-system                       pod/rke2-snapshot-validation-webhook-54c5989b65-5kp2x       1/1     Running     0          7m15s
metallb-system                    pod/metallb-controller-5895d8446d-z54lm                     1/1     Running     0          7m15s
metallb-system                    pod/metallb-speaker-fxwgk                                   1/1     Running     0          7m15s

NAMESPACE                         NAME                                              TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)
         AGE
cattle-fleet-system               service/gitjob                                    ClusterIP      10.43.30.8      <none>            80/TCP
         5m51s
cattle-provisioning-capi-system   service/capi-webhook-service                      ClusterIP      10.43.7.100     <none>            443/TCP
         4m52s
cattle-system                     service/rancher                                   ClusterIP      10.43.100.229   <none>            80/TCP,443/TCP
         6m34s
cattle-system                     service/rancher-webhook                           ClusterIP      10.43.121.133   <none>            443/TCP
         5m19s
cert-manager                      service/cert-manager                              ClusterIP      10.43.140.65    <none>            9402/TCP
         7m14s
cert-manager                      service/cert-manager-webhook                      ClusterIP      10.43.108.158   <none>            443/TCP
         7m14s
default                           service/kubernetes                                ClusterIP      10.43.0.1       <none>            443/TCP
         8m26s
default                           service/kubernetes-vip                            LoadBalancer   10.43.138.138   192.168.100.151   9345:31006/TCP,6443:31599/TCP   8m21s
kube-system                       service/cilium-agent                              ClusterIP      None            <none>            9964/TCP
         7m32s
kube-system                       service/rke2-coredns-rke2-coredns                 ClusterIP      10.43.0.10      <none>            53/UDP,53/TCP
         7m31s
kube-system                       service/rke2-ingress-nginx-controller-admission   ClusterIP      10.43.157.19    <none>            443/TCP
         7m3s
kube-system                       service/rke2-metrics-server                       ClusterIP      10.43.4.123     <none>            443/TCP
         7m15s
kube-system                       service/rke2-snapshot-validation-webhook          ClusterIP      10.43.91.161    <none>            443/TCP
         7m16s
metallb-system                    service/metallb-webhook-service                   ClusterIP      10.43.71.192    <none>            443/TCP
         7m15s

NAMESPACE        NAME                                           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system      daemonset.apps/cilium                          1         1         1       1            1           kubernetes.io/os=linux   7m32s
kube-system      daemonset.apps/rke2-ingress-nginx-controller   1         1         1       1            1           kubernetes.io/os=linux   7m3s
metallb-system   daemonset.apps/metallb-speaker                 1         1         1       1            1           kubernetes.io/os=linux   7m15s

NAMESPACE                         NAME                                                   READY   UP-TO-DATE   AVAILABLE   AGE
cattle-fleet-local-system         deployment.apps/fleet-agent                            1/1     1            1           34s
cattle-fleet-system               deployment.apps/fleet-controller                       1/1     1            1           5m51s
cattle-fleet-system               deployment.apps/gitjob                                 1/1     1            1           5m51s
cattle-provisioning-capi-system   deployment.apps/capi-controller-manager                1/1     1            1           4m52s
cattle-system                     deployment.apps/rancher                                1/1     1            1           6m34s
cattle-system                     deployment.apps/rancher-webhook                        1/1     1            1           5m19s
cert-manager                      deployment.apps/cert-manager                           1/1     1            1           7m14s
cert-manager                      deployment.apps/cert-manager-cainjector                1/1     1            1           7m14s
cert-manager                      deployment.apps/cert-manager-webhook                   1/1     1            1           7m14s
endpoint-copier-operator          deployment.apps/endpoint-copier-operator               2/2     2            2           7m16s
kube-system                       deployment.apps/cilium-operator                        1/2     2            1           7m32s
kube-system                       deployment.apps/rke2-coredns-rke2-coredns              1/1     1            1           7m31s
kube-system                       deployment.apps/rke2-coredns-rke2-coredns-autoscaler   1/1     1            1           7m31s
kube-system                       deployment.apps/rke2-metrics-server                    1/1     1            1           7m15s
kube-system                       deployment.apps/rke2-snapshot-controller               1/1     1            1           7m14s
kube-system                       deployment.apps/rke2-snapshot-validation-webhook       1/1     1            1           7m15s
metallb-system                    deployment.apps/metallb-controller                     1/1     1            1           7m15s

NAMESPACE                         NAME                                                              DESIRED   CURRENT   READY   AGE
cattle-fleet-local-system         replicaset.apps/fleet-agent-68f4d5d5f7                            1         1         1       34s
cattle-fleet-system               replicaset.apps/fleet-controller-85564cc978                       1         1         1       5m51s
cattle-fleet-system               replicaset.apps/gitjob-9dc58fb5b                                  1         1         1       5m51s
cattle-provisioning-capi-system   replicaset.apps/capi-controller-manager-5c57b4b8f7                1         1         1       4m52s
cattle-system                     replicaset.apps/rancher-58575f9575                                1         1         1       6m34s
cattle-system                     replicaset.apps/rancher-webhook-5c6556f7ff                        1         1         1       5m19s
cert-manager                      replicaset.apps/cert-manager-6c69f9f796                           1         1         1       7m14s
cert-manager                      replicaset.apps/cert-manager-cainjector-584f44558c                1         1         1       7m14s
cert-manager                      replicaset.apps/cert-manager-webhook-76f9945d6f                   1         1         1       7m14s
endpoint-copier-operator          replicaset.apps/endpoint-copier-operator-58964b659b               2         2         2       7m16s
kube-system                       replicaset.apps/cilium-operator-558bbf6cfd                        2         2         1       7m32s
kube-system                       replicaset.apps/rke2-coredns-rke2-coredns-6c8d9bb6d               1         1         1       7m31s
kube-system                       replicaset.apps/rke2-coredns-rke2-coredns-autoscaler-55fb4bbbcf   1         1         1       7m31s
kube-system                       replicaset.apps/rke2-metrics-server-544c8c66fc                    1         1         1       7m15s
kube-system                       replicaset.apps/rke2-snapshot-controller-59cc9cd8f4               1         1         1       7m14s
kube-system                       replicaset.apps/rke2-snapshot-validation-webhook-54c5989b65       1         1         1       7m15s
metallb-system                    replicaset.apps/metallb-controller-5895d8446d                     1         1         1       7m15s

NAMESPACE     NAME                                                      COMPLETIONS   DURATION   AGE
kube-system   job.batch/helm-install-cert-manager                       1/1           85s        8m21s
kube-system   job.batch/helm-install-endpoint-copier-operator           1/1           59s        8m21s
kube-system   job.batch/helm-install-metallb                            1/1           60s        8m21s
kube-system   job.batch/helm-install-rancher                            1/1           100s       8m21s
kube-system   job.batch/helm-install-rke2-cilium                        1/1           44s        8m18s
kube-system   job.batch/helm-install-rke2-coredns                       1/1           45s        8m18s
kube-system   job.batch/helm-install-rke2-ingress-nginx                 1/1           76s        8m16s
kube-system   job.batch/helm-install-rke2-metrics-server                1/1           60s        8m16s
kube-system   job.batch/helm-install-rke2-snapshot-controller           1/1           61s        8m15s
kube-system   job.batch/helm-install-rke2-snapshot-controller-crd       1/1           60s        8m16s
kube-system   job.batch/helm-install-rke2-snapshot-validation-webhook   1/1           60s        8m14s

当我们访问 https://192.168.100.50.sslip.io 并使用先前设置的 adminadminadmin 口令登录后,Rancher 仪表板即会显示:

隔离式 Rancher

21.7 NeuVector 安装

与 Rancher 安装不同,NeuVector 安装不需要在 EIB 中进行任何特殊处理。EIB 将自动隔离 NeuVector 所需的每个映像。

创建定义文件:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$jHugJNNd3HElGsUZ$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
kubernetes:
  version: v1.28.9+rke2r1
  helm:
    charts:
      - name: neuvector-crd
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector-values.yaml
      - name: neuvector
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector-values.yaml
    repositories:
      - name: rancher-charts
        url: https://charts.rancher.io/

另外,为 NeuVector 创建 Helm values 文件:

cat << EOF > $CONFIG_DIR/kubernetes/helm/values/neuvector-values.yaml
controller:
  replicas: 1
manager:
  enabled: false
cve:
  scanner:
    enabled: false
    replicas: 1
k3s:
  enabled: true
crdwebhook:
  enabled: false
EOF

我们来构建映像:

podman run --rm -it --privileged -v $CONFIG_DIR:/eib \
registry.suse.com/edge/edge-image-builder:1.0.2 \
build --definition-file eib-iso-definition.yaml

输出应如下所示:

Generating image customization components...
Identifier ................... [SUCCESS]
Custom Files ................. [SKIPPED]
Time ......................... [SKIPPED]
Network ...................... [SUCCESS]
Groups ....................... [SKIPPED]
Users ........................ [SUCCESS]
Proxy ........................ [SKIPPED]
Rpm .......................... [SKIPPED]
Systemd ...................... [SKIPPED]
Elemental .................... [SKIPPED]
Suma ......................... [SKIPPED]
Populating Embedded Artifact Registry... 100% (6/6, 20 it/min)
Embedded Artifact Registry ... [SUCCESS]
Keymap ....................... [SUCCESS]
Configuring Kubernetes component...
The Kubernetes CNI is not explicitly set, defaulting to 'cilium'.
Downloading file: rke2_installer.sh
Kubernetes ................... [SUCCESS]
Certificates ................. [SKIPPED]
Building ISO image...
Kernel Params ................ [SKIPPED]
Image build complete!

置备使用构建映像的节点后,可以校验 NeuVector 安装:

/var/lib/rancher/rke2/bin/kubectl get all -n neuvector --kubeconfig /etc/rancher/rke2/rke2.yaml

输出应类似于以下内容,这表明已成功部署所有组件:

NAME                                           READY   STATUS    RESTARTS   AGE
pod/neuvector-controller-pod-bc74745cf-x9fsc   1/1     Running   0          13m
pod/neuvector-enforcer-pod-vzw7t               1/1     Running   0          13m

NAME                                      TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                         AGE
service/neuvector-svc-admission-webhook   ClusterIP   10.43.240.25   <none>        443/TCP                         13m
service/neuvector-svc-controller          ClusterIP   None           <none>        18300/TCP,18301/TCP,18301/UDP   13m

NAME                                    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/neuvector-enforcer-pod   1         1         1       1            1           <none>          13m

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/neuvector-controller-pod   1/1     1            1           13m

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/neuvector-controller-pod-bc74745cf   1         1         1       13m

NAME                                  SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob.batch/neuvector-updater-pod   0 0 * * *   False     0        <none>          13m

21.8 Longhorn 安装

Longhorn 的官方文档包含 longhorn-images.txt 文件,其中列出了隔离式安装所需的所有映像。我们将在定义文件中包含这些映像。我们来创建定义文件:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$jHugJNNd3HElGsUZ$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
kubernetes:
  version: v1.28.9+rke2r1
  helm:
    charts:
      - name: longhorn
        repositoryName: longhorn
        targetNamespace: longhorn-system
        createNamespace: true
        version: 1.6.1
    repositories:
      - name: longhorn
        url: https://charts.longhorn.io
embeddedArtifactRegistry:
  images:
    - name: longhornio/csi-attacher:v4.4.2
    - name: longhornio/csi-provisioner:v3.6.2
    - name: longhornio/csi-resizer:v1.9.2
    - name: longhornio/csi-snapshotter:v6.3.2
    - name: longhornio/csi-node-driver-registrar:v2.9.2
    - name: longhornio/livenessprobe:v2.12.0
    - name: longhornio/backing-image-manager:v1.6.1
    - name: longhornio/longhorn-engine:v1.6.1
    - name: longhornio/longhorn-instance-manager:v1.6.1
    - name: longhornio/longhorn-manager:v1.6.1
    - name: longhornio/longhorn-share-manager:v1.6.1
    - name: longhornio/longhorn-ui:v1.6.1
    - name: longhornio/support-bundle-kit:v0.0.36

我们来构建映像:

podman run --rm -it --privileged -v $CONFIG_DIR:/eib \
registry.suse.com/edge/edge-image-builder:1.0.2 \
build --definition-file eib-iso-definition.yaml

输出应如下所示:

Generating image customization components...
Identifier ................... [SUCCESS]
Custom Files ................. [SKIPPED]
Time ......................... [SKIPPED]
Network ...................... [SUCCESS]
Groups ....................... [SKIPPED]
Users ........................ [SUCCESS]
Proxy ........................ [SKIPPED]
Rpm .......................... [SKIPPED]
Systemd ...................... [SKIPPED]
Elemental .................... [SKIPPED]
Suma ......................... [SKIPPED]
Populating Embedded Artifact Registry... 100% (13/13, 20 it/min)
Embedded Artifact Registry ... [SUCCESS]
Keymap ....................... [SUCCESS]
Configuring Kubernetes component...
The Kubernetes CNI is not explicitly set, defaulting to 'cilium'.
Downloading file: rke2_installer.sh
Downloading file: rke2-images-core.linux-amd64.tar.zst 100% (782/782 MB, 108 MB/s)
Downloading file: rke2-images-cilium.linux-amd64.tar.zst 100% (367/367 MB, 104 MB/s)
Downloading file: rke2.linux-amd64.tar.gz 100% (34/34 MB, 108 MB/s)
Downloading file: sha256sum-amd64.txt 100% (3.9/3.9 kB, 7.5 MB/s)
Kubernetes ................... [SUCCESS]
Certificates ................. [SKIPPED]
Building ISO image...
Kernel Params ................ [SKIPPED]
Image build complete!

置备使用构建映像的节点后,可以校验 Longhorn 安装:

/var/lib/rancher/rke2/bin/kubectl get all -n longhorn-system --kubeconfig /etc/rancher/rke2/rke2.yaml

输出应类似于以下内容,这表明已成功部署所有组件:

NAME                                                    READY   STATUS    RESTARTS      AGE
pod/csi-attacher-5c4bfdcf59-9hgvv                       1/1     Running   0             35s
pod/csi-attacher-5c4bfdcf59-dt6jl                       1/1     Running   0             35s
pod/csi-attacher-5c4bfdcf59-swpwq                       1/1     Running   0             35s
pod/csi-provisioner-667796df57-dfrzw                    1/1     Running   0             35s
pod/csi-provisioner-667796df57-tvsrt                    1/1     Running   0             35s
pod/csi-provisioner-667796df57-xszsx                    1/1     Running   0             35s
pod/csi-resizer-694f8f5f64-6khlb                        1/1     Running   0             35s
pod/csi-resizer-694f8f5f64-gnr45                        1/1     Running   0             35s
pod/csi-resizer-694f8f5f64-sbl4k                        1/1     Running   0             35s
pod/csi-snapshotter-959b69d4b-2k4v8                     1/1     Running   0             35s
pod/csi-snapshotter-959b69d4b-9d8wl                     1/1     Running   0             35s
pod/csi-snapshotter-959b69d4b-l2w95                     1/1     Running   0             35s
pod/engine-image-ei-5cefaf2b-cwd8f                      1/1     Running   0             43s
pod/instance-manager-f0d17f96bc92f3cc44787a2a347f6a98   1/1     Running   0             43s
pod/longhorn-csi-plugin-szv7t                           3/3     Running   0             35s
pod/longhorn-driver-deployer-9f4fc86-q8fz2              1/1     Running   0             83s
pod/longhorn-manager-zp66l                              1/1     Running   0             83s
pod/longhorn-ui-5f4b7bbf69-k645d                        1/1     Running   3 (65s ago)   83s
pod/longhorn-ui-5f4b7bbf69-t7xt4                        1/1     Running   3 (62s ago)   83s

NAME                                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/longhorn-admission-webhook    ClusterIP   10.43.74.59    <none>        9502/TCP   83s
service/longhorn-backend              ClusterIP   10.43.45.206   <none>        9500/TCP   83s
service/longhorn-conversion-webhook   ClusterIP   10.43.83.108   <none>        9501/TCP   83s
service/longhorn-engine-manager       ClusterIP   None           <none>        <none>     83s
service/longhorn-frontend             ClusterIP   10.43.84.55    <none>        80/TCP     83s
service/longhorn-recovery-backend     ClusterIP   10.43.75.200   <none>        9503/TCP   83s
service/longhorn-replica-manager      ClusterIP   None           <none>        <none>     83s

NAME                                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/engine-image-ei-5cefaf2b   1         1         1       1            1           <none>          43s
daemonset.apps/longhorn-csi-plugin        1         1         1       1            1           <none>          35s
daemonset.apps/longhorn-manager           1         1         1       1            1           <none>          83s

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/csi-attacher               3/3     3            3           35s
deployment.apps/csi-provisioner            3/3     3            3           35s
deployment.apps/csi-resizer                3/3     3            3           35s
deployment.apps/csi-snapshotter            3/3     3            3           35s
deployment.apps/longhorn-driver-deployer   1/1     1            1           83s
deployment.apps/longhorn-ui                2/2     2            2           83s

NAME                                               DESIRED   CURRENT   READY   AGE
replicaset.apps/csi-attacher-5c4bfdcf59            3         3         3       35s
replicaset.apps/csi-provisioner-667796df57         3         3         3       35s
replicaset.apps/csi-resizer-694f8f5f64             3         3         3       35s
replicaset.apps/csi-snapshotter-959b69d4b          3         3         3       35s
replicaset.apps/longhorn-driver-deployer-9f4fc86   1         1         1       83s
replicaset.apps/longhorn-ui-5f4b7bbf69             2         2         2       83s

21.9 KubeVirt 和 CDI 安装

KubeVirt 和 CDI 的 Helm chart 只会安装各自的操作器。余下的系统将由操作器来部署,这意味着,我们必须在定义文件中包含所有必要的容器映像。我们来创建定义文件:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$jHugJNNd3HElGsUZ$eodjVe4te5ps44SVcWshdfWizrP.xAyd71CVEXazBJ/.v799/WRCBXxfYmunlBO2yp1hm/zb4r8EmnrrNCF.P/
kubernetes:
  version: v1.28.9+rke2r1
  helm:
    charts:
      - name: kubevirt-chart
        repositoryName: suse-edge
        version: 0.2.4
        targetNamespace: kubevirt-system
        createNamespace: true
        installationNamespace: kube-system
      - name: cdi-chart
        repositoryName: suse-edge
        version: 0.2.3
        targetNamespace: cdi-system
        createNamespace: true
        installationNamespace: kube-system
    repositories:
      - name: suse-edge
        url: oci://registry.suse.com/edge
embeddedArtifactRegistry:
  images:
    - name: registry.suse.com/suse/sles/15.5/cdi-uploadproxy:1.58.0-150500.6.12.1
    - name: registry.suse.com/suse/sles/15.5/cdi-uploadserver:1.58.0-150500.6.12.1
    - name: registry.suse.com/suse/sles/15.5/cdi-apiserver:1.58.0-150500.6.12.1
    - name: registry.suse.com/suse/sles/15.5/cdi-controller:1.58.0-150500.6.12.1
    - name: registry.suse.com/suse/sles/15.5/cdi-importer:1.58.0-150500.6.12.1
    - name: registry.suse.com/suse/sles/15.5/cdi-cloner:1.58.0-150500.6.12.1
    - name: registry.suse.com/suse/sles/15.5/virt-api:1.1.1-150500.8.12.1
    - name: registry.suse.com/suse/sles/15.5/virt-controller:1.1.1-150500.8.12.1
    - name: registry.suse.com/suse/sles/15.5/virt-launcher:1.1.1-150500.8.12.1
    - name: registry.suse.com/suse/sles/15.5/virt-handler:1.1.1-150500.8.12.1
    - name: registry.suse.com/suse/sles/15.5/virt-exportproxy:1.1.1-150500.8.12.1
    - name: registry.suse.com/suse/sles/15.5/virt-exportserver:1.1.1-150500.8.12.1

我们来构建映像:

podman run --rm -it --privileged -v $CONFIG_DIR:/eib \
registry.suse.com/edge/edge-image-builder:1.0.2 \
build --definition-file eib-iso-definition.yaml

输出应如下所示:

Generating image customization components...
Identifier ................... [SUCCESS]
Custom Files ................. [SKIPPED]
Time ......................... [SKIPPED]
Network ...................... [SUCCESS]
Groups ....................... [SKIPPED]
Users ........................ [SUCCESS]
Proxy ........................ [SKIPPED]
Rpm .......................... [SKIPPED]
Systemd ...................... [SKIPPED]
Elemental .................... [SKIPPED]
Suma ......................... [SKIPPED]
Populating Embedded Artifact Registry... 100% (13/13, 6 it/min)
Embedded Artifact Registry ... [SUCCESS]
Keymap ....................... [SUCCESS]
Configuring Kubernetes component...
The Kubernetes CNI is not explicitly set, defaulting to 'cilium'.
Downloading file: rke2_installer.sh
Kubernetes ................... [SUCCESS]
Certificates ................. [SKIPPED]
Building ISO image...
Kernel Params ................ [SKIPPED]
Image build complete!

置备使用构建映像的节点后,可以校验 KubeVirt 和 CDI 的安装。

校验 KubeVirt:

/var/lib/rancher/rke2/bin/kubectl get all -n kubevirt-system --kubeconfig /etc/rancher/rke2/rke2.yaml

输出应类似于以下内容,这表明已成功部署所有组件:

NAME                                   READY   STATUS    RESTARTS   AGE
pod/virt-api-7c45477984-z226r          1/1     Running   0          2m4s
pod/virt-controller-664d9986b5-8p8gm   1/1     Running   0          98s
pod/virt-controller-664d9986b5-v2n4h   1/1     Running   0          98s
pod/virt-handler-2fx8c                 1/1     Running   0          98s
pod/virt-operator-5cf69867dc-hz5s8     1/1     Running   0          2m30s
pod/virt-operator-5cf69867dc-kp266     1/1     Running   0          2m30s

NAME                                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubevirt-operator-webhook     ClusterIP   10.43.210.235   <none>        443/TCP   2m7s
service/kubevirt-prometheus-metrics   ClusterIP   None            <none>        443/TCP   2m7s
service/virt-api                      ClusterIP   10.43.226.140   <none>        443/TCP   2m7s
service/virt-exportproxy              ClusterIP   10.43.213.201   <none>        443/TCP   2m7s

NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/virt-handler   1         1         1       1            1           kubernetes.io/os=linux   98s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/virt-api          1/1     1            1           2m4s
deployment.apps/virt-controller   2/2     2            2           98s
deployment.apps/virt-operator     2/2     2            2           2m30s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/virt-api-7c45477984          1         1         1       2m4s
replicaset.apps/virt-controller-664d9986b5   2         2         2       98s
replicaset.apps/virt-operator-5cf69867dc     2         2         2       2m30s

校验 CDI:

/var/lib/rancher/rke2/bin/kubectl get all -n cdi-system --kubeconfig /etc/rancher/rke2/rke2.yaml

输出应类似于以下内容,这表明已成功部署所有组件:

NAME                                   READY   STATUS    RESTARTS   AGE
pod/cdi-apiserver-db465b888-mdsmm      1/1     Running   0          3m6s
pod/cdi-deployment-56c7d74995-vt9sw    1/1     Running   0          3m6s
pod/cdi-operator-55c74f4b86-gkt58      1/1     Running   0          3m10s
pod/cdi-uploadproxy-7d7b94b968-msg2h   1/1     Running   0          3m6s

NAME                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/cdi-api                  ClusterIP   10.43.161.135   <none>        443/TCP    3m6s
service/cdi-prometheus-metrics   ClusterIP   10.43.161.159   <none>        8080/TCP   3m6s
service/cdi-uploadproxy          ClusterIP   10.43.25.136    <none>        443/TCP    3m6s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cdi-apiserver     1/1     1            1           3m6s
deployment.apps/cdi-deployment    1/1     1            1           3m6s
deployment.apps/cdi-operator      1/1     1            1           3m10s
deployment.apps/cdi-uploadproxy   1/1     1            1           3m6s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/cdi-apiserver-db465b888      1         1         1       3m6s
replicaset.apps/cdi-deployment-56c7d74995    1         1         1       3m6s
replicaset.apps/cdi-operator-55c74f4b86      1         1         1       3m10s
replicaset.apps/cdi-uploadproxy-7d7b94b968   1         1         1       3m6s

21.10 查错

如果您在构建映像时遇到任何问题,或者想要进一步测试和调试该过程,请参见上游文档

第 IV 部分 第三方集成

如何集成第三方工具

  • 22 NATS
  • NATS 是为日益发展的超级互联世界而开发的连接技术。仅凭这一项技术,应用程序就能在云供应商、本地、边缘、Web 和移动设备的任意组合之间安全地通讯。NATS 由一系列开源产品组成,这些产品紧密集成,但可以轻松独立部署。NATS 已由全球数千家公司使用,涵盖微服务、边缘计算、移动通讯和 IoT 等用例,并可用于增强或取代传统的讯息交换。

  • 23 SLE Micro 上的 NVIDIA GPU
  • 本指南将演示如何通过预构建的开源驱动程序在 SLE Micro 5.5 上实现主机级别的 NVIDIA GPU 支持。这些驱动程序将植入到操作系统中,而不是由 NVIDIA 的 GPU Operator 动态加载。对于想要将部署所需的所有项目预先植入映像,并且不需要动态选择驱动程序版本(即,由用户通过 Kubernetes 选择驱动程序版本)的客户而言,此配置非常理想。本指南首先介绍如何将其他组件部署到已预先部署的系统,然后使用一个章节介绍如何通过 Edge Image Builder 将此配置嵌入到初始部署中。如果您不想了解基础知识并想要手动完成设置,请直接跳到该章节。

22 NATS

NATS 是为日益发展的超级互联世界而开发的连接技术。仅凭这一项技术,应用程序就能在云供应商、本地、边缘、Web 和移动设备的任意组合之间安全地通讯。NATS 由一系列开源产品组成,这些产品紧密集成,但可以轻松独立部署。NATS 已由全球数千家公司使用,涵盖微服务、边缘计算、移动通讯和 IoT 等用例,并可用于增强或取代传统的讯息交换。

22.1 体系结构

NATS 是能够在应用程序之间以讯息形式实现数据交换的基础架构。

22.1.1 NATS 客户端应用程序

应用程序可以使用 NATS 客户端库在不同的实例之间发布和订阅讯息,以及发出请求和做出答复。这些应用程序通常称作客户端应用程序

22.1.2 NATS 服务基础架构

NATS 服务由一个或多个 NATS 服务器进程提供,这些进程配置为彼此互连并提供 NATS 服务基础架构。NATS 服务基础架构可以从一个终端设备上运行的单个 NATS 服务器进程,扩展为由许多群集组成的全球公用超级群集,这些群集跨越所有主要云提供商和全球所有区域。

22.1.3 简单讯息交换设计

NATS 使应用程序能够通过发送和接收讯息来轻松进行通讯。这些讯息按照主题字符串进行寻址和标识,并且不依赖于网络位置。数据经过编码,并构造为由发布者发送的讯息。该讯息由一个或多个订阅者接收、解码和处理。

22.1.4 NATS JetStream

NATS 有一个称为 JetStream 的内置分布式保存系统。JetStream 旨在解决当今技术存在的流式传输问题 — 复杂性、脆弱性和可伸缩性不足的问题。JetStream 还能解决发布者和订阅者之间的耦合问题(订阅者需要启动并运行才能收到发布的讯息)。有关 NATS JetStream 的详细信息,请参见此处

22.2 安装

22.2.1 在 K3s 上安装 NATS

NATS 是为多种体系结构构建的,因此可以在 K3s 上轻松安装。(第 13 章 “K3s

我们创建 values 文件来重写 NATS 的默认值。

cat > values.yaml <<EOF
cluster:
  # Enable the HA setup of the NATS
  enabled: true
  replicas: 3

nats:
  jetstream:
    # Enable JetStream
    enabled: true

    memStorage:
      enabled: true
      size: 2Gi

    fileStorage:
      enabled: true
      size: 1Gi
      storageDirectory: /data/
EOF

现在我们需要通过 Helm 安装 NATS:

helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm install nats nats/nats --namespace nats --values values.yaml \
 --create-namespace

在上面创建的 values.yaml 文件中,需将以下组件放在 nats 名称空间中:

  1. HA 版本的 NATS 有状态副本集,其中包含三个容器:NATS 服务器、配置重载器和指标分支。

  2. NATS 箱容器,其中附带一组可用于校验设置的 NATS 实用程序。

  3. JetStream 还会利用其键值后端,该后端附带与 Pod 绑定的 PVC

22.2.1.1 测试设置

kubectl exec -n nats -it deployment/nats-box -- /bin/sh -l
  1. 为测试主题创建订阅:

    nats sub test &
  2. 向测试对象发送讯息:

    nats pub test hi

22.2.1.2 清理

helm -n nats uninstall nats
rm values.yaml

22.2.2 NATS 用作 K3s 的后端

K3s 利用的一个组件是 KINE,它是一个填充码,用于将 etcd 替换为最初面向关系数据库的备用存储后端。由于 JetStream 提供了键值 API,因此可以将 NATS 用作 K3s 群集的后端。

有一个已经合并的 PR 可以直接将内置的 NATS 包含在 K3s 中,但这项更改仍未包含在 K3s 版本中。

出于此原因,应该手动构建 K3s 二进制文件。

本教程使用了 SLE Micro on OSX on Apple Silicon (UTM) VM。

注意
注意

在 OSX PC 上运行以下命令。

22.2.2.1 构建 K3s

git clone --depth 1 https://github.com/k3s-io/k3s.git && cd k3s

以下命令在构建标记中添加 nats,以在 K3s 中启用 NATS 内置功能:

sed -i '' 's/TAGS="ctrd/TAGS="nats ctrd/g' scripts/build
make local

请将 <node-ip> 替换为启动 K3s 的节点的实际 IP:

export NODE_IP=<node-ip>
sudo scp dist/artifacts/k3s-arm64 ${NODE_IP}:/usr/local/bin/k3s
注意
注意

在本地构建 K3s 需要 buildx Docker CLI 插件。如果 $ make local 失败,可以手动安装该插件。

22.2.2.2 安装 NATS CLI

TMPDIR=$(mktemp -d)
nats_version="nats-0.0.35-linux-arm64"
curl -o "${TMPDIR}/nats.zip" -sfL https://github.com/nats-io/natscli/releases/download/v0.0.35/${nats_version}.zip
unzip "${TMPDIR}/nats.zip" -d "${TMPDIR}"

sudo scp ${TMPDIR}/${nats_version}/nats ${NODE_IP}:/usr/local/bin/nats
rm -rf ${TMPDIR}

22.2.2.3 运行用作 K3s 后端的 NATS

我们需要在节点上通过 ssh 进行连接,并使用指向 nats--datastore-endpoint 标志运行 K3s。

注意
注意

以下命令将 K3s 作为前台进程启动,因此您可以轻松地通过日志来查看是否出现了任何问题。为了不阻碍当前终端,可以在该命令的前面添加 & 标志,以将其作为后台进程启动。

k3s server  --datastore-endpoint=nats://
注意
注意

为了将使用 NATS 后端的 K3s 服务器永久保留在您的 slemicro VM 上,可以运行以下脚本,以创建包含所需配置的 systemd 服务。

export INSTALL_K3S_SKIP_START=false
export INSTALL_K3S_SKIP_DOWNLOAD=true

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server \
 --datastore-endpoint=nats://"  sh -

22.2.2.4 查错

可以在节点上运行以下命令来校验流中的所有操作是否正常进行:

nats str report -a
nats str view -a

23 SLE Micro 上的 NVIDIA GPU

23.1 简介

本指南将演示如何通过预构建的开源驱动程序在 SLE Micro 5.5 上实现主机级别的 NVIDIA GPU 支持。这些驱动程序将植入到操作系统中,而不是由 NVIDIA 的 GPU Operator 动态加载。对于想要将部署所需的所有项目预先植入映像,并且不需要动态选择驱动程序版本(即,由用户通过 Kubernetes 选择驱动程序版本)的客户而言,此配置非常理想。本指南首先介绍如何将其他组件部署到已预先部署的系统,然后使用一个章节介绍如何通过 Edge Image Builder 将此配置嵌入到初始部署中。如果您不想了解基础知识并想要手动完成设置,请直接跳到该章节。

必须指出的是,这些驱动程序的支持工作由 SUSE 和 NVIDIA 在密切合作的前提下提供,而驱动程序由 SUSE 构建并作为软件包储存库的一部分交付。但是,如果您在使用驱动程序期间在这两方面有任何疑虑或问题,请咨询您的 SUSE 或 NVIDIA 客户经理以获得进一步的帮助。如果您打算使用 NVIDIA AI Enterprise (NVAIE),请确保使用 NVAIE 认证的 GPU,这可能需要使用专有的 NVIDIA 驱动程序。如果您不确定,请咨询您的 NVIDIA 代表。

本指南不会介绍有关 NVIDIA GPU Operator 集成的更多信息。虽然其中不会介绍如何为 Kubernetes 集成 NVIDIA GPU Operator,但您仍然可以按照本指南中的大部分步骤来设置底层操作系统,并通过 NVIDIA GPU Operator Helm chart 中的 driver.enabled=false 标志来让 GPU Operator 使用预安装的驱动程序,在这种情况下,GPU Operator 会直接选择主机上安装的驱动程序。NVIDIA 在此处提供了更详细的说明。SUSE 最近还发布了一份技术参考文档 (TRD),其中介绍了如何使用 GPU Operator 和 NVIDIA 专有的驱动程序,您可以根据用例的要求参考此文档。

23.2 先决条件

如果您要学习本指南,事先需要做好以下准备:

  • 至少一台装有 SLE Micro 5.5 的主机,可以是物理主机,也可以是虚拟主机。

  • 您的主机已附加到某个订阅,只有这样,才能访问软件包 — 可在此处进行评估。

  • 已安装兼容的 NVIDIA GPU(或完全直通到运行 SLE Micro 的虚拟机)。

  • root 用户访问权限 — 本章中的说明假设您是 root 用户,而不是通过 sudo 提升了的特权。

23.3 手动安装

本节介绍如何直接将 NVIDIA 驱动程序安装到 SLE Micro 操作系统上,因为 NVIDIA 开放驱动程序现在包含在核心 SLE Micro 软件包储存库中,因此,只需安装所需的 RPM 软件包就能安装这些驱动程序。无需编译或下载可执行软件包。下面介绍如何部署支持最新 GPU 的第六代 (G06) 驱动程序(有关更多信息,请参见此处),请选择适合您系统中的 NVIDIA GPU 的驱动程序代系。对于新式 GPU,“G06”驱动程序是最常见的选择。

在开始之前,必须知道的是,除了 SUSE 作为 SLE Micro 一部分交付的 NVIDIA 开放驱动程序之外,您可能还需要将其他 NVIDIA 组件用于设置。这些组件可能包括 OpenGL 库、CUDA 工具包、命令行实用程序(例如 nvidia-smi)和容器集成组件(例如 nvidia-container-toolkit)。其中许多组件不是由 SUSE 交付,因为它们是专有的 NVIDIA 软件,或者我们代替 NVIDIA 交付这些软件毫无意义。因此在说明中,我们将配置其他一些用于访问所述组件的储存库,并讲解一些示例来介绍这些工具的用法,以得到一个功能完备的系统。必须能够区分 SUSE 储存库和 NVIDIA 储存库,因为 NVIDIA 提供的软件包版本与 SUSE 构建的版本有时不匹配。这种情况通常发生在 SUSE 推出新的开放驱动程序版本时,需要经过几天时间,NVIDIA 储存库中才会提供匹配的同等软件包。

我们建议您采取以下措施来确保所选驱动程序版本与您的 GPU 兼容并符合现有的任何 CUDA 要求:

提示
提示

要查找 NVIDIA 开放驱动程序版本,请在目标计算机上运行 zypper se -s nvidia-open-driver或者SLE Micro 5.5 for x86_64 的 SUSE Customer Center 中搜索“nvidia-open-driver”。

在此处,您会看到四个可用版本,其中 545.29.06 是最新版本:

SUSE Customer Center

在确认 NVIDIA 储存库中提供了同等版本后,便可以在主机操作系统上安装软件包了。为此,需要打开 transactional-update 会话,它会创建底层操作系统的新读/写快照,以便我们可以对不可变平台进行更改(有关 transactional-update 的更多说明,请参见此处):

transactional-update shell

在进入 transactional-update 外壳后,从 NVIDIA 添加其他软件包储存库。这样就可以提取其他实用程序,例如 nvidia-smi

zypper ar https://download.nvidia.com/suse/sle15sp5/ nvidia-sle15sp5-main
zypper --gpg-auto-import-keys refresh

然后,可以安装驱动程序,并安装 nvidia-compute-utils 来获取其他实用程序。如果您不需要这些实用程序,可以忽略其安装,但为了稍后进行测试,最好现在就安装它们:

zypper install -y --auto-agree-with-licenses nvidia-open-driver-G06-signed-kmp nvidia-compute-utils-G06
注意
注意

如果安装失败,可能表明所选驱动程序版本与 NVIDIA 在其储存库中提供的版本之间存在依赖关系不匹配情况。请参见上一节来校验您的版本是否匹配。尝试安装不同的驱动程序版本。例如,如果 NVIDIA 储存库中有较低的版本,您可以尝试在 install 命令中指定 nvidia-open-driver-G06-signed-kmp=545.29.06,以指定一致的版本。

接下来,如果您使用支持的 GPU(请记住,可在此处找到列表),可以通过启用模块级别的支持来查看驱动程序是否有效,但每个用户的情况有所不同 - 如果您使用的是支持的 GPU,请跳过此步骤:

sed -i '/NVreg_OpenRmEnableUnsupportedGpus/s/^#//g' /etc/modprobe.d/50-nvidia-default.conf

安装这些软件包后,请退出 transactional-update 会话:

exit
注意
注意

在继续之前,请确保已退出 transactional-update 会话。

安装驱动程序后,接下来请重引导。由于 SLE Micro 是不可变的操作系统,因此它需要重引导至您在上一步骤中创建的新快照。驱动程序只会安装到此新快照中,因此如果不重引导至此新快照(会自动重引导),就无法加载驱动程序。准备就绪后,发出 reboot 命令:

reboot

系统成功重引导后,请重新登录并使用 nvidia-smi 工具校验驱动程序是否已成功加载,以及它是否可以访问和枚举您的 GPU:

nvidia-smi

此命令应显示如下所示的输出,请注意,以下示例中显示了两个 GPU:

Wed Feb 28 12:31:06 2024
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 545.29.06              Driver Version: 545.29.06    CUDA Version: 12.3     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  NVIDIA A100-PCIE-40GB          Off | 00000000:17:00.0 Off |                    0 |
| N/A   29C    P0              35W / 250W |      4MiB / 40960MiB |      0%      Default |
|                                         |                      |             Disabled |
+-----------------------------------------+----------------------+----------------------+
|   1  NVIDIA A100-PCIE-40GB          Off | 00000000:CA:00.0 Off |                    0 |
| N/A   30C    P0              33W / 250W |      4MiB / 40960MiB |      0%      Default |
|                                         |                      |             Disabled |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|  No running processes found                                                           |
+---------------------------------------------------------------------------------------+

在 SLE Micro 系统上安装和校验 NVIDIA 驱动程序的过程到此结束。

23.4 进一步验证手动安装

在此阶段,我们只能确认的是,在主机级别,可以访问 NVIDIA 设备,并且驱动程序可以成功加载。但是,如果我们想要确保设备正常运行,可以通过一项简单测试来验证 GPU 是否可以从用户空间应用程序接收指令,最好是通过容器和 CUDA 库接收,因为实际工作负载通常使用这种方法。为此,我们可以通过安装 nvidia-container-toolkit (NVIDIA Container Toolkit) 来进一步修改主机操作系统。首先,打开另一个 transactional-update 外壳,请注意,在上一步骤中我们可能是通过单个事务执行了此操作,后面的章节将介绍如何完全自动地执行此操作:

transactional-update shell

接下来,从 NVIDIA Container Toolkit 储存库安装 nvidia-container-toolkit 软件包:

  • 下面的 nvidia-container-toolkit.repo 包含稳定储存库 (nvidia-container-toolkit) 和实验性储存库 (nvidia-container-toolkit-experimental)。对于生产用途,建议使用稳定储存库。默认会禁用实验性储存库。

zypper ar https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo
zypper --gpg-auto-import-keys install -y nvidia-container-toolkit

准备就绪后,可以退出 transactional-update 外壳:

exit

... 然后将计算机重引导至新快照:

reboot
注意
注意

如前所述,需确保已退出 transactional-update 外壳并重引导计算机,使更改生效。

重引导计算机后,可以校验系统是否可以使用 NVIDIA Container Toolkit 成功枚举设备。输出应该非常详细,包含 INFO 和 WARN 讯息,但不包含 ERROR 讯息:

nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

这会确保计算机上启动的任何容器都可以采用已发现的 NVIDIA GPU 设备。准备就绪后,可以运行基于 podman 的容器。通过 podman 执行此操作可以方便地从容器内部验证对 NVIDIA 设备的访问,稍后还可以自信地对 Kubernetes 执行同样的操作。根据 SLE BCI,为 podman 授予对上一条命令处理过的带标签 NVIDIA 设备的访问权限,然后直接运行 Bash 命令:

podman run --rm --device nvidia.com/gpu=all --security-opt=label=disable -it registry.suse.com/bci/bci-base:latest bash

现在,您将从临时 podman 容器内部执行命令。该容器无权访问您的底层系统,并且是临时性的,因此我们在此处执行的所有操作都不会保存,并且您无法破坏底层主机上的任何设置。由于我们现在处于容器中,因此可以安装所需的 CUDA 库。请再次对照此页面检查驱动程序的 CUDA 版本是否正确,不过,先前 nvidia-smi 命令的输出应该也会显示所需的 CUDA 版本。以下示例将安装 CUDA 12.3 并提取许多示例、演示和开发包,以便您可以全面验证 GPU:

zypper ar http://developer.download.nvidia.com/compute/cuda/repos/sles15/x86_64/ cuda-sle15-sp5
zypper in -y cuda-libraries-devel-12-3 cuda-minimal-build-12-3 cuda-demo-suite-12-3

成功安装后,请不要退出容器。我们将运行 deviceQuery CUDA 示例,它会全面验证通过 CUDA 以及从容器本身内部进行 GPU 访问的情况:

/usr/local/cuda-12/extras/demo_suite/deviceQuery

如果成功,您应会看到如下所示的输出,请注意命令结束后返回的 Result = PASS 讯息,并注意在以下输出中,系统正确识别了两个 GPU,而您的环境中可能只有一个 GPU:

/usr/local/cuda-12/extras/demo_suite/deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 2 CUDA Capable device(s)

Device 0: "NVIDIA A100-PCIE-40GB"
  CUDA Driver Version / Runtime Version          12.2 / 12.1
  CUDA Capability Major/Minor version number:    8.0
  Total amount of global memory:                 40339 MBytes (42298834944 bytes)
  (108) Multiprocessors, ( 64) CUDA Cores/MP:     6912 CUDA Cores
  GPU Max Clock rate:                            1410 MHz (1.41 GHz)
  Memory Clock rate:                             1215 Mhz
  Memory Bus Width:                              5120-bit
  L2 Cache Size:                                 41943040 bytes
  Maximum Texture Dimension Size (x,y,z)         1D=(131072), 2D=(131072, 65536), 3D=(16384, 16384, 16384)
  Maximum Layered 1D Texture Size, (num) layers  1D=(32768), 2048 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(32768, 32768), 2048 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total number of registers available per block: 65536
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  2048
  Maximum number of threads per block:           1024
  Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
  Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 3 copy engine(s)
  Run time limit on kernels:                     No
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Enabled
  Device supports Unified Addressing (UVA):      Yes
  Device supports Compute Preemption:            Yes
  Supports Cooperative Kernel Launch:            Yes
  Supports MultiDevice Co-op Kernel Launch:      Yes
  Device PCI Domain ID / Bus ID / location ID:   0 / 23 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

Device 1: <snip to reduce output for multiple devices>
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >
> Peer access from NVIDIA A100-PCIE-40GB (GPU0) -> NVIDIA A100-PCIE-40GB (GPU1) : Yes
> Peer access from NVIDIA A100-PCIE-40GB (GPU1) -> NVIDIA A100-PCIE-40GB (GPU0) : Yes

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 12.3, CUDA Runtime Version = 12.3, NumDevs = 2, Device0 = NVIDIA A100-PCIE-40GB, Device1 = NVIDIA A100-PCIE-40GB
Result = PASS

在此处,您可以继续运行任何其他 CUDA 工作负载 — 使用编译器以及 CUDA 生态系统的任何其他方面来运行进一步的测试。完成后,可以退出容器,请注意您在容器中安装的任何内容都是临时性的(因此会丢失!),并且底层操作系统不会受到影响:

exit

23.5 使用 Kubernetes 实现

确认已在 SLE Micro 上安装并使用 NVIDIA 开放驱动程序后,我们来了解如何在同一台计算机上配置 Kubernetes。本指南不会指导您部署 Kubernetes,但假设您已安装 K3sRKE2,并且已相应地配置 kubeconfig,以便能够以超级用户的身份执行标准 kubectl 命令。假设您的节点构成了单节点群集,不过,对多节点群集可以使用类似的核心步骤。首先,请确保可以正常进行 kubectl 访问:

kubectl get nodes

此命令应会显示如下所示的输出:

NAME       STATUS   ROLES                       AGE   VERSION
node0001   Ready    control-plane,etcd,master   13d   v1.28.9+rke2r1

您会发现,k3s/rke2 安装已检测到主机上的 NVIDIA Container Toolkit,并已将 NVIDIA 运行时集成自动配置到 containerd(k3s/rke2 使用的容器运行时接口)中。这一点可以通过检查 containerd config.toml 文件来确认:

tail -n8 /var/lib/rancher/rke2/agent/etc/containerd/config.toml

此命令必须显示如下所示的内容。同等的 K3s 位置是 /var/lib/rancher/k3s/agent/etc/containerd/config.toml

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes."nvidia"]
  runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes."nvidia".options]
  BinaryName = "/usr/bin/nvidia-container-runtime"
注意
注意

如果未显示这些项,则可能表示检测失败。原因可能是计算机或 Kubernetes 服务未重启动。如果需要,请如前所述手动添加这些项。

接下来,我们需要将作为附加 Kubernetes 运行时的 NVIDIA RuntimeClass 配置为默认设置,以确保需要访问 GPU 的任何用户 Pod 请求都可以按照 containerd 配置中的配置,使用 NVIDIA Container Toolkit 通过 nvidia-container-runtime 进行这种访问:

kubectl apply -f - <<EOF
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: nvidia
handler: nvidia
EOF

下一步是配置 NVIDIA Device Plugin,该插件会将 Kubernetes 配置为利用 NVIDIA GPU 作为群集中可用的资源,并与 NVIDIA Container Toolkit 配合工作。此工具最初会检测底层主机上的所有功能,包括 GPU、驱动程序和其他功能(例如 GL),然后允许您请求 GPU 资源并将其用作应用程序的一部分。

首先,需要添加并更新 NVIDIA Device Plugin 的 Helm 储存库:

helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo update

现在可以安装 NVIDIA Device Plugin:

helm upgrade -i nvdp nvdp/nvidia-device-plugin --namespace nvidia-device-plugin --create-namespace --version 0.14.5 --set runtimeClassName=nvidia

几分钟后,您会看到一个新的 Pod 正在运行,它将在可用节点上完成检测,并根据检测到的 GPU 数量来标记节点:

kubectl get pods -n nvidia-device-plugin
NAME                              READY   STATUS    RESTARTS      AGE
nvdp-nvidia-device-plugin-jp697   1/1     Running   2 (12h ago)   6d3h

kubectl get node node0001 -o json | jq .status.capacity
{
  "cpu": "128",
  "ephemeral-storage": "466889732Ki",
  "hugepages-1Gi": "0",
  "hugepages-2Mi": "0",
  "memory": "32545636Ki",
  "nvidia.com/gpu": "1",                      <----
  "pods": "110"
}

现在,可以创建一个 NVIDIA Pod 来尝试使用此 GPU。我们来尝试在 CUDA 基准容器上执行此操作:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: nbody-gpu-benchmark
  namespace: default
spec:
  restartPolicy: OnFailure
  runtimeClassName: nvidia
  containers:
  - name: cuda-container
    image: nvcr.io/nvidia/k8s/cuda-sample:nbody
    args: ["nbody", "-gpu", "-benchmark"]
    resources:
      limits:
        nvidia.com/gpu: 1
    env:
    - name: NVIDIA_VISIBLE_DEVICES
      value: all
    - name: NVIDIA_DRIVER_CAPABILITIES
      value: all
EOF

如果一切顺利,您可以在日志中看到基准测试信息:

kubectl logs nbody-gpu-benchmark
Run "nbody -benchmark [-numbodies=<numBodies>]" to measure performance.
	-fullscreen       (run n-body simulation in fullscreen mode)
	-fp64             (use double precision floating point values for simulation)
	-hostmem          (stores simulation data in host memory)
	-benchmark        (run benchmark to measure performance)
	-numbodies=<N>    (number of bodies (>= 1) to run in simulation)
	-device=<d>       (where d=0,1,2.... for the CUDA device to use)
	-numdevices=<i>   (where i=(number of CUDA devices > 0) to use for simulation)
	-compare          (compares simulation results running once on the default GPU and once on the CPU)
	-cpu              (run n-body simulation on the CPU)
	-tipsy=<file.bin> (load a tipsy model file for simulation)

NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
GPU Device 0: "Turing" with compute capability 7.5

> Compute 7.5 CUDA device: [Tesla T4]
40960 bodies, total time for 10 iterations: 101.677 ms
= 165.005 billion interactions per second
= 3300.103 single-precision GFLOP/s at 20 flops per interaction

最后,如果您的应用程序需要 OpenGL,您可以在主机级别安装所需的 NVIDIA OpenGL 库,然后 NVIDIA Device Plugin 和 NVIDIA Container Toolkit 可将这些库提供给容器。为此,请如下所示安装软件包:

transactional-update pkg install nvidia-gl-G06
注意
注意

需要重引导才能将此软件包提供给应用程序。NVIDIA Device Plugin 会通过 NVIDIA Container Toolkit 自动重新检测此软件包。

23.6 通过 Edge Image Builder 将所有组件融合到一起

现在您已展示了您的应用程序和 GPU 在 SLE Micro 上的完整功能,接下来可以使用第 9 章 “Edge Image Builder通过可部署/可使用的 ISO 或 RAW 磁盘映像将它们作为一个整体来提供。本指南不会介绍如何使用 Edge Image Builder,但它提供了构建此类映像所需的配置。下面提供了映像定义的示例以及所需的 Kubernetes 配置文件,以确保可以现成地部署所有必要的组件。下面是该示例的 Edge Image Builder 目录结构:

.
├── base-images
│   └── SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso
├── eib-config-iso.yaml
├── kubernetes
│   ├── config
│   │   └── server.yaml
│   ├── helm
│   │   └── values
│   │       └── nvidia-device-plugin.yaml
│   └── manifests
│       └── nvidia-runtime-class.yaml
└── rpms
    └── gpg-keys
        └── nvidia-container-toolkit.key

我们来浏览这些文件。首先,这是一个运行 K3s 的单节点群集的示例映像定义,它还会部署实用程序和 OpenGL 软件包 (eib-config-iso.yaml):

apiVersion: 1.0
image:
  arch: x86_64
  imageType: iso
  baseImage: SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso
  outputImageName: deployimage.iso
operatingSystem:
  time:
    timezone: Europe/London
    ntp:
      pools:
        - 2.suse.pool.ntp.org
  isoConfiguration:
    installDevice: /dev/sda
  users:
    - username: root
      encryptedPassword: $6$XcQN1xkuQKjWEtQG$WbhV80rbveDLJDz1c93K5Ga9JDjt3mF.ZUnhYtsS7uE52FR8mmT8Cnii/JPeFk9jzQO6eapESYZesZHO9EslD1
  packages:
    packageList:
      - nvidia-open-driver-G06-signed-kmp-default
      - nvidia-compute-utils-G06
      - nvidia-gl-G06
      - nvidia-container-toolkit
    additionalRepos:
      - url: https://download.nvidia.com/suse/sle15sp5/
      - url: https://nvidia.github.io/libnvidia-container/stable/rpm/x86_64
    sccRegistrationCode: <snip>
kubernetes:
  version: v1.28.9+k3s1
  helm:
    charts:
      - name: nvidia-device-plugin
        version: v0.14.5
        installationNamespace: kube-system
        targetNamespace: nvidia-device-plugin
        createNamespace: true
        valuesFile: nvidia-device-plugin.yaml
        repositoryName: nvidia
    repositories:
      - name: nvidia
        url: https://nvidia.github.io/k8s-device-plugin
注意
注意

这只是一个示例。您可能需要根据自己的要求和期望对其进行自定义。此外,如果使用 SLE Micro,则您需要提供自己的 sccRegistrationCode 来解析软件包依赖项并提取 NVIDIA 驱动程序。

除此之外,还需要添加其他组件,供 Kubernetes 在引导时加载。首先需要为 EIB 目录创建 kubernetes 目录,其中包含配置、Helm chart 值和任何其他所需清单的子目录:

mkdir -p kubernetes/config kubernetes/helm/values kubernetes/manifests

现在我们来通过选择 CNI(如果未选择,则默认为 Cilium)并启用 SELinux 来设置(可选的)Kubernetes 配置:

cat << EOF > kubernetes/config/server.yaml
cni: cilium
selinux: true
EOF

现在确保在 Kubernetes 群集上创建 NVIDIA RuntimeClass:

cat << EOF > kubernetes/manifests/nvidia-runtime-class.yaml
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: nvidia
handler: nvidia
EOF

我们将使用内置的 Helm 控制器通过 Kubernetes 本身来部署 NVIDIA Device Plugin。我们需要在 chart 的 values 文件中提供运行时类:

cat << EOF > kubernetes/helm/values/nvidia-device-plugin.yaml
runtimeClassName: nvidia
EOF

在继续之前,我们需要抓取 NVIDIA Container Toolkit RPM 公共密钥:

mkdir -p rpms/gpg-keys
curl -o rpms/gpg-keys/nvidia-container-toolkit.key https://nvidia.github.io/libnvidia-container/gpgkey

系统会自动隔离所有必要的项目,包括 Kubernetes 二进制文件、容器映像、Helm chart(以及所有引用的映像),这意味着在部署时,系统默认不需要互联网连接。现在您只需从 SUSE 下载页面抓取 SLE Micro ISO(并将其放入 base-images 目录),然后可以调用 Edge Image Builder 工具来生成 ISO。为完成本示例,使用了以下命令来构建映像:

podman run --rm --privileged -it -v /path/to/eib-files/:/eib \
registry.suse.com/edge/edge-image-builder:1.0.2 \
build --definition-file eib-config-iso.yaml

有关更多说明,请参见 Edge Image Builder 的文档

23.7 解决问题

23.7.1 nvidia-smi 找不到 GPU

使用 dmesg 检查内核讯息。如果讯息指出无法分配 NvKMSKapDevice,请运用“GPU 不受支持”解决方法:

sed -i '/NVreg_OpenRmEnableUnsupportedGpus/s/^#//g' /etc/modprobe.d/50-nvidia-default.conf

注意:如果您在上述步骤中更改了内核模块配置,则需要重新加载或重引导内核模块才能使更改生效。

第 V 部分 Day 2 操作

本章介绍管理员如何在管理群集和下游群集上处理不同的“Day 2”操作任务。

  • 24 管理群集
  • 本章介绍如何在管理群集上执行各种 Day 2 操作。

  • 25 下游群集
  • 本章介绍如何使用管理群集对下游群集的不同组件执行各种 Day 2 操作。

24 管理群集

本章介绍如何在管理群集上执行各种 Day 2 操作。

24.1 RKE2 升级

注意
注意

为了确保能够实现灾难恢复,我们建议备份 RKE2 群集数据。有关如何执行此操作的信息,请查看此页面rke2 二进制文件的默认位置为 /opt/rke2/bin

可以使用 RKE2 安装脚本升级 RKE2 版本,如下所示:

curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=vX.Y.Z+rke2rN sh -

安装后请记得重启动 rke2 进程:

# For server nodes:
systemctl restart rke2-server

# For agent nodes:
systemctl restart rke2-agent
重要
重要

为了避免任何不可预见的升级问题,请遵循以下节点升级顺序:

  1. 服务器节点 - 应每次升级一个节点。

  2. 代理节点 - 应在完成所有服务器节点升级之后进行升级。可以同时升级。

有关更多信息,请参见 RKE2 升级文档

24.2 操作系统升级

注意
注意

本节假设您已将系统注册到 https://scc.suse.com

SUSE 定期发布新的 SLE Micro 软件包更新。SLE Micro 使用 transactional-upgrade 来检索更新的软件包版本。

transactional-upgrade 提供应用程序和库来以事务方式更新 Linux 操作系统,也就是说,更新将在后台执行,同时系统可以照常继续运行。只有在重引导系统后,更新才会生效。有关更多信息,请参见 transactional-update GitHub 页面。

要更新系统中的所有软件包,请执行::

transactional-update

由于重引导节点会导致它有一段时间不可用,如果您运行的是多节点群集,可以先封锁清空节点,然后再重引导

要封锁节点,请执行::

kubectl cordon <node>

这会导致将该节点移出默认调度机制,以确保不会错误地将任何 Pod 分配到该节点。

要清空节点,请执行::

kubectl drain <node>

这可以确保将该节点上的所有工作负载转移到其他可用节点。

注意
注意

根据您在节点上运行的工作负载,可能还需要在命令中提供其他标志(例如 --delete-emptydir-data--ignore-daemonsets)。

重引导节点:

sudo reboot

成功重引导后,该节点上的软件包将会更新。唯一剩下的操作就是使用 uncordon 命令将该节点放回到默认调度机制。

解封节点::

kubectl uncordon <node>

注意
注意

如果您要撤销更新,请使用以下 transactional-update 命令执行上述步骤:

transactional-update rollback last

24.3 Helm 升级

注意
注意

本节假设您已在系统上安装 helm。有关 helm 安装说明,请查看此页面

本节介绍如何升级通过 EIB 部署的(第 24.3.1 节 “通过 EIB 部署的 Helm chart”)和不是通过 EIB 部署的(第 24.3.2 节 “不是通过 EIB 部署的 Helm chart”)Helm chart。

24.3.1 通过 EIB 部署的 Helm chart

EIB 使用 RKE2 的清单自动部署功能来部署其映像定义文件(第 3.3 节 “创建映像定义文件”)中定义的 Helm chart。

要升级以这种方式部署的 chart,需要升级 EIB 在初始化器节点上的 /var/lib/rancher/rke2/server/manifests 目录下创建的 chart 清单文件。

注意
注意

为了确保能够实现灾难恢复,我们建议您始终备份 chart 清单文件,并按照 chart 提供的任何灾难恢复相关文档进行操作。

要升级 chart 清单文件,请执行以下步骤:

  1. 找到初始化器节点

    • 对于多节点群集 - 在 EIB 映像定义文件中,应该已经为某个节点指定了 initializer: true 属性。如果未指定此属性,则初始化器节点将是节点列表中的第一个服务器节点。

    • 对于单节点群集 - 初始化器是当前正在运行的节点。

  2. 通过 SSH 连接到初始化器节点:

    ssh root@<node_ip>
  3. 提取 Helm chart:

    • 对于托管在 Helm chart 储存库中的 Helm chart:

      helm repo add <chart_repo_name> <chart_repo_urls>
      helm pull <chart_repo_name>/<chart_name>
      
      # Alternatively if you want to pull a specific verison
      helm pull <chart_repo_name>/<chart_name> --version=X.Y.Z
    • 对于基于 OCI 的 Helm chart:

      helm pull oci://<chart_oci_url>
      
      # Alternatively if you want to pull a specific verison
      helm pull oci://<chart_oci_url> --version=X.Y.Z
  4. 将提取的 .tgz 存档编码,以便可以将其传递给 HelmChart CR 配置:

    base64 -w 0 <chart_name>-X.Y.Z.tgz  > <chart_name>-X.Y.Z.txt
  5. 为要编辑的 chart 清单文件创建副本:

    cp /var/lib/rancher/rke2/server/manifests/<chart_name>.yaml ./<chart_name>.yaml
  6. 更改 bar.yaml 文件的 chartContentversion 配置:

    sed -i -e "s|chartContent:.*|chartContent: $(<chart-name-X.Y.Z.txt)|" -e "s|version:.*|version: X.Y.Z|" <chart_name>.yaml
    注意
    注意

    如果需要对 chart 进行任何其他升级更改(例如添加新的自定义 chart 值),则需要手动编辑 chart 清单文件。

  7. 替换原始 chart 清单文件:

    cp <chart_name>.yaml /var/lib/rancher/rke2/server/manifests/

以上命令将触发 Helm chart 升级。升级将由 helm-controller 处理。

要跟踪 Helm chart 的升级,需要查看 helm-controller 为 chart 升级创建的 Pod 的日志。有关详细信息,请参见“示例”(第 24.3.1.1 节 “示例”)一节。

24.3.1.1 示例

注意
注意

本节中的示例假设您已找到并连接到初始化器节点。

本节提供有关如何升级以下 Helm chart 的示例:

24.3.1.1.1 Rancher 升级
注意
注意

为了确保能够实现灾难恢复,我们建议进行 Rancher 备份。有关如何执行此操作的信息,请查看此页面

此示例说明如何将 Rancher 升级到 2.8.4 版本。

  1. 添加 Rancher Prime Helm 储存库:

    helm repo add rancher-prime https://charts.rancher.com/server-charts/prime
  2. 提取最新的 Rancher Prime Helm chart 版本:

    helm pull rancher-prime/rancher --version=2.8.4
  3. .tgz 存档编码,以便可以将其传递给 HelmChart CR 配置:

    base64 -w 0 rancher-2.8.4.tgz  > rancher-2.8.4-encoded.txt
  4. 为要编辑的 rancher.yaml 文件创建副本:

    cp /var/lib/rancher/rke2/server/manifests/rancher.yaml ./rancher.yaml
  5. 更改 rancher.yaml 文件的 chartContentversion 配置:

    sed -i -e "s|chartContent:.*|chartContent: $(<rancher-2.8.4-encoded.txt)|" -e "s|version:.*|version: 2.8.4|" rancher.yaml
    注意
    注意

    如果需要对 chart 进行任何其他升级更改(例如添加新的自定义 chart 值),则需要手动编辑 rancher.yaml 文件。

  6. 替换原始 rancher.yaml 文件:

    cp rancher.yaml /var/lib/rancher/rke2/server/manifests/

要校验是否做出了更新,请执行以下操作:

  1. 列出 default 名称空间中的 Pod:

    kubectl get pods -n default
    
    # Example output
    NAME                              READY   STATUS      RESTARTS   AGE
    helm-install-cert-manager-7v7nm   0/1     Completed   0          88m
    helm-install-rancher-p99k5        0/1     Completed   0          3m21s
  2. 查看 helm-install-rancher-* Pod 的日志:

    kubectl logs <helm_install_rancher_pod> -n default
    
    # Example
    kubectl logs helm-install-rancher-p99k5 -n default
  3. 校验 Rancher Pod 是否正在运行:

    kubectl get pods -n cattle-system
    
    # Example output
    NAME                               READY   STATUS      RESTARTS   AGE
    helm-operation-mccvd               0/2     Completed   0          3m52s
    helm-operation-np8kn               0/2     Completed   0          106s
    helm-operation-q8lf7               0/2     Completed   0          2m53s
    rancher-648d4fbc6c-qxfpj           1/1     Running     0          5m27s
    rancher-648d4fbc6c-trdnf           1/1     Running     0          9m57s
    rancher-648d4fbc6c-wvhbf           1/1     Running     0          9m57s
    rancher-webhook-649dcc48b4-zqjs7   1/1     Running     0          100s
  4. 校验 Rancher 版本是否已升级:

    kubectl get settings.management.cattle.io server-version
    
    # Example output
    NAME             VALUE
    server-version   v2.8.4
24.3.1.1.2 Metal3 升级

此示例说明如何将 Metal3 升级到 0.7.1 版本。

  1. 提取最新的 Metal3 Helm chart 版本:

    helm pull oci://registry.suse.com/edge/metal3-chart --version 0.7.1
  2. .tgz 存档编码,以便可以将其传递给 HelmChart CR 配置:

    base64 -w 0 metal3-chart-0.7.1.tgz  > metal3-chart-0.7.1-encoded.txt
  3. 为要编辑的 Metal3 清单文件创建副本:

    cp /var/lib/rancher/rke2/server/manifests/metal3.yaml ./metal3.yaml
  4. 更改 Metal3 清单文件的 chartContentversion 配置:

    sed -i -e "s|chartContent:.*|chartContent: $(<metal3-chart-0.7.1-encoded.txt)|" -e "s|version:.*|version: 0.7.1|" metal3.yaml
    注意
    注意

    如果需要对 chart 进行任何其他升级更改(例如添加新的自定义 chart 值),则需要手动编辑 metal3.yaml 文件。

  5. 替换原始 Metal3 清单文件:

    cp metal3.yaml /var/lib/rancher/rke2/server/manifests/

要校验是否做出了更新,请执行以下操作:

  1. 列出 default 名称空间中的 Pod:

    kubectl get pods -n default
    
    # Example output
    NAME                              READY   STATUS      RESTARTS   AGE
    helm-install-metal3-7p7bl         0/1     Completed   0          27s
  2. 查看 helm-install-rancher-* Pod 的日志:

    kubectl logs <helm_install_rancher_pod> -n default
    
    # Example
    kubectl logs helm-install-metal3-7p7bl -n default
  3. 校验 Metal3 Pod 是否正在运行:

    kubectl get pods -n metal3-system
    
    # Example output
    NAME                                                     READY   STATUS    RESTARTS      AGE
    baremetal-operator-controller-manager-785f99c884-9z87p   2/2     Running   2 (25m ago)   36m
    metal3-metal3-ironic-96fb66cdd-lkss2                     4/4     Running   0             3m54s
    metal3-metal3-mariadb-55fd44b648-q6zhk                   1/1     Running   0             36m
  4. 校验 HelmChart 资源版本是否已升级:

    kubectl get helmchart metal3 -n default
    
    # Example output
    NAME     JOB                   CHART   TARGETNAMESPACE   VERSION   REPO   HELMVERSION   BOOTSTRAP
    metal3   helm-install-metal3           metal3-system     0.7.1

24.3.2 不是通过 EIB 部署的 Helm chart

  1. 获取当前正在运行的 Helm chart .yaml 文件的值,并根据需要对其进行任何更改:

    helm get values <chart_name> -n <chart_namespace> -o yaml > <chart_name>-values.yaml
  2. 更新 Helm chart:

    # For charts using a chart repository
    helm upgrade <chart_name> <chart_repo_name>/<chart_name> \
      --namespace <chart_namespace> \
      -f <chart_name>-values.yaml \
      --version=X.Y.Z
    
    # For OCI based charts
    helm upgrade <chart_name> oci://<oci_registry_url>/<chart_name> \
      --namespace <chart_namespace> \
      -f <chart_name>-values.yaml \
      --version=X.Y.Z
  3. 校验 chart 是否已升级。根据具体的 chart,可能需要校验不同的资源。有关 chart 升级示例,请参见“示例”(第 24.3.2.1 节 “示例”)一节。

24.3.2.1 示例

本节提供有关如何升级以下 Helm chart 的示例:

24.3.2.1.1 Rancher
注意
注意

为了确保能够实现灾难恢复,我们建议进行 Rancher 备份。有关如何执行此操作的信息,请查看此页面

此示例说明如何将 Rancher 升级到 2.8.4 版本。

  1. 获取当前 Rancher 版本的值,并将其列显到 rancher-values.yaml 文件中:

    helm get values rancher -n cattle-system -o yaml > rancher-values.yaml
  2. 更新 Helm chart:

    helm upgrade rancher rancher-prime/rancher \
      --namespace cattle-system \
      -f rancher-values.yaml \
      --version=2.8.4
  3. 校验 Rancher 版本是否已升级:

    kubectl get settings.management.cattle.io server-version
    
    # Example output
    NAME             VALUE
    server-version   v2.8.4

有关 Rancher Helm chart 升级的详细信息,请查看此页面

24.3.2.1.2 Metal3

此示例说明如何将 Metal3 升级到 0.7.1 版本。

  1. 获取当前 Rancher 版本的值,并将其列显到 rancher-values.yaml 文件中:

    helm get values metal3 -n metal3-system -o yaml > metal3-values.yaml
  2. 更新 Helm chart:

    helm upgrade metal3 oci://registry.suse.com/edge/metal3-chart \
      --namespace metal3-system \
      -f metal3-values.yaml \
      --version=0.7.1
  3. 校验 Metal3 Pod 是否正在运行:

    kubectl get pods -n metal3-system
    
    # Example output
    NAME                                                     READY   STATUS    RESTARTS   AGE
    baremetal-operator-controller-manager-785f99c884-fvsx4   2/2     Running   0          12m
    metal3-metal3-ironic-96fb66cdd-j9mgf                     4/4     Running   0          2m41s
    metal3-metal3-mariadb-55fd44b648-7fmvk                   1/1     Running   0          12m
  4. 校验 Metal3 Helm 版本是否已更改:

    helm ls -n metal3-system
    
    # Expected output
    NAME  	NAMESPACE    	REVISION	UPDATED                                	STATUS  	CHART       	APP VERSION
    metal3	metal3-system	2       	2024-06-17 12:43:06.774802846 +0000 UTC	deployed	metal3-0.7.1	1.16.0

25 下游群集

本章介绍如何使用管理群集对下游群集的不同组件执行各种 Day 2 操作。

25.1 简介

本节旨在充当 Day 2 操作文档的起点,在其中可以找到以下信息。

  1. 用于在多个下游群集中实现 Day 2 操作的默认组件(第 25.1.1 节 “组件”)。

  2. 确定要为特定用例使用哪些 Day 2 资源(第 25.1.2 节 “确定您的用例”)。

  3. Day 2 操作的建议工作流程顺序(第 25.1.3 节 “Day 2 工作流程”)。

25.1.1 组件

下面提供了默认组件的说明,应在管理群集下游群集上设置这些组件,以便可以成功执行 Day 2 操作。

25.1.1.1 Rancher

注意
注意

如果您要在用例中使用 Fleet(第 6 章 “Fleet)但不使用 Rancher,则完全可以跳过 Rancher 组件的设置。

Rancher 负责管理您的下游群集。应将其部署在您的管理群集上。

有关详细信息,请参见第 4 章 “Rancher

25.1.1.2 Fleet

Fleet 负责多群集资源部署。

通常由 Rancher 组件提供。对于不使用 Rancher 的用例,可将 Fleet 部署为独立组件。

有关将 Fleet 安装为独立组件的详细信息,请参见 Fleet 的安装细节

有关 Fleet 组件的详细信息,请参见第 6 章 “Fleet

重要
重要

本文档主要依赖于 Fleet,更具体地说,依赖于使用 GitRepo捆绑包资源(有关详细信息,请参见第 25.1.2 节 “确定您的用例”)来通过 GitOps 自动部署与 Day 2 操作相关的资源。

对于需要使用第三方 GitOps 工具的用例,请参见:

  1. 对于操作系统软件包更新 - 第 25.3.4.3 节 “SUC 计划部署 - 第三方 GitOps 工作流程”

  2. 对于 Kubernetes 发行版升级 - 第 25.4.4.3 节 “SUC 计划部署 - 第三方 GitOps 工作流程”

  3. 对于 Helm chart 升级 - 从第 33.1 节 “摘要”页面检索所需 Edge 版本支持的 chart 版本,并在第三方 GitOps 工具中填充 chart 版本和 URL

25.1.1.3 系统升级控制器 (SUC)

系统升级控制器 (SUC) 负责根据通过自定义资源(称为计划)提供的配置数据在指定节点上执行任务。应将其放置在每个需要执行某种 Day 2 操作的下游群集上。

有关 SUC 的详细信息,请参见上游储存库

有关如何在下游群集上部署 SUC 的信息,请先确定您的用例(第 25.1.2 节 “确定您的用例”),然后参见第 25.2.1.1 节 “使用 GitRepo 资源进行 SUC 部署”第 25.2.1.2 节 “使用捆绑包资源进行 SUC 部署”来了解 SUC 部署信息。

25.1.2 确定您的用例

如前所述,与 Day 2 操作相关的资源将通过 Fleet 的 GitRepo捆绑包资源传播到下游群集。

下面提供了有关这些资源的作用,以及应在哪些用例中使用它们来执行 Day 2 操作的详细信息。

25.1.2.1 GitRepo

GitRepo 是一种 Fleet(第 6 章 “Fleet)资源,它代表一个 Git 储存库,Fleet 可从中创建捆绑包。每个捆绑包是基于 GitRepo 资源中定义的配置路径创建的。有关详细信息,请参见 GitRepo 文档。

Day 2 操作而言,GitRepo 资源通常用于在利用 Fleet GitOps 方法的非隔离环境中部署 SUCSUC 计划

或者,如果您通过本地 git 服务器镜像储存库设置,则 GitRepo 资源也可用于在隔离环境中部署 SUCSUC 计划

25.1.2.2 捆绑包

捆绑包包含了要在目标群集上部署的原始 Kubernetes 资源。通常它们是基于 GitRepo 资源创建的,但在某些用例中也可以手动部署。有关详细信息,请参见捆绑包文档。

Day 2 操作而言,捆绑包资源通常用于在不使用某种形式的本地 GitOps 过程(例如本地 git 服务器)的隔离环境中部署 SUCSUC 计划

或者,如果您的用例不允许使用 GitOps 工作流程(例如需使用 Git 储存库),则捆绑包资源也可用于在非隔离环境中部署 SUCSUC 计划

25.1.3 Day 2 工作流程

下面是在将下游群集升级到特定 Edge 版本时应遵循的 Day 2 工作流程。

25.2 系统升级控制器部署指南

系统升级控制器 (SUC) 负责根据自定义资源(称为计划)中定义的配置在指定节点上部署资源。有关详细信息,请参见上游文档

注意
注意

本节只会重点介绍如何部署系统升级控制器。应根据以下文档部署计划资源:

25.2.1 部署

注意
注意

本节假设您要使用 Fleet(第 6 章 “Fleet)来编排 SUC 部署。使用第三方 GitOps 工作流程的用户应参见第 25.2.1.3 节 “使用第三方 GitOps 工作流程时部署系统升级控制器”来了解需要在其工作流程中设置哪些资源。

要确定所要使用的资源,请参见第 25.1.2 节 “确定您的用例”

25.2.1.1 使用 GitRepo 资源进行 SUC 部署

本节介绍如何创建 GitRepo 资源,用于将成功完成 SUC 部署所需的 SUC 计划传送到目标下游群集。

Edge 团队会在每个 suse-edge/fleet-examples 版本中的 gitrepos/day2/system-upgrade-controller-gitrepo.yaml 下,为 SUC 维护一个随时可用的 GitRepo 资源。

重要
重要

如果您使用 suse-edge/fleet-examples 储存库,请确保使用带有专用版本标记的资源。

可通过以下方式之一创建 GitRepo

创建 GitRepo 后,Fleet 将负责拾取资源,并将 SUC 资源部署到所有目标群集。有关如何跟踪部署过程的信息,请参见第 25.2.2.1 节 “监控 SUC 部署”

25.2.1.1.1 GitRepo 部署 - Rancher UI
  1. 在左上角,选择 ☰ → Continuous Delivery(持续交付)

  2. 转到 Git 储存库 → 添加储存库

如果使用 suse-edge/fleet-examples 储存库,请执行以下步骤:

  1. 储存库 URL - https://github.com/suse-edge/fleet-examples.git

  2. Watch(监视)→ Revision(修订版)- 为要使用的 suse-edge/fleet-examples 储存库选择版本标记,例如 release-3.0.1

  3. 路径下,添加版本标记中显示的系统升级控制器路径 - fleets/day2/system-upgrade-controller

  4. 选择下一步转到目标配置部分

  5. 请仅选择您要为其部署系统升级控制器的群集。如果您对配置感到满意,请单击创建

或者,如果您决定使用自己的储存库来托管这些文件,则需要提供上述储存库数据。

25.2.1.1.2 GitRepo 创建 - 手动
  1. 选择您要从中部署 SUC GitRepo 的所需 Edge 版本标记(在下文中用 ${REVISION} 表示)。

  2. 提取 GitRepo 资源:

    curl -o system-upgrade-controller-gitrepo.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/{REVISION}/gitrepos/day2/system-upgrade-controller-gitrepo.yaml
  3. 编辑 GitRepo 配置,在 spec.targets 下指定所需的目标列表。默认情况下,suse-edge/fleet-examples 中的 GitRepo 资源不会映射到任何下游群集。

    • 为了匹配所有群集,请将默认的 GitRepo 目标更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 或者,如果您要更细致地选择群集,请参见映射到下游群集

  4. GitRepo 资源应用于管理群集

    kubectl apply -f system-upgrade-controller-gitrepo.yaml
  5. 查看 fleet-default 名称空间下创建的 GitRepo 资源:

    kubectl get gitrepo system-upgrade-controller -n fleet-default
    
    # Example output
    NAME                        REPO                                               COMMIT       BUNDLEDEPLOYMENTS-READY   STATUS
    system-upgrade-controller   https://github.com/suse-edge/fleet-examples.git   release-3.0.1   0/0

25.2.1.2 使用捆绑包资源进行 SUC 部署

本节介绍如何创建捆绑包资源,用于将成功完成 SUC 部署所需的 SUC 计划传送到目标下游群集。

Edge 团队会在每个 suse-edge/fleet-examples 版本中的 bundles/day2/system-upgrade-controller/controller-bundle.yaml 下,为 SUC 维护随时可用的捆绑包资源。

重要
重要

如果您使用 suse-edge/fleet-examples 储存库,请确保使用带有专用版本标记的资源。

可通过以下方式之一创建捆绑包

创建捆绑包后,Fleet 将负责拾取资源,并将 SUC 资源部署到所有目标群集。有关如何跟踪部署过程的信息,请参见第 25.2.2.1 节 “监控 SUC 部署”

25.2.1.2.1 捆绑包创建 - Rancher UI
  1. 在左上角,选择 ☰ → Continuous Delivery(持续交付)

  2. 转到高级 > 捆绑包

  3. 选择从 YAML 创建

  4. 此处可通过以下方式之一创建捆绑包:

  5. 更改捆绑包目标群集:

    • 为了匹配所有下游群集,请将默认的捆绑包 .spec.targets 更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 有关更精细的下游群集映射,请参见映射到下游群集

  6. 创建

25.2.1.2.2 捆绑包创建 - 手动
  1. 选择您要从中部署 SUC 捆绑包的所需 Edge 版本标记(在下文中用 ${REVISION} 表示)。

  2. 提取捆绑包资源:

    curl -o controller-bundle.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/bundles/day2/system-upgrade-controller/controller-bundle.yaml
  3. 编辑捆绑包目标配置,在 spec.targets 下提供所需的目标列表。默认情况下,suse-edge/fleet-examples 中的捆绑包资源不会映射到任何下游群集。

    • 为了匹配所有群集,请将默认的捆绑包目标更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 或者,如果您要更细致地选择群集,请参见映射到下游群集

  4. 捆绑包资源应用于管理群集

    kubectl apply -f controller-bundle.yaml
  5. 查看 fleet-default 名称空间下创建的捆绑包资源:

    kubectl get bundles system-upgrade-controller -n fleet-default
    
    # Example output
    NAME                        BUNDLEDEPLOYMENTS-READY   STATUS
    system-upgrade-controller   0/0

25.2.1.3 使用第三方 GitOps 工作流程时部署系统升级控制器

要使用第三方 GitOps 工具部署系统升级控制器,根据具体使用的工具,您可能需要获取系统升级控制器 Helm chart 和/或 Kubernetes 资源的信息。

选择您要从中使用 SUC 的特定 Edge 版本

从该页面中,可以在 fleets/day2/system-upgrade-controller/fleet.ymal 文件的 helm 配置部分下找到 SUC Helm chart 数据。

可以在 SUC 捆绑包配置中的 .spec.resources.content 下找到 SUC Kubernetes 资源。该捆绑包的位置为 bundles/day2/system-upgrade-controller/controller-bundle.yaml

使用上面提到的资源来填充第三方 GitOps 工作流程所需的数据,以部署 SUC

25.2.2 使用 Rancher 监控 SUC 资源

本节介绍如何使用 Rancher UI 监控 SUC 部署生命周期以及任何已部署的 SUC 计划。

25.2.2.1 监控 SUC 部署

要检查特定群集的 SUC Pod 日志,请执行以下操作:

  1. 在左上角,选择 ☰ → <您的群集名称>

  2. 选择工作负载 → Pod

  3. 在名称空间下拉菜单中选择 cattle-system 名称空间

    day2 监控 suc 部署 1
  4. 在 Pod 过滤栏中输入 SUC 名称 - system-upgrade-controller

  5. 在 Pod 右侧选择 ⋮ → 查看日志

    day2 监控 suc 部署 2
  6. SUC 日志应如下所示:

    day2 监控 suc 部署 3

25.2.2.2 监控 SUC 计划

重要
重要

SUC 计划 Pod 会保持活动状态 15 分钟。此期限过后,创建它们的相应作业会将其去除。要访问 SUC 计划 Pod 日志,应该为群集启用日志记录。有关如何在 Rancher 中执行此操作的信息,请参见 Rancher 与日志记录服务的集成

要检查特定 SUC 计划的 Pod 日志,请执行以下操作:

  1. 在左上角,选择 ☰ → <您的群集名称>

  2. 选择工作负载 → Pod

  3. 在名称空间下拉菜单中选择 cattle-system 名称空间

    day2 监控 suc 部署 1
  4. 在 Pod 过滤栏中输入 SUC 计划 Pod 的名称。该名称采用以下模板格式:apply-<计划名称>-on-<节点名称>

    day2 k8s 计划监控
    图 25.1︰ Kubernetes 升级计划 Pod 示例

    请注意,在图 1 中,有一个 Pod 处于已完成状态,另有一个 Pod 处于未知状态。这是预料之中的情况,其原因是在节点上执行了 Kubernetes 版本升级。

    day2 操作系统软件包计划监控
    图 25.2︰ 操作系统软件包更新计划 Pod 示例
    day2 chart 升级计划监控
    图 25.3︰ HA 群集上 EIB 部署的 Helm chart 的升级计划 Pod 示例
  5. 选择您要查看其日志的 Pod,然后导航到 ⋮ → 查看日志

25.3 操作系统软件包更新

25.3.1 组件

本节介绍操作系统软件包更新过程在默认 Day 2 组件(第 25.1.1 节 “组件”)之上使用的自定义组件。

25.3.1.1 edge-update.service

负责执行操作系统软件包更新的 Systemd 服务。使用 transactional-update 命令执行发行版升级 (dup)。

注意
注意

如果您要使用常规升级方法,请在每个节点上的 /etc/edge/ 下创建一个 edge-update.conf 文件。在此文件中添加 UPDATE_METHOD=up 变量。

此组件通过 SUC 计划交付,该计划应位于需要进行操作系统软件包更新的每个下游群集上。

25.3.2 要求

一般:

  1. 已在 SCC 中注册的计算机 - 所有下游群集节点都应已注册到 https://scc.suse.com/。只有这样,edge-update.service 才能成功连接到所需的操作系统 RPM 储存库。

  2. 确保 SUC 计划容忍度与节点容忍度相匹配 - 如果您的 Kubernetes 群集节点具有自定义污点,请确保在 SUC 计划中为这些污点添加容忍度。默认情况下,SUC 计划仅包含控制平面节点的容忍度。默认容忍度包括:

    • CriticalAddonsOnly=true:NoExecute

    • node-role.kubernetes.io/control-plane:NoSchedule

    • node-role.kubernetes.io/etcd:NoExecute

      注意
      注意

      其他任何容忍度必须添加到每个计划的 .spec.tolerations 部分下。与操作系统软件包更新相关的 SUC 计划可以在 suse-edge/fleet-examples 储存库中的 fleets/day2/system-upgrade-controller-plans/os-pkg-update 下找到。请确保使用有效储存库版本标记中的计划。

      控制平面 SUC 计划定义自定义容忍度的示例如下:

      apiVersion: upgrade.cattle.io/v1
      kind: Plan
      metadata:
        name: os-pkg-plan-control-plane
      spec:
        ...
        tolerations:
        # default tolerations
        - key: "CriticalAddonsOnly"
          operator: "Equal"
          value: "true"
          effect: "NoExecute"
        - key: "node-role.kubernetes.io/control-plane"
          operator: "Equal"
          effect: "NoSchedule"
        - key: "node-role.kubernetes.io/etcd"
          operator: "Equal"
          effect: "NoExecute"
        # custom toleration
        - key: "foo"
          operator: "Equal"
          value: "bar"
          effect: "NoSchedule"
      ...

隔离:

  1. 镜像 SUSE RPM 储存库 - 操作系统 RPM 储存库应在本地镜像,以便 edge-update.service 可以访问它们。可以使用 RMT 实现此目的。

25.3.3 更新过程

注意
注意

本节假设您将使用 Fleet(第 6 章 “Fleet)部署操作系统软件包更新 SUC 计划。如果您打算使用其他方法部署 SUC 计划,请参见第 25.3.4.3 节 “SUC 计划部署 - 第三方 GitOps 工作流程”

操作系统软件包更新过程主要围绕着将 SUC 计划部署到下游群集来进行。然后,这些计划将包含有关如何以及在哪些节点上部署 edge-update.service systemd.service 的信息。有关 SUC 计划结构的信息,请参见上游文档

操作系统软件包更新 SUC 计划通过以下方式交付:

要确定使用哪个资源,请参见第 25.1.2 节 “确定您的用例”

有关更新过程中会发生哪些情况的完整概述,请参见第 25.3.3.1 节 “概述”一节。

25.3.3.1 概述

本节旨在介绍操作系统软件包更新过程从头到尾的完整工作流程。

day2 操作系统软件包更新流程图
图 25.4︰ 操作系统软件包更新工作流程

操作系统软件包更新步骤:

  1. 用户可以根据用例,确定是要使用 GitRepo 还是捆绑包资源将操作系统软件包更新 SUC 计划部署到所需的下游群集。有关如何将 GitRepo/捆绑包映射到特定的一组下游群集的信息,请参见映射到下游群集

    1. 如果您不确定是要使用 GitRepo 还是捆绑包资源进行 SUC 计划部署,请参见第 25.1.2 节 “确定您的用例”

    2. 有关 GitRepo/捆绑包配置选项,请参见第 25.3.4.1 节 “SUC 计划部署 - GitRepo 资源”第 25.3.4.2 节 “SUC 计划部署 - 捆绑包资源”

  2. 用户将配置的 GitRepo/捆绑包资源部署到其管理群集中的 fleet-default 名称空间。此操作可以手动完成,也可以通过 Rancher UI(如果可用)完成。

  3. Fleet(第 6 章 “Fleet)持续监控 fleet-default 名称空间,并立即检测新部署的 GitRepo/捆绑包资源。有关 Fleet 监控哪些名称空间的详细信息,请参见 Fleet 的名称空间文档。

  4. 如果用户已部署 GitRepo 资源,Fleet 将协调 GitRepo,并根据其路径fleet.yaml 配置,在 fleet-default 名称空间中部署捆绑包资源。有关详细信息,请参见 Fleet 的 GitRepo 内容文档。

  5. 然后,Fleet 继续将此捆绑包中的 Kubernetes 资源部署到所有目标下游群集。在操作系统软件包更新的上下文中,Fleet 将部署捆绑包中的以下资源:

    1. os-pkg-plan-agent SUC 计划 - 告知 SUC 如何在群集代理节点上执行软件包更新。如果群集仅由控制平面节点组成,则做解释。

    2. os-pkg-plan-control-plane SUC 计划 - 告知 SUC 如何在群集控制平面节点上执行软件包更新。

    3. os-pkg-update 密钥 - 在每个 SUC 计划中引用;附带一个 update.sh 脚本,该脚本负责创建执行实际软件包更新的 edge-update.service sustemd.service

      注意
      注意

      上述资源将部署在每个下游群集的 cattle-system 名称空间中。

  6. 在下游群集上,SUC 将拾取新部署的 SUC 计划,并在与 SUC 计划中定义的节点选择器匹配的每个节点上部署更新 Pod。有关如何监控 SUC 计划 Pod 的信息,请参见第 25.2.2.2 节 “监控 SUC 计划”

  7. 更新 Pod(部署在每个节点上)挂载 os-pkg-update 密钥并执行密钥附带的 update.sh 脚本。

  8. update.sh 继续执行以下操作:

    1. 创建 edge-update.service - 创建的服务属于 oneshot 类型,采用以下工作流程:

      1. 通过执行以下命令更新节点操作系统上的所有软件包版本:

        transactional-update cleanup dup
      2. 成功执行 transactional-update 后,将安排系统重引导,使软件包版本更新生效

        注意
        注意

        成功执行 transactional-update 后,将安排系统重引导并等待 1 分钟

    2. 启动 edge-update.service 并等待启动完成

    3. 清理 edge-update.service - 在 systemd.service 完成其工作后,会将其从系统中去除,以确保将来不会发生意外的执行/重引导。

系统重引导后,操作系统软件包更新过程即告完成。重引导后,所有操作系统软件包版本应会更新到可用操作系统 RPM 储存库中显示的相应最新版本。

25.3.4 操作系统软件包更新 - SUC 计划部署

本节介绍如何使用 Fleet 的 GitRepo捆绑包资源来编排 SUC 计划相关的操作系统软件包更新的部署。

25.3.4.1 SUC 计划部署 - GitRepo 资源

可通过以下方式之一部署 GitRepo 资源,该资源中附带了所需的操作系统软件包更新 SUC 计划

  1. 通过 Rancher UI 部署 - 第 25.3.4.1.1 节 “GitRepo 创建 - Rancher UI”(如果 Rancher 可用)。

  2. 手动将相应资源部署(第 25.3.4.1.2 节 “GitRepo 创建 - 手动”)到管理群集

部署后,要监控目标群集节点的操作系统软件包更新过程,请参见第 25.2.2.2 节 “监控 SUC 计划”文档。

25.3.4.1.1 GitRepo 创建 - Rancher UI
  1. 在左上角,选择 ☰ → Continuous Delivery(持续交付)

  2. 转到 Git 储存库 → 添加储存库

如果使用 suse-edge/fleet-examples 储存库,请执行以下步骤:

  1. 储存库 URL - https://github.com/suse-edge/fleet-examples.git

  2. 监视 → 修订版 - 为要使用的 suse-edge/fleet-examples 储存库选择版本标记

  3. 路径下,添加您要使用的操作系统软件包更新 Fleet 的路径 - fleets/day2/system-upgrade-controller-plans/os-pkg-update

  4. 选择下一步转到目标配置部分。请仅选择您要升级其节点软件包的群集

  5. 创建

或者,如果您决定使用自己的储存库来托管这些文件,则需要提供上述储存库数据。

25.3.4.1.2 GitRepo 创建 - 手动
  1. 选择您要从中应用操作系统 SUC 更新计划的所需 Edge 版本标记(在下文中用 ${REVISION} 表示)。

  2. 提取 GitRepo 资源:

    curl -o os-pkg-update-gitrepo.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/gitrepos/day2/os-pkg-update-gitrepo.yaml
  3. 编辑 GitRepo 配置,在 spec.targets 下指定所需的目标列表。默认情况下,suse-edge/fleet-examples 中的 GitRepo 资源不会映射到任何下游群集。

    • 为了匹配所有群集,请将默认的 GitRepo 目标更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 或者,如果您要更细致地选择群集,请参见映射到下游群集

  4. GitRepo 资源应用于管理群集

    kubectl apply -f os-pkg-update-gitrepo.yaml
  5. 查看 fleet-default 名称空间下创建的 GitRepo 资源:

    kubectl get gitrepo os-pkg-update -n fleet-default
    
    # Example output
    NAME            REPO                                              COMMIT         BUNDLEDEPLOYMENTS-READY   STATUS
    os-pkg-update   https://github.com/suse-edge/fleet-examples.git   release-3.0.1  0/0

25.3.4.2 SUC 计划部署 - 捆绑包资源

可通过以下方式之一部署捆绑包资源,该资源中附带了所需的操作系统软件包更新 SUC 计划

  1. 通过 Rancher UI 部署 - 第 25.3.4.2.1 节 “捆绑包创建 - Rancher UI”(如果 Rancher 可用)。

  2. 手动将相应资源部署(第 25.3.4.2.2 节 “捆绑包创建 - 手动”)到管理群集

部署后,要监控目标群集节点的操作系统软件包更新过程,请参见第 25.2.2.2 节 “监控 SUC 计划”文档。

25.3.4.2.1 捆绑包创建 - Rancher UI
  1. 在左上角,单击 ☰ → Continuous Delivery(持续交付)

  2. 转到高级 > 捆绑包

  3. 选择从 YAML 创建

  4. 此处可通过以下方式之一创建捆绑包:

    1. 通过手动将捆绑包内容复制到从 YAML 创建页面。可以从 https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/bundles/day2/system-upgrade-controller-plans/os-pkg-update/pkg-update-bundle.yaml 检索内容,其中 ${REVISION} 是您使用的 Edge 版本

    2. 通过将 suse-edge/fleet-examples 储存库克隆到所需的版本标记中,并在从 YAML 创建页面中选择从文件读取选项。然后导航到 bundles/day2/system-upgrade-controller-plans/os-pkg-update 目录并选择 pkg-update-bundle.yaml。这会在从 YAML 创建页面中自动填充捆绑包内容。

  5. 更改捆绑包目标群集:

    • 为了匹配所有下游群集,请将默认的捆绑包 .spec.targets 更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 有关更精细的下游群集映射,请参见映射到下游群集

  6. 选择创建

25.3.4.2.2 捆绑包创建 - 手动
  1. 选择您要从中应用操作系统软件包更新 SUC 计划的所需 Edge 版本标记(在下文中用 ${REVISION} 表示)。

  2. 提取捆绑包资源:

    curl -o pkg-update-bundle.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/bundles/day2/system-upgrade-controller-plans/os-pkg-update/pkg-update-bundle.yaml
  3. 编辑捆绑包目标配置,在 spec.targets 下提供所需的目标列表。默认情况下,suse-edge/fleet-examples 中的捆绑包资源不会映射到任何下游群集。

    • 为了匹配所有群集,请将默认的捆绑包目标更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 或者,如果您要更细致地选择群集,请参见映射到下游群集

  4. 捆绑包资源应用于管理群集

    kubectl apply -f pkg-update-bundle.yaml
  5. 查看 fleet-default 名称空间下创建的捆绑包资源:

    kubectl get bundles os-pkg-update -n fleet-default
    
    # Example output
    NAME            BUNDLEDEPLOYMENTS-READY   STATUS
    os-pkg-update   0/0

25.3.4.3 SUC 计划部署 - 第三方 GitOps 工作流程

在某些用例中,用户可能希望将操作系统软件包更新 SUC 计划合并到他们自己的第三方 GitOps 工作流程(例如 Flux)中。

要获取所需的操作系统软件包更新资源,首先请确定您要使用的 suse-edge/fleet-examples 储存库的 Edge 版本标记。

然后,便可以在 fleets/day2/system-upgrade-controller-plans/os-pkg-update 中查找资源,其中:

  • plan-control-plane.yaml - 控制平面节点的系统升级控制器计划资源

  • plan-agent.yaml - 代理节点的系统升级控制器计划资源

  • secret.yaml - 密钥,其中附带了用于创建 edge-update.service systemd.service 的脚本

重要
重要

这些计划资源由系统升级控制器解释,应部署在您要升级的每个下游群集上。有关如何部署系统升级控制器的信息,请参见第 25.2.1.3 节 “使用第三方 GitOps 工作流程时部署系统升级控制器”

为了更好地了解如何使用 GitOps 工作流程来部署操作系统软件包更新的 SUC 计划,建议查看有关使用 Fleet 进行更新的过程概述(第 25.3.3.1 节 “概述”)。

25.4 Kubernetes 版本升级

重要
重要

本节介绍不是通过 Rancher(第 4 章 “Rancher)实例创建的下游群集的 Kubernetes 升级过程。有关如何对通过 Rancher 创建的群集进行 Kubernetes 版本升级的信息,请参见升级和回滚 Kubernetes

25.4.1 组件

本节介绍 Kubernetes 升级过程在默认 Day 2 组件(第 25.1.1 节 “组件”)之上使用的自定义组件。

25.4.1.1 rke2-upgrade

负责升级特定节点的 RKE2 版本的映像。

此组件由 SUC 根据 SUC 计划创建的 Pod 交付。该计划应位于需要进行 RKE2 升级的每个下游群集上。

有关 rke2-upgrade 映像如何执行升级的详细信息,请参见上游文档

25.4.1.2 k3s-upgrade

负责升级特定节点的 K3s 版本的映像。

此组件由 SUC 根据 SUC 计划创建的 Pod 交付。该计划应位于需要进行 K3s 升级的每个下游群集上。

有关 k3s-upgrade 映像如何执行升级的详细信息,请参见上游文档

25.4.2 要求

  1. 备份您的 Kubernetes 发行版:

    1. 对于导入的 RKE2 群集,请参见 RKE2 备份和恢复文档。

    2. 对于导入的 K3s 群集,请参见 K3s 备份和恢复文档。

  2. 确保 SUC 计划容忍度与节点容忍度相匹配 - 如果您的 Kubernetes 群集节点具有自定义污点,请确保在 SUC 计划中为这些污点添加容忍度。默认情况下,SUC 计划仅包含控制平面节点的容忍度。默认容忍度包括:

    • CriticalAddonsOnly=true:NoExecute

    • node-role.kubernetes.io/control-plane:NoSchedule

    • node-role.kubernetes.io/etcd:NoExecute

      注意
      注意

      其他任何容忍度必须添加到每个计划的 .spec.tolerations 部分下。与 Kubernetes 版本升级相关的 SUC 计划可以在 suse-edge/fleet-examples 储存库中的以下位置找到:

      • 对于 RKE2 - fleets/day2/system-upgrade-controller-plans/rke2-upgrade

      • 对于 K3s - fleets/day2/system-upgrade-controller-plans/k3s-upgrade

      请确保使用有效储存库版本标记中的计划。

      为 RKE2 控制平面 SUC 计划定义自定义容忍度的示例如下:

      apiVersion: upgrade.cattle.io/v1
      kind: Plan
      metadata:
        name: rke2-plan-control-plane
      spec:
        ...
        tolerations:
        # default tolerations
        - key: "CriticalAddonsOnly"
          operator: "Equal"
          value: "true"
          effect: "NoExecute"
        - key: "node-role.kubernetes.io/control-plane"
          operator: "Equal"
          effect: "NoSchedule"
        - key: "node-role.kubernetes.io/etcd"
          operator: "Equal"
          effect: "NoExecute"
        # custom toleration
        - key: "foo"
          operator: "Equal"
          value: "bar"
          effect: "NoSchedule"
      ...

25.4.3 升级过程

注意
注意

本节假设您将使用 Fleet(第 6 章 “Fleet)部署 SUC 计划。如果您打算使用其他方法部署 SUC 计划,请参见第 25.4.4.3 节 “SUC 计划部署 - 第三方 GitOps 工作流程”

Kubernetes 版本升级过程主要围绕着将 SUC 计划部署到下游群集来进行。这些计划包含的信息会告知 SUC 要在哪些节点上创建运行 rke2/k3s-upgrade 映像的 Pod。有关 SUC 计划结构的信息,请参见上游文档

Kubernetes 升级计划通过以下方式交付:

要确定使用哪个资源,请参见第 25.1.2 节 “确定您的用例”

有关更新过程中会发生哪些情况的完整概述,请参见第 25.4.3.1 节 “概述”一节。

25.4.3.1 概述

本节旨在介绍 Kubernetes 版本升级过程从头到尾的完整工作流程。

day2 k8s 版本升级流程图
图 25.5︰ Kubernetes 版本升级工作流程

Kubernetes 版本升级步骤:

  1. 用户可以根据用例,确定是要使用 GitRepo 还是捆绑包资源将 Kubernetes 升级 SUC 计划部署到所需的下游群集。有关如何将 GitRepo/捆绑包映射到特定的一组下游群集的信息,请参见映射到下游群集

    1. 如果您不确定是要使用 GitRepo 还是捆绑包资源进行 SUC 计划部署,请参见第 25.1.2 节 “确定您的用例”

    2. 有关 GitRepo/捆绑包配置选项,请参见第 25.4.4.1 节 “SUC 计划部署 - GitRepo 资源”第 25.4.4.2 节 “SUC 计划部署 - 捆绑包资源”

  2. 用户将配置的 GitRepo/捆绑包资源部署到其管理群集中的 fleet-default 名称空间。此操作可以手动完成,也可以通过 Rancher UI(如果可用)完成。

  3. Fleet(第 6 章 “Fleet)持续监控 fleet-default 名称空间,并立即检测新部署的 GitRepo/捆绑包资源。有关 Fleet 监控哪些名称空间的详细信息,请参见 Fleet 的名称空间文档。

  4. 如果用户已部署 GitRepo 资源,Fleet 将协调 GitRepo,并根据其路径fleet.yaml 配置,在 fleet-default 名称空间中部署捆绑包资源。有关详细信息,请参见 Fleet 的 GitRepo 内容文档。

  5. 然后,Fleet 继续将此捆绑包中的 Kubernetes 资源部署到所有目标下游群集。在 Kubernetes 版本升级的上下文中,Fleet 将部署捆绑包中的以下资源(具体取决于 Kubernetes 发行版):

    1. rke2-plan-agent/k3s-plan-agent - 告知 SUC 如何在群集代理节点上执行 Kubernetes 升级。如果群集仅由控制平面节点组成,则做解释。

    2. rke2-plan-control-plane/k3s-plan-control-plane - 告知 SUC 如何在群集控制平面节点上执行 Kubernetes 升级。

      注意
      注意

      上述 SUC 计划将部署在每个下游群集的 cattle-system 名称空间中。

  6. 在下游群集上,SUC 将拾取新部署的 SUC 计划,并在与 SUC 计划中定义的节点选择器匹配的每个节点上部署更新 Pod。有关如何监控 SUC 计划 Pod 的信息,请参见第 25.2.2.2 节 “监控 SUC 计划”

  7. 根据您部署的 SUC 计划更新 Pod 将运行 rke2-upgradek3s-upgrade 映像,并在每个群集节点上执行以下工作流程:

    1. 封锁群集节点 - 为了确保在升级此节点时不会意外调度任何 Pod,我们将此节点标记为不可调度

    2. 将节点操作系统上安装的 rke2/k3s 二进制文件替换为 Pod 当前正在运行的 rke2-upgrade/k3s-upgrade 映像附带的二进制文件。

    3. 终止节点操作系统上正在运行的 rke2/k3s 进程 - 这会指示监督程序使用新版本自动重启动 rke2/k3s 进程。

    4. 解封群集节点 - 成功完成 Kubernetes 发行版升级后,将节点重新标记为可调度

      注意
      注意

      有关 rke2-upgradek3s-upgrade 映像工作原理的更多信息,请参见 rke2-upgradek3s-upgrade 上游项目。

执行上述步骤后,每个群集节点的 Kubernetes 版本应会升级到所需的 Edge 兼容版本

25.4.4 Kubernetes 版本升级 - SUC 计划部署

25.4.4.1 SUC 计划部署 - GitRepo 资源

可通过以下方式之一部署 GitRepo 资源,该资源中附带了所需的 Kubernetes 升级 SUC 计划

  1. 通过 Rancher UI 部署 - 第 25.4.4.1.1 节 “GitRepo 创建 - Rancher UI”(如果 Rancher 可用)。

  2. 手动将相应资源部署(第 25.4.4.1.2 节 “GitRepo 创建 - 手动”)到管理群集

部署后,要监控目标群集节点的 Kubernetes 升级过程,请参见第 25.2.2.2 节 “监控 SUC 计划”文档。

25.4.4.1.1 GitRepo 创建 - Rancher UI
  1. 在左上角,选择 ☰ → Continuous Delivery(持续交付)

  2. 转到 Git 储存库 → 添加储存库

如果使用 suse-edge/fleet-examples 储存库,请执行以下步骤:

  1. 储存库 URL - https://github.com/suse-edge/fleet-examples.git

  2. 监视 → 修订版 - 为要使用的 suse-edge/fleet-examples 储存库选择版本标记

  3. 路径下,添加版本标记中显示的 Kubernetes 发行版升级 Fleet 路径:

    1. 对于 RKE2 - fleets/day2/system-upgrade-controller-plans/rke2-upgrade

    2. 对于 K3s - fleets/day2/system-upgrade-controller-plans/k3s-upgrade

  4. 选择下一步转到目标配置部分。请仅选择您要升级其中的所需 Kubernetes 发行版的群集

  5. 创建

或者,如果您决定使用自己的储存库来托管这些文件,则需要提供上述储存库数据。

25.4.4.1.2 GitRepo 创建 - 手动
  1. 选择您要从中应用 Kubernetes SUC 升级计划的所需 Edge 版本标记(在下文中用 ${REVISION} 表示)。

  2. 提取 GitRepo 资源:

    • 对于 RKE2 群集:

      curl -o rke2-upgrade-gitrepo.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/gitrepos/day2/rke2-upgrade-gitrepo.yaml
    • 对于 K3s 群集:

      curl -o k3s-upgrade-gitrepo.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/gitrepos/day2/k3s-upgrade-gitrepo.yaml
  3. 编辑 GitRepo 配置,在 spec.targets 下指定所需的目标列表。默认情况下,suse-edge/fleet-examples 中的 GitRepo 资源不会映射到任何下游群集。

    • 为了匹配所有群集,请将默认的 GitRepo 目标更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 或者,如果您要更细致地选择群集,请参见映射到下游群集

  4. GitRepo 资源应用于管理群集

    # RKE2
    kubectl apply -f rke2-upgrade-gitrepo.yaml
    
    # K3s
    kubectl apply -f k3s-upgrade-gitrepo.yaml
  5. 查看 fleet-default 名称空间下创建的 GitRepo 资源:

    # RKE2
    kubectl get gitrepo rke2-upgrade -n fleet-default
    
    # K3s
    kubectl get gitrepo k3s-upgrade -n fleet-default
    
    # Example output
    NAME           REPO                                              COMMIT          BUNDLEDEPLOYMENTS-READY   STATUS
    k3s-upgrade    https://github.com/suse-edge/fleet-examples.git   release-3.0.1   0/0
    rke2-upgrade   https://github.com/suse-edge/fleet-examples.git   release-3.0.1   0/0

25.4.4.2 SUC 计划部署 - 捆绑包资源

可通过以下方式之一部署捆绑包资源,该资源中附带了所需的 Kubernetes 升级 SUC 计划

  1. 通过 Rancher UI 部署 - 第 25.4.4.2.1 节 “捆绑包创建 - Rancher UI”(如果 Rancher 可用)。

  2. 手动将相应资源部署(第 25.4.4.2.2 节 “捆绑包创建 - 手动”)到管理群集

部署后,要监控目标群集节点的 Kubernetes 升级过程,请参见第 25.2.2.2 节 “监控 SUC 计划”文档。

25.4.4.2.1 捆绑包创建 - Rancher UI
  1. 在左上角,单击 ☰ → Continuous Delivery(持续交付)

  2. 转到高级 > 捆绑包

  3. 选择从 YAML 创建

  4. 此处可通过以下方式之一创建捆绑包:

    1. 通过手动将捆绑包内容复制到从 YAML 创建页面。可以检索内容:

    2. 通过将 suse-edge/fleet-examples 储存库克隆到所需的版本标记中,并在从 YAML 创建页面中选择从文件读取选项。然后导航到所需的捆绑包(对于 RKE2,为 /bundles/day2/system-upgrade-controller-plans/rke2-upgrade/plan-bundle.yaml;对于 K3s,为 /bundles/day2/system-upgrade-controller-plans/k3s-upgrade/plan-bundle.yaml)。这会在从 YAML 创建页面中自动填充捆绑包内容

  5. 更改捆绑包目标群集:

    • 为了匹配所有下游群集,请将默认的捆绑包 .spec.targets 更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 有关更精细的下游群集映射,请参见映射到下游群集

  6. 创建

25.4.4.2.2 捆绑包创建 - 手动
  1. 选择您要从中应用 Kubernetes SUC 升级计划的所需 Edge 版本标记(在下文中用 ${REVISION} 表示)。

  2. 提取捆绑包资源:

    • 对于 RKE2 群集:

      curl -o rke2-plan-bundle.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/bundles/day2/system-upgrade-controller-plans/rke2-upgrade/plan-bundle.yaml
    • 对于 K3s 群集:

      curl -o k3s-plan-bundle.yaml https://raw.githubusercontent.com/suse-edge/fleet-examples/${REVISION}/bundles/day2/system-upgrade-controller-plans/k3s-upgrade/plan-bundle.yaml
  3. 编辑捆绑包目标配置,在 spec.targets 下提供所需的目标列表。默认情况下,suse-edge/fleet-examples 中的捆绑包资源不会映射到任何下游群集。

    • 为了匹配所有群集,请将默认的捆绑包目标更改为:

      spec:
        targets:
        - clusterSelector: {}
    • 或者,如果您要更细致地选择群集,请参见映射到下游群集

  4. 捆绑包资源应用于管理群集

    # For RKE2
    kubectl apply -f rke2-plan-bundle.yaml
    
    # For K3s
    kubectl apply -f k3s-plan-bundle.yaml
  5. 查看 fleet-default 名称空间下创建的捆绑包资源:

    # For RKE2
    kubectl get bundles rke2-upgrade -n fleet-default
    
    # For K3s
    kubectl get bundles k3s-upgrade -n fleet-default
    
    # Example output
    NAME           BUNDLEDEPLOYMENTS-READY   STATUS
    k3s-upgrade    0/0
    rke2-upgrade   0/0

25.4.4.3 SUC 计划部署 - 第三方 GitOps 工作流程

在某些用例中,用户可能希望将 Kubernetes 升级资源合并到他们自己的第三方 GitOps 工作流程(例如 Flux)中。

要获取所需的升级资源,首先请确定您要使用的 suse-edge/fleet-examples 储存库的 Edge 版本标记。

然后,便可以在以下位置查找资源:

  • 对于 RKE2 群集升级:

    • 对于控制平面节点 - fleets/day2/system-upgrade-controller-plans/rke2-upgrade/plan-control-plane.yaml

    • 对于代理节点 - fleets/day2/system-upgrade-controller-plans/rke2-upgrade/plan-agent.yaml

  • 对于 K3s 群集升级:

    • 对于控制平面节点 - fleets/day2/system-upgrade-controller-plans/k3s-upgrade/plan-control-plane.yaml

    • 对于代理节点 - fleets/day2/system-upgrade-controller-plans/k3s-upgrade/plan-agent.yaml

重要
重要

这些计划资源由系统升级控制器解释,应部署在您要升级的每个下游群集上。有关如何部署系统升级控制器的信息,请参见第 25.2.1.3 节 “使用第三方 GitOps 工作流程时部署系统升级控制器”

为了更好地了解如何使用 GitOps 工作流程来部署 Kubernetes 版本升级的 SUC 计划,建议查看有关使用 Fleet 进行更新的过程概述(第 25.4.3.1 节 “概述”)。

25.5 Helm chart 升级

注意
注意

以下章节重点介绍如何使用 Fleet 功能实现 Helm chart 更新。

采用第三方 GitOps 工作流程的用户应从 fleets/day2/chart-templates/<chart-name> 中的 fleet.yaml 文件获取所需 Helm chart 的配置。请确保从有效的“Day 2”Edge 版本中检索 chart 数据。

25.5.1 组件

除了默认的 Day 2 组件(第 25.1.1 节 “组件”)之外,此操作不需要其他自定义组件。

25.5.2 为隔离环境做好准备

25.5.2.1 确保您有权访问 Helm chart 的升级 fleet.yaml 文件

将所需的资源托管在管理群集可访问的本地 git 服务器上。

25.5.2.2 找到 Edge 发行版本的所需资产

  1. 转到 Day 2 版本页面,找到您要将 chart 升级到的 Edge 3.X.Y 版本,然后单击资产

  2. 从该版本的资产部分下载以下文件,对 SUSE 支持的 Helm chart 进行隔离式升级时需要这些文件:

    版本文件

    说明

    edge-save-images.sh

    此脚本提取 edge-release-images.txt 文件中的映像并将其保存到“.tar.gz”存档中,然后您可以在隔离环境中使用该存档。

    edge-save-oci-artefacts.sh

    此脚本提取 edge-release-helm-oci-artefacts.txt 文件中的 SUSE OCI chart 项目,并为包含所有其他 chart OCI 存档的目录创建“.tar.gz”存档。

    edge-load-images.sh

    此脚本加载 edge-save-images.sh 生成的“.tar.gz”存档中的映像,重新标记这些映像并将其推送到专用注册表中。

    edge-load-oci-artefacts.sh

    此脚本获取包含“.tgz”SUSE OCI chart 的目录,并将所有 OCI chart 加载到专用注册表中。该目录是从 edge-save-oci-artefacts.sh 脚本生成的“.tar.gz”存档中检索的。

    edge-release-helm-oci-artefacts.txt

    此文件包含 SUSE Edge 版本 Helm chart 的 OCI 项目列表。

    edge-release-images.txt

    此文件包含 Edge 版本 Helm chart 所需的映像列表。

25.5.2.3 创建 SUSE Edge 版本映像存档

在可以访问互联网的计算机上:

  1. edge-save-images.sh 设为可执行文件:

    chmod +x edge-save-images.sh
  2. 使用 edge-save-images.sh 脚本创建 Docker 可导入的“.tar.gz”存档:

    ./edge-save-images.sh --source-registry registry.suse.com
  3. 这会创建一个随时可加载的 edge-images.tar.gz(除非指定了 -i|--images 选项)存档,其中包含所需的映像。

  4. 将此存档复制到隔离的计算机

    scp edge-images.tar.gz <user>@<machine_ip>:/path

25.5.2.4 创建 SUSE Edge Helm chart OCI 映像存档

在可以访问互联网的计算机上:

  1. edge-save-oci-artefacts.sh 设为可执行文件:

    chmod +x edge-save-oci-artefacts.sh
  2. 使用 edge-save-oci-artefacts.sh 脚本创建包含所有 SUSE Edge Helm chart OCI 映像的“.tar.gz”存档:

    ./edge-save-oci-artefacts.sh --source-registry registry.suse.com
  3. 这会创建一个包含所有 SUSE Edge Helm chart OCI 映像的 oci-artefacts.tar.gz 存档

  4. 将此存档复制到隔离的计算机

    scp oci-artefacts.tar.gz <user>@<machine_ip>:/path

25.5.2.5 将 SUSE Edge 版本映像加载到隔离的计算机上

在隔离的计算机上:

  1. 登录到专用注册表(如果需要):

    podman login <REGISTRY.YOURDOMAIN.COM:PORT>
  2. edge-load-images.sh 设为可执行文件:

    chmod +x edge-load-images.sh
  3. 使用 edge-load-images.sh复制的 edge-images.tar.gz 存档中加载映像,重新标记这些映像并将其推送到专用注册表中:

    ./edge-load-images.sh --source-registry registry.suse.com --registry <REGISTRY.YOURDOMAIN.COM:PORT> --images edge-images.tar.gz

25.5.2.6 将 SUSE Edge Helm chart OCI 映像加载到隔离的计算机上

在隔离的计算机上:

  1. 登录到专用注册表(如果需要):

    podman login <REGISTRY.YOURDOMAIN.COM:PORT>
  2. edge-load-oci-artefacts.sh 设为可执行文件:

    chmod +x edge-load-oci-artefacts.sh
  3. 解压缩复制的 oci-artefacts.tar.gz 存档:

    tar -xvf oci-artefacts.tar.gz
  4. 这会使用命名模板 edge-release-oci-tgz-<date> 生成一个目录

  5. 将此目录传递给 edge-load-oci-artefacts.sh 脚本,以将 SUSE Edge Helm chart OCI 映像加载到专用注册表中:

    注意
    注意

    此脚本假设您的环境中已预装了 Helm CLI。有关 Helm 安装说明,请参见安装 Helm

    ./edge-load-oci-artefacts.sh --archive-directory edge-release-oci-tgz-<date> --registry <REGISTRY.YOURDOMAIN.COM:PORT> --source-registry registry.suse.com

25.5.2.7 为 Kubernetes 发行版创建指向专用注册表的注册表镜像

对于 RKE2,请参见 Containerd 注册表配置

对于 K3s,请参见嵌入式注册表镜像

25.5.3 升级过程

注意
注意

以下升级过程利用 Rancher 的 Fleet(第 6 章 “Fleet)功能。使用第三方 GitOps 工作流程的用户应根据第 33.1 节 “摘要”中所述检索每个 Edge 版本支持的 chart 版本,并将这些支持的版本填充到其第三方 GitOps 工作流程中。

本节重点介绍以下用例的 Helm 升级过程:

  1. 我有一个新群集,想要部署和管理 SUSE Helm chart(第 25.5.3.1 节 “我有一个新群集,想要部署和管理 SUSE Helm chart”

  2. 我想升级 Fleet 管理的 Helm chart(第 25.5.3.2 节 “我想升级 Fleet 管理的 Helm chart”

  3. 我想升级 EIB 创建的 Helm chart(第 25.5.3.3 节 “我想升级 EIB 创建的 Helm chart”

重要
重要

手动部署的 Helm chart 无法可靠升级。我们建议使用第 25.5.3.1 节 “我有一个新群集,想要部署和管理 SUSE Helm chart”方法重新部署这些 Helm chart。

25.5.3.1 我有一个新群集,想要部署和管理 SUSE Helm chart

适用于想要通过 Fleet 管理其 Helm chart 生命周期的用户。

25.5.3.1.1 准备 Fleet 资源
  1. 从您要使用的 Edge 版本标记中获取 Chart 的 Fleet 资源

    1. 从选定的 Edge 版本标记修订版导航到 Helm chart Fleet 目录 - fleets/day2/chart-templates/<chart>

    2. 将该 chart Fleet 目录复制到用于 GitOps 工作流程的 Git 储存库

    3. (可选)如果 Helm chart 需要对其进行配置,请编辑复制的目录中 fleet.yaml 文件内的 .helm.values 配置

    4. (可选)在某些用例中,您可能需要向 chart 的 Fleet 目录添加其他资源,使该目录能够更好地适应您的环境。有关如何增强 Fleet 目录的信息,请参见 Git 储存库内容

longhorn Helm chart 的示例如下:

  • 用户 Git 储存库结构:

    <user_repository_root>
    └── longhorn
        └── fleet.yaml
  • 填充了用户 longhorn 数据的 fleet.yaml 内容:

    defaultNamespace: longhorn-system
    
    helm:
      releaseName: "longhorn"
      chart: "longhorn"
      repo: "https://charts.longhorn.io"
      version: "1.6.1"
      takeOwnership: true
      # custom chart value overrides
      values:
        # Example for user provided custom values content
        defaultSettings:
          deletingConfirmationFlag: true
    
    # https://fleet.rancher.io/bundle-diffs
    diff:
      comparePatches:
      - apiVersion: apiextensions.k8s.io/v1
        kind: CustomResourceDefinition
        name: engineimages.longhorn.io
        operations:
        - {"op":"remove", "path":"/status/conditions"}
        - {"op":"remove", "path":"/status/storedVersions"}
        - {"op":"remove", "path":"/status/acceptedNames"}
      - apiVersion: apiextensions.k8s.io/v1
        kind: CustomResourceDefinition
        name: nodes.longhorn.io
        operations:
        - {"op":"remove", "path":"/status/conditions"}
        - {"op":"remove", "path":"/status/storedVersions"}
        - {"op":"remove", "path":"/status/acceptedNames"}
      - apiVersion: apiextensions.k8s.io/v1
        kind: CustomResourceDefinition
        name: volumes.longhorn.io
        operations:
        - {"op":"remove", "path":"/status/conditions"}
        - {"op":"remove", "path":"/status/storedVersions"}
        - {"op":"remove", "path":"/status/acceptedNames"}
    注意
    注意

    上面只是一些示例值,用于演示基于 longhorn chart 创建的自定义配置。不应将它们视为 longhorn chart 的部署指南。

25.5.3.1.2 创建 GitRepo

在储存库中填充 chart 的 Fleet 资源后,必须创建 GitRepo 资源。此资源将包含有关如何访问 chart 的 Fleet 资源以及需要将这些资源应用于哪些群集的信息。

可以通过 Rancher UI 或者通过将资源手动部署到管理群集来创建 GitRepo 资源。

有关如何手动创建和部署 GitRepo 资源的信息,请参见创建部署

要通过 Rancher UI 创建 GitRepo 资源,请参见在 Rancher UI 中访问 Fleet

用于手动部署的 longhorn GitRepo 资源示例:

apiVersion: fleet.cattle.io/v1alpha1
kind: GitRepo
metadata:
  name: longhorn-git-repo
  namespace: fleet-default
spec:
  # If using a tag
  # revision: <user_repository_tag>
  #
  # If using a branch
  # branch: <user_repository_branch>
  paths:
  # As seen in the 'Prepare your Fleet resources' example
  - longhorn
  repo: <user_repository_url>
  targets:
  # Match all clusters
  - clusterSelector: {}
25.5.3.1.3 管理部署的 Helm chart

通过 Fleet 部署后,要进行 Helm chart 升级,请参见第 25.5.3.2 节 “我想升级 Fleet 管理的 Helm chart”

25.5.3.2 我想升级 Fleet 管理的 Helm chart

  1. 确定需要将 chart 升级到哪个版本,以便它与 Edge 3.X.Y 版本兼容。可以在第 33.1 节 “摘要”中查看每个 Edge 版本的 Helm chart 版本。

  2. 在 Fleet 监控的 Git 储存库中,根据第 33.1 节 “摘要”中所述使用正确的 chart 版本储存库编辑 Helm chart 的 fleet.yaml 文件。

  3. 提交更改并将其推送到储存库后,会触发所需 Helm chart 的升级

25.5.3.3 我想升级 EIB 创建的 Helm chart

注意
注意

本节假设您已预先部署了系统升级控制器 (SUC),如果您尚未部署,或者不确定为何需要 SUC,请参见默认的 Day 2 组件(第 25.1.1 节 “组件”)列表。

EIB 利用 rke2/k3s 的自动部署清单功能来部署 Helm chart。它在初始化器节点的 /var/lib/rancher/<rke2/k3s>/server/manifests 位置创建 HelmChart 资源定义清单,然后让 rke2/k3s 拾取该清单并将其自动部署到群集中。

Day 2 的角度看,这意味着对 Helm chart 的任何升级都需要通过编辑特定 chart的 HelmChart 清单文件来进行。为了对多个群集自动完成此过程,本节使用了 SUC 计划

有关信息,请参见以下资源:

25.5.3.3.1 概述

本节旨在概述用户升级一个或多个 Helm chart 所要执行的工作流程。有关完成 Helm chart 升级所要执行的步骤的详细说明,请参见第 25.5.3.3.2 节 “升级步骤”

day2 Helm chart 升级流程图
图 25.6︰ Helm chart 升级工作流程
  1. 该工作流程的第一个步骤是用户提取其 chart 要升级到的新 Helm chart 存档。

  2. 然后对存档进行编码,并将其作为配置传递到位于相关 SUC 计划的 Fleet 目录下的 eib-chart-upgrade-user-data.yaml 文件中。“升级步骤”(第 25.5.3.3.2 节 “升级步骤”)一节会进一步解释此过程。

  3. 然后,用户继续配置并部署 GitRepo 资源,用于将全部所需的资源(SUC 计划、密钥等)传送到下游群集。

    1. 该资源部署在管理群集上的 fleet-default 名称空间下。

  4. Fleet(第 6 章 “Fleet)检测部署的资源,并将配置的所有资源部署到指定的下游群集。部署的资源包括:

    1. eib-chart-upgrade SUC 计划,SUC 将使用它在每个节点上创建升级 Pod

    2. eib-chart-upgrade-script 密钥,其中附带升级脚本升级 Pod 将使用该脚本来升级初始化器节点上的 HelmChart 清单。

    3. eib-chart-upgrade-user-data 密钥,其中附带 chart 数据,升级脚本将使用这些数据来了解需要升级哪些 chart 清单。

  5. 部署 eib-chart-upgrade SUC 计划后,SUC 将拾取该计划并创建一个用于部署升级 Pod 的作业。

  6. 部署后,升级 Pod 将挂载 eib-chart-upgrade-scripteib-chart-upgrade-user-data 密钥,并执行 eib-chart-upgrade-script 密钥附带的升级脚本

  7. 升级脚本执行以下操作:

    1. 确定运行脚本的 Pod 是否已部署在初始化器节点上。初始化器节点是托管 HelmChart 清单的节点。对于单节点群集,它是单个控制平面节点。对于 HA 群集,它是您在 EIB 中创建群集时标记为初始化器的节点。如果您未指定 initializer 属性,则节点列表中的第一个节点将标记为初始化器。有关详细信息,请参见 EIB 的上游文档

      注意
      注意

      如果升级脚本在非初始化器节点上运行,则它会立即完成执行,而不会执行下面的步骤。

    2. 备份要编辑的清单,以确保能够实现灾难恢复。

      注意
      注意

      默认情况下,清单的备份存储在 /tmp/eib-helm-chart-upgrade-<date> 目录下。如果您要使用自定义位置,可以将 MANIFEST_BACKUP_DIR 环境变量传递给 Helm chart 升级 SUC 计划(计划中的示例)。

    3. 编辑 HelmChart 清单。从此版本开始,已更改以下属性以触发 chart 升级:

      1. chartContent 属性的内容已替换为 eib-chart-upgrade-user-data 密钥中提供的经过编码的存档。

      2. version 属性的值已替换为 eib-chart-upgrade-user-data 密钥中提供的版本。

  8. 成功执行升级脚本后,RKE2/K3s 的 Helm 集成将拾取更改并自动触发 Helm chart 的升级。

25.5.3.3.2 升级步骤
  1. 确定您要从中复制 Helm chart 升级逻辑的 Edge 版本标记

  2. fleets/day2/system-upgrade-controller-plans/eib-chart-upgrade Fleet 目录复制到将由 Fleet 用来执行 GitOps 的储存库。

  3. 提取您要升级到的 Helm chart 存档:

    helm pull [chart URL | repo/chartname]
    
    # Alternatively if you want to pull a specific version:
    # helm pull [chart URL | repo/chartname] --version 0.0.0
  4. 对提取的 chart 存档进行编码:

    # Encode the archive and disable line wrapping
    base64 -w 0 <chart-archive>.tgz
  5. 配置您在步骤 2 中复制的 eib-chart-upgrade Fleet 目录下的 eib-chart-upgrade-user-data.yaml 密钥:

    1. 该密钥附带一个名为 chart_upgrade_data.txt 的文件。此文件包含 chart 升级数据,升级脚本将使用这些数据来了解哪些 chart 需要升级。该文件要求以每个 chart 项一行的形式指定配置项,其格式如下:“<name>|<version>|<base64_encoded_archive>”

      1. name - Helm chart 的名称,如 EIB 定义文件的 kubernetes.helm.charts.name[] 属性中所示。

      2. version - 应包含 Helm chart 的新版本。在升级期间,此值用于替换 HelmChart 清单的旧 version 值。

      3. base64_encoded_archive - 在此处传递 base64 -w 0 <chart-archive>.tgz 的输出。在升级期间,此值用于替换 HelmChart 清单的旧 chartContent 值。

        注意
        注意

        在开始添加数据之前,应从该文件中去除 <name>|<version>|<base64_encoded_archive> 行。它是一个示例行,用于说明在何处以及如何配置 chart 数据。

  6. 配置一个 GitRepo 资源用于传送 chart 升级 fleet。有关 GitRepo 的详细信息,请参见 GitRepo 资源

    1. 通过 Rancher UI 配置 GitRepo

      1. 在左上角,选择 ☰ → Continuous Delivery(持续交付)

      2. 转到 Git 储存库 → 添加储存库

      3. 在此处将您的储存库数据路径传递给 chart 升级 fleet

      4. 选择下一步,并指定您要对其中已配置的 chart 进行升级的目标群集

      5. 创建

    2. 如果无法对您的设置使用 Rancher,可以在管理群集上手动配置 GitRepo

      1. 在以下模板中填充您的数据:

        apiVersion: fleet.cattle.io/v1alpha1
        kind: GitRepo
        metadata:
          name: CHANGE_ME
          namespace: fleet-default
        spec:
          # if running from a tag
          # revision: CHANGE_ME
          # if running from a branch
          # branch: CHANGE_ME
          paths:
          # path to your chart upgrade fleet relative to your repository
          - CHANGE_ME
          # your repository URL
          repo: CHANGE_ME
          targets:
          # Select target clusters
          - clusterSelector: CHANGE_ME
          # To match all clusters:
          # - clusterSelector: {}

        有关如何设置和部署 GitRepo 资源的详细信息,请参见 GitRepo 资源创建 GitRepo 资源

        有关如何在更精细的级别匹配目标群集的信息,请参见映射到下游群集

      2. 将配置的 GitRepo 资源部署到管理群集fleet-default 名称空间。

执行这些步骤后,应该可以成功创建 GitRepo 资源。然后,Fleet 将拾取该资源,并创建捆绑包。此捆绑包将包含 GitRepo 在其 Fleet 目录下配置的原始 Kubernetes 资源。

然后,Fleet 会将捆绑包中的所有 Kubernetes 资源部署到指定的下游群集。其中一个资源是触发 chart 升级的 SUC 计划。有关要部署的资源的完整列表以及升级过程的工作流程,请参见“概述”(第 25.5.3.3.1 节 “概述”)一节。

要跟踪升级过程本身,请参见“监控 SUC 计划”(第 25.2.2.2 节 “监控 SUC 计划”)一节。

25.5.3.3.3 示例

下面一节将为第 25.5.3.3.2 节 “升级步骤”一节提供真实示例。

我通过 EIB 部署了以下两个群集:

  • longhorn-single-k3s - 单节点 K3s 群集

  • longhorn-ha-rke2 - HA RKE2 群集

这两个群集都运行 Longhorn,并已使用以下映像定义片段通过 EIB 进行部署:

kubernetes:
  # HA RKE2 cluster specific snippet
  # nodes:
  # - hostname: cp1rke2.example.com
  #   initializer: true
  #   type: server
  # - hostname: cp2rke2.example.com
  #   type: server
  # - hostname: cp3rke2.example.com
  #   type: server
  # - hostname: agent1rke2.example.com
  #   type: agent
  # - hostname: agent2rke2.example.com
  #   type: agent
  # version depending on the distribution
  version: v1.28.9+k3s1/v1.28.9+rke2r1
  helm:
    charts:
    - name: longhorn
      repositoryName: longhorn
      targetNamespace: longhorn-system
      createNamespace: true
      version: 1.5.5
    repositories:
    - name: longhorn
      url: https://charts.longhorn.io
...
day2 Helm chart 升级 - k3s 旧版示例
图 25.7︰ longhorn-single-k3s 安装的 Longhorn 版本
day2 Helm chart 升级 - rke2 旧版示例
图 25.8︰ longhorn-ha-rke2 安装的 Longhorn 版本

这种部署的问题在于,longhorn-single-k3slonghorn-ha-rke2 当前运行的 Longhorn 版本与任何 Edge 版本都不兼容。

我们需要将这两个群集上的 chart 升级到 Edge 支持的 Longhorn 版本。

为此,我们需要执行以下步骤:

  1. 确定我们要从中获取升级逻辑的 Edge 版本标记。例如,此示例将使用 release-3.0.1 版本标记,它支持的 Longhorn 版本为 1.6.1

  2. 克隆 release-3.0.1 版本标记,并将 fleets/day2/system-upgrade-controller-plans/eib-chart-upgrade 目录复制到我们自己的储存库。

    为简单起见,本节将根据 suse-edge/fleet-examples 储存库的某个分支介绍操作步骤,因此目录结构是相同的,但您可以将 eib-chart-upgrade Fleet 目录放入您的储存库中的任何位置。

    目录结构示例:

    .
    ...
    |-- fleets
    |   `-- day2
    |       `-- system-upgrade-controller-plans
    |           `-- eib-chart-upgrade
    |               |-- eib-chart-upgrade-script.yaml
    |               |-- eib-chart-upgrade-user-data.yaml
    |               |-- fleet.yaml
    |               `-- plan.yaml
    ...

  3. 添加 Longhorn chart 储存库:

    helm repo add longhorn https://charts.longhorn.io
  4. 提取 Longhorn chart 版本 1.6.1

    helm pull longhorn/longhorn --version 1.6.1

    这会将 Longhorn 作为名为 longhorn-1.6.1.tgz 的存档来提取。

  5. 对 Longhorn 存档进行编码:

    base64 -w 0 longhorn-1.6.1.tgz

    这会输出该存档的采用 base64 编码的单行字符串。

  6. 现在我们已准备好全部所需的数据,可以配置 eib-chart-upgrade-user-data.yaml 文件。文件配置应如下所示:

    apiVersion: v1
    kind: Secret
    metadata:
      name: eib-chart-upgrade-user-data
    type: Opaque
    stringData:
      # <name>|<version>|<base64_encoded_archive>
      chart_upgrade_data.txt: |
        longhorn|1.6.1|H4sIFAAAAAAA/ykAK2FIUjBjSE02THk5NWIzV...
    1. longhorn 是 EIB 定义文件中所示的 chart 名称

    2. 1.6.1 是要将 Longhorn HelmChart 清单的 version 属性升级到的版本

    3. H4sIFAAAAAAA/ykAK2FIUjBjSE02THk5NWIzV... 是经过编码的 Longhorn 1.6.1 存档的片段。此处添加了片段是为了方便阅读。您始终应在此处提供完整的采用 base64 编码的存档字符串。

      注意
      注意

      此示例显示了单个 chart 的升级配置,如果您的用例需要升级多个群集上的多个 chart,您可以追加其他 chart 数据,如下所示:

      apiVersion: v1
      kind: Secret
      metadata:
        name: eib-chart-upgrade-user-data
      type: Opaque
      stringData:
        # <name>|<version>|<base64_encoded_archive>
        chart_upgrade_data.txt: |
          chartA|0.0.0|<chartA_base64_archive>
          chartB|0.0.0|<chartB_base64_archive>
          chartC|0.0.0|<chartC_base64_archive>
          ...
  7. 我们还确定不要在 /tmp 中保留清单备份,因此在 plan.yaml 文件中添加了以下配置:

    apiVersion: upgrade.cattle.io/v1
    kind: Plan
    metadata:
      name: eib-chart-upgrade
    spec:
      ...
      upgrade:
        ...
        # For when you want to backup your chart
        # manifest data under a specific directory
        #
        envs:
        - name: MANIFEST_BACKUP_DIR
          value: "/root"

    这可以确保将清单备份保存在 /root 目录而不是 /tmp 中。

  8. 完成全部所需的配置后,剩下的操作就是创建 GitRepo 资源。此示例通过 Rancher UI 创建 GitRepo 资源。

  9. 根据“升级步骤”(第 25.5.3.3.2 节 “升级步骤”)中所述的步骤,我们已经:

    1. GitRepo 命名为“longhorn-upgrade”。

    2. 将 URL 传递给要使用的储存库 - https://github.com/suse-edge/fleet-examples.git

    3. 传递储存库的分支 -“doc-example”

    4. 传递储存库中显示的 eib-chart-upgrade Fleet 目录路径 - fleets/day2/system-upgrade-controller-plans/eib-chart-upgrade

    5. 选择目标群集并创建资源

      day2 Helm chart 升级 - GitRepo 示例
      图 25.9︰ 成功部署 SUC 和 Longhorn GitRepo

现在我们需要监控群集上的升级过程:

  1. 按照“监控 SUC 计划”(第 25.2.2.2 节 “监控 SUC 计划”)一节中的指导,检查升级 Pod 的状态。

    1. 已成功完成的、在初始化器节点上运行的升级 Pod 应会保存如下所示的日志:

      day2 Helm chart 升级 - 初始化器日志示例
      图 25.10︰ 升级初始化器节点上运行的 Pod
    2. 已成功完成的、在非初始化器节点上运行的升级 Pod 应会保存如下所示的日志:

      day2 Helm chart 升级 - 非初始化器日志示例
      图 25.11︰ 升级非初始化器节点上运行的 Pod
  2. 升级 Pod 成功完成后,我们还需要等待 Helm 控制器创建 Pod 并监控这些 Pod。这些 Pod 将根据升级 PodHelmChart 清单文件所做的文件更改执行实际升级。

    1. 在您的群集中,转到工作负载 → Pod,然后在 default 名称空间中搜索包含 longhorn 字符串的 Pod。这会使用命名模板 helm-install-longhorn-* 生成一个 Pod,请查看此 Pod 的日志。

      day2 Helm chart 升级 - Helm 安装示例
      图 25.12︰ 已成功完成的 helm-install Pod
    2. 日志应如下所示:

      day2 Helm chart 升级 - 已成功升级的 Pod 示例
      图 25.13︰ 已成功完成的 helm-install Pod 的日志

确保一切成功完成后,我们需要校验版本是否已更改:

  1. 在群集上,转到更多资源 → Helm → HelmChart,然后在 default 名称空间中搜索 longhorn HelmChart 资源:

    day2 Helm chart 升级 - k3s Longhorn 升级示例
    图 25.14︰ longhorn-single-k3s 上已升级的 Longhorn 版本
    day2 Helm chart 升级 - rke2 Longhorn 升级示例
    图 25.15︰ longhorn-ha-rke2 上已升级的 Longhorn 版本

此结果确认 Longhorn Helm chart 已成功升级,本示例到此结束。

如果出于某种原因,我们想要还原到 Longhorn 的前一 chart 版本,可以在初始化器节点上的 /root/longhorn.yaml 中找到旧版 Longhorn 清单。这是肯定的,因为我们已在 SUC 计划中指定了 MANIFEST_BACKUP_DIR

25.5.3.3.4 使用第三方 GitOps 工具进行 Helm chart 升级

在某些用例中,用户可能希望将此升级过程与除 Fleet 以外的 GitOps 工作流程(例如 Flux)配合使用。

要获取与 EIB 所部署的 Helm chart 升级相关的资源,需要首先确定您要使用的 suse-edge/fleet-examples 储存库的 Edge 版本标记。

然后,便可以在 fleets/day2/system-upgrade-controller-plans/eib-chart-upgrade 中查找资源,其中:

  • plan.yaml - 与升级过程相关的系统升级控制器计划。

  • eib-chart-upgrade-script.yaml - 密钥,其中包含负责编辑和升级 HelmChart 清单文件的升级脚本

  • eib-chart-upgrade-user-data.yaml - 密钥,其中包含升级脚本使用的文件;用户需事先在其中填充相关的 chart 升级数据。

重要
重要

这些计划资源由系统升级控制器解释,应部署在包含需要升级的 chart 的每个下游群集上。有关如何部署系统升级控制器的信息,请参见第 25.2.1.3 节 “使用第三方 GitOps 工作流程时部署系统升级控制器”

为了更好地了解如何使用 GitOps 工作流程来为升级过程部署 SUC 计划,建议查看有关使用 Fleet 进行升级的过程概述(第 25.5.3.3.1 节 “概述”)。

第 VI 部分 产品文档

在这里查找 ATIP 文档

  • 26 SUSE 自适应电信基础架构平台 (ATIP)
  • SUSE 自适应电信基础架构平台 (ATIP) 是针对电信行业进行优化的边缘计算平台,可帮助电信公司实现创新并加速其网络的现代化改造。

  • 27 概念和体系结构
  • SUSE ATIP 是旨在用于托管从核心到边缘规模的现代云原生电信应用程序的平台。

  • 28 要求和假设
  • ATIP 节点的硬件要求基于以下组件:

  • 29 设置管理群集
  • 管理群集是用于管理运行时堆栈的置备和生命周期的 ATIP 组成部分。从技术角度讲,管理群集包含以下组件:

  • 30 电信功能配置
  • 本章将阐释部署了 ATIP 的群集上特定于电信的功能配置。

  • 31 全自动定向网络置备
  • 定向网络置备是用于自动置备下游群集的功能。如果您有许多下游群集需要置备并希望自动完成该过程,此功能将非常有用。

  • 32 生命周期操作
  • 本章介绍已部署的 ATIP 群集的生命周期管理操作。

26 SUSE 自适应电信基础架构平台 (ATIP)

SUSE 自适应电信基础架构平台 (ATIP) 是针对电信行业进行优化的边缘计算平台,可帮助电信公司实现创新并加速其网络的现代化改造。

ATIP 是一个完整的电信云堆栈,用于托管 5G 分组核心和云 RAN 等云原生网络功能 (CNF)。

  • 对电信规模的复杂边缘堆栈配置实现自动化零接触式部署和生命周期管理。

  • 使用特定于电信公司的配置和工作负载持续保证电信级硬件的质量。

  • 由专用于边缘的组件构成,因此占用空间更小,并且性能功耗比更高。

  • 通过与供应商无关的 API 和完全开源性来维持灵活的平台策略。

27 概念和体系结构

SUSE ATIP 是旨在用于托管从核心到边缘规模的现代云原生电信应用程序的平台。

本页介绍 ATIP 中使用的体系结构和组件。了解这些知识将有助于部署和使用 ATIP。

27.1 ATIP 体系结构

下图显示了 ATIP 的概要体系结构:

ATIP 产品体系结构 1

27.2 组件

有两个不同的区块 - 管理堆栈和运行时堆栈:

  • 管理堆栈:ATIP 的这一组成部分用于管理运行时堆栈的置备和生命周期。管理堆栈包括以下组件:

    • 使用 Rancher 在公有云和私有云环境中进行多群集管理(第 4 章 “Rancher

    • 使用 Metal3(第 8 章 “Metal3)、MetalLB(第 17 章 “MetalLB)和 CAPI(群集 API)基础架构提供程序来提供裸机支持

    • 全面的租户隔离和 IDP(身份提供程序)集成

    • 第三方集成和扩展大型商城

    • 不区分供应商的 API 和丰富的提供商生态系统

    • 控制 SLE Micro 事务更新

    • GitOps 引擎,可以结合使用 Git 储存库和 Fleet(第 6 章 “Fleet)来管理群集的生命周期

  • 运行时堆栈:ATIP 的这一组成部分用于运行工作负载。

    • 包含 K3s(第 13 章 “K3s)和 RKE2(第 14 章 “RKE2)等安全轻量级发行版的 Kubernetes(RKE2 已针对政府用途和受监管行业进行强化、认证和优化)。

    • NeuVector(第 16 章 “NeuVector),可用于实现映像漏洞扫描、深度包检测和群集内自动流量控制等安全功能。

    • 包含 Longhorn(第 15 章 “Longhorn)的块存储,让您可以方便地使用云原生存储解决方案。

    • 包含 SLE Micro(第 7 章 “SLE Micro)的优化操作系统,可以启用安全、轻量且不可变(事务文件系统)的操作系统来运行容器。SLE Micro 适用于 aarch64x86_64 体系结构,还支持用于电信和边缘用例的实时内核

27.3 部署流程示例

下面是工作流程的简要示例,可帮助您了解管理组件与运行时组件之间的关系。

定向网络置备是可用于部署预配置了所有组件,并可以在无需人工干预的情况下运行工作负载的新下游群集的工作流程。

27.3.1 示例 1:部署装有所有组件的新管理群集

使用 Edge Image Builder(第 9 章 “Edge Image Builder)创建包含管理堆栈的新 ISO 映像。然后,可以使用此 ISO 映像在 VM 或裸机上安装新管理群集。

ATIP 产品体系结构 2
注意
注意

有关如何部署新管理群集的详细信息,请参见 ATIP 管理群集指南(第 29 章 “设置管理群集)。

注意
注意

有关如何使用 Edge Image Builder 的详细信息,请参见 Edge Image Builder 指南(第 3 章 “使用 Edge Image Builder 配置独立群集)。

27.3.2 示例 2:使用电信配置文件部署单节点下游群集,使其能够运行电信工作负载

启动并运行管理群集后,我们可以使用该群集通过定向网络置备工作流程,来部署启用并配置了所有电信功能的单节点下游群集。

下图显示了部署该群集的概要工作流程:

ATIP 产品体系结构 3
注意
注意

有关如何部署下游群集的详细信息,请参见 ATIP 自动置备指南(第 31 章 “全自动定向网络置备)。

注意
注意

有关电信功能的详细信息,请参见 ATIP 电信功能指南(第 30 章 “电信功能配置)。

27.3.3 示例 3:使用 MetalLB 作为负载平衡器部署高可用性下游群集

启动并运行管理群集后,我们可以使用该群集通过定向网络置备工作流程,来部署使用 MetalLB 作为负载平衡器的高可用性下游群集。

下图显示了部署该群集的概要工作流程:

ATIP 产品体系结构 4
注意
注意

有关如何部署下游群集的详细信息,请参见 ATIP 自动置备指南(第 31 章 “全自动定向网络置备)。

注意
注意

有关 MetalLB 的详细信息,请参见第 17 章 “MetalLB

28 要求和假设

28.1 硬件

ATIP 节点的硬件要求基于以下组件:

  • 管理群集:管理群集包含 SLE MicroRKE2Rancher PrimeMetal3 等组件,用于管理多个下游群集。服务器的硬件要求可能根据所要管理的下游群集数量而有所不同。

    • 服务器(VM裸机)的最低要求如下:

      • RAM:至少 8 GB(建议至少提供 16 GB)

      • CPU:至少 2 个(建议至少提供 4 个 CPU)

  • 下游群集:下游群集是部署在 ATIP 节点上的群集,用于运行电信工作负载。需要满足特定的要求才能启用 SR-IOVCPU 性能优化等某些电信功能。

    • SR-IOV:要以直通模式将 VF(虚拟功能)挂接到 CNF/VNF,NIC 必须支持 SR-IOV,并且必须在 BIOS 中启用 VT-d/AMD-Vi。

    • CPU 处理器:要运行特定的电信工作负载,应该适配 CPU 处理器型号,以启用此参考表格(第 30 章 “电信功能配置)中所述的大多数功能。

    • 使用虚拟媒体进行安装所要满足的固件要求:

服务器硬件

BMC 型号

管理

Dell 硬件

第 15 代

iDRAC9

Supermicro 硬件

01.00.25

Supermicro SMC - redfish

HPE 硬件

1.50

iLO6

28.2 网络

下图显示了电信环境的典型网络体系结构作为参考:

ATIP 产品要求 1

网络体系结构基于以下组件:

  • 管理网络:此网络用于管理 ATIP 节点。它用于带外管理。通常,此网络还会连接到独立的管理交换机,但可以通过 VLAN 连接到同一服务交换机以隔离流量。

  • 控制平面网络:此网络用于 ATIP 节点与其上运行的服务之间的通讯。此网络还用于 ATIP 节点与外部服务(例如 DHCPDNS 服务器)之间的通讯。在某些情况下,对于联网环境,交换机/路由器可以通过互联网处理流量。

  • 其他网络:在某些情况下,ATIP 节点可以连接到其他网络以满足特定的客户目的。

注意
注意

要使用定向网络置备工作流程,管理群集必须与下游群集服务器基板管理控制器 (BMC) 建立网络连接,以便可以自动准备和置备主机。

28.3 服务(DHCP、DNS 等)

可能需要一些外部服务(例如 DHCPDNS 等),具体取决于部署环境的类型:

  • 联网环境:在这种情况下,ATIP 节点将连接到互联网(通过路由 L3 协议),外部服务将由客户提供。

  • 离线/隔离环境:在这种情况下,ATIP 节点未建立互联网 IP 连接,因此需要通过其他服务在本地镜像 ATIP 定向网络置备工作流程所需的内容。

  • 文件服务器:文件服务器用于在执行定向网络置备工作流程期间存储 ATIP 节点上置备的 ISO 映像。metal3 Helm chart 可以部署媒体服务器来存储 ISO 映像 — 请查看下面一节(注意),但也可以使用现有的本地 Web 服务器。

28.4 禁用 rebootmgr

rebootmgr 是当系统中存在未完成的更新时用于配置重引导策略的服务。对于电信工作负载,必须禁用或正确配置 rebootmgr 服务,以避免在系统安排了更新时重引导节点,从而避免对节点上运行的服务造成任何影响。

注意
注意

有关 rebootmgr 的详细信息,请参见 rebootmgr GitHub 储存库

运行以下命令来校验使用的策略:

cat /etc/rebootmgr.conf
[rebootmgr]
window-start=03:30
window-duration=1h30m
strategy=best-effort
lock-group=default

可以运行以下命令来禁用 rebootmgr:

sed -i 's/strategy=best-effort/strategy=off/g' /etc/rebootmgr.conf

也可以使用 rebootmgrctl 命令:

rebootmgrctl strategy off
注意
注意

可以使用定向网络置备工作流程来自动执行此项设置 rebootmgr 策略的配置。有关详细信息,请查看 ATIP 自动置备文档(第 31 章 “全自动定向网络置备)。

29 设置管理群集

29.1 简介

管理群集是用于管理运行时堆栈的置备和生命周期的 ATIP 组成部分。从技术角度讲,管理群集包含以下组件:

  • SUSE Linux Enterprise Micro(操作系统)。可以根据用例自定义某些配置,例如网络、存储、用户和内核参数。

  • RKE2(Kubernetes 群集)。可以根据用例将其配置为使用特定的 CNI 插件,例如 MultusCilium 等。

  • Rancher(管理平台),用于管理群集的生命周期。

  • Metal3,该组件用于管理裸机节点的生命周期。

  • CAPI,该组件用于管理 Kubernetes 群集(下游群集)的生命周期。在 ATIP 中,RKE2 CAPI 提供程序也用于管理 RKE2 群集(下游群集)的生命周期。

通过上述所有组件,管理群集可以管理下游群集的生命周期,并使用声明性方法来管理基础架构和应用程序。

注意
注意

有关 SUSE Linux Enterprise Micro 的详细信息,请参见:SLE Micro(第 7 章 “SLE Micro

有关 RKE2 的详细信息,请参见:RKE2(第 14 章 “RKE2

有关 Rancher 的详细信息,请参见:Rancher(第 4 章 “Rancher

有关 Metal3 的详细信息,请参见:Metal3(第 8 章 “Metal3

29.2 设置管理群集的步骤

需要执行以下步骤来设置管理群集(使用单个节点):

ATIP 产品管理群集 1

使用声明性方法设置管理群集需要执行三个主要步骤:

  1. 为联网环境准备映像(第 29.3 节 “为联网环境准备映像”:第一步是准备包含所有必要配置的清单和文件,以便在联网环境中使用。

    • 联网环境的目录结构(第 29.3.1 节 “目录结构”):此步骤创建一个目录结构,供 Edge Image Builder 用来存储配置文件和映像本身。

    • 管理群集定义文件(第 29.3.2 节 “管理群集定义文件”):mgmt-cluster.yaml 文件是管理群集的主定义文件。其中包含有关所要创建的映像的以下信息:

      • 映像信息:与要使用基础映像创建的映像相关的信息。

      • 操作系统:要在映像中使用的操作系统配置。

      • Kubernetes:要在群集中使用的 Helm chart 和储存库、Kubernetes 版本、网络配置以及节点。

    • Custom 文件夹(第 29.3.3 节 “Custom 文件夹”):custom 文件夹包含的配置文件和脚本供 Edge Image Builder 用来部署功能完备的管理群集。

      • Files 文件夹:包含管理群集要使用的配置文件。

      • Scripts 文件夹:包含管理群集要使用的脚本。

    • Kubernetes 文件夹(第 29.3.4 节 “Kubernetes 文件夹”):kubernetes 文件夹包含管理群集要使用的配置文件。

      • Manifests 文件夹:包含管理群集要使用的清单。

      • Helm 文件夹:包含管理群集要使用的 Helm chart。

      • Config 文件夹:包含管理群集要使用的配置文件。

    • Network 文件夹(第 29.3.5 节 “Network 文件夹”):network 文件夹包含管理群集节点要使用的网络配置文件。

  2. 为隔离环境准备映像(第 29.4 节 “为隔离环境准备映像”:此步骤用于显示差异,以准备好要在隔离方案中使用的清单和文件。

    • 隔离环境的目录结构(第 29.4.1 节 “隔离环境的目录结构”):必须修改目录结构,以包含用于在隔离环境中运行管理群集的资源。

    • 定义文件中的修改(第 29.4.2 节 “定义文件中的修改”):必须修改 mgmt-cluster.yaml 文件,以包含 embeddedArtifactRegistry 部分,并将 images 字段设置为要包含在 EIB 输出映像中的所有容器映像。

    • custom 文件夹中的修改(第 29.4.3 节 “custom 文件夹中的修改”):必须修改 custom 文件夹,以包含用于在隔离环境中运行管理群集的资源。

      • 注册脚本:使用隔离环境时,必须去除 custom/scripts/99-register.sh 脚本。

      • 隔离资源:必须在 custom/files 文件夹中包含 custom/files/airgap-resources.tar.gz 文件,该文件包含用于在隔离环境中运行管理群集的所有资源。

      • 脚本:必须修改 custom/scripts/99-mgmt-setup.sh 脚本,以提取 airgap-resources.tar.gz 文件并将其复制到最终位置。必须修改 custom/files/metal3.sh 脚本,以使用 airgap-resources.tar.gz 文件中包含的本地资源,而不是从互联网下载资源。

  3. 创建映像(第 29.5 节 “映像创建”:此步骤使用 Edge Image Builder 工具创建映像(适用于联网方案和隔离方案)。在系统上运行 Edge Image Builder 工具之前请先检查先决条件(第 9 章 “Edge Image Builder)。

  4. 置备管理群集(第 29.6 节 “置备管理群集”:此步骤使用上一步骤中创建的映像来置备管理群集(适用于联网方案和隔离方案)。可以使用便携式计算机、服务器、VM 或任何其他带有 USB 端口的 x86_64 系统来执行此步骤。

注意
注意

有关 Edge Image Builder 的详细信息,请参见 Edge Image Builder(第 9 章 “Edge Image Builder)和 Edge Image Builder 快速入门(第 3 章 “使用 Edge Image Builder 配置独立群集)。

29.3 为联网环境准备映像

使用 Edge Image Builder 为管理群集创建映像时可以自定义许多配置,但本文档只会介绍设置管理群集所需的最低限度配置。Edge Image Builder 通常从容器内部运行,因此,如果您目前无法运行容器,则首先需要安装 PodmanRancher Desktop 之类的容器运行时。本指南假设您已经安装了可用的容器运行时。

此外,作为部署高可用性管理群集的先决条件,您需要在网络中预留三个 IP:- apiVIP(表示 API VIP 地址,用于访问 Kubernetes API 服务器)。- ingressVIP(表示入口 VIP 地址,由 Rancher UI 等组件使用)。- metal3VIP(表示 Metal3 VIP 地址)。

29.3.1 目录结构

运行 EIB 时,将从主机挂载一个目录,因此首先需要创建一个目录结构,供 EIB 用来存储配置文件和映像本身。此目录采用以下结构:

eib
├── mgmt-cluster.yaml
├── network
│ └── mgmt-cluster-node1.yaml
├── kubernetes
│ ├── manifests
│ │ ├── rke2-ingress-config.yaml
│ │ ├── neuvector-namespace.yaml
│ │ ├── ingress-l2-adv.yaml
│ │ └── ingress-ippool.yaml
│ ├── helm
│ │ └── values
│ │     ├── rancher.yaml
│ │     ├── neuvector.yaml
│ │     ├── metal3.yaml
│ │     └── certmanager.yaml
│ └── config
│     └── server.yaml
├── custom
│ ├── scripts
│ │ ├── 99-register.sh
│ │ ├── 99-mgmt-setup.sh
│ │ └── 99-alias.sh
│ └── files
│     ├── rancher.sh
│     ├── mgmt-stack-setup.service
│     ├── metal3.sh
│     └── basic-setup.sh
└── base-images
注意
注意

必须从 SUSE Customer CenterSUSE 下载页面下载 SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso 映像,并且必须将它放在 base-images 文件夹中。

应检查该映像的 SHA256 校验和,确保它未遭篡改。可以在映像所下载到的位置找到校验和。

可以在 SUSE Edge GitHub 储存库中的“telco-examples”文件夹下找到目录结构的示例。

29.3.2 管理群集定义文件

mgmt-cluster.yaml 文件是管理群集的主定义文件。其中包含以下信息:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso
  outputImageName: eib-mgmt-cluster-image.iso
operatingSystem:
  isoConfiguration:
    installDevice: /dev/sda
  users:
  - username: root
    encryptedPassword: ${ROOT_PASSWORD}
  packages:
    packageList:
    - git
    - jq
    sccRegistrationCode: ${SCC_REGISTRATION_CODE}
kubernetes:
  version: ${KUBERNETES_VERSION}
  helm:
    charts:
      - name: cert-manager
        repositoryName: jetstack
        version: 1.14.2
        targetNamespace: cert-manager
        valuesFile: certmanager.yaml
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn-crd
        version: 103.3.0+up1.6.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn
        version: 103.3.0+up1.6.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: metal3-chart
        version: 0.7.1
        repositoryName: suse-edge-charts
        targetNamespace: metal3-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: metal3.yaml
      - name: neuvector-crd
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: neuvector
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: rancher
        version: 2.8.4
        repositoryName: rancher-prime
        targetNamespace: cattle-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: rancher.yaml
    repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      - name: rancher-charts
        url: https://charts.rancher.io/
      - name: suse-edge-charts
        url: oci://registry.suse.com/edge
      - name: rancher-prime
        url: https://charts.rancher.com/server-charts/prime
    network:
      apiHost: ${API_HOST}
      apiVIP: ${API_VIP}
    nodes:
      - hostname: mgmt-cluster-node1
        initializer: true
        type: server
#     - hostname: mgmt-cluster-node2
#       initializer: true
#       type: server
#     - hostname: mgmt-cluster-node3
#       initializer: true
#       type: server

为了解释 mgmt-cluster.yaml 定义文件中的字段和值,我们将此文件划分成了以下几个部分。

  • 映像部分(定义文件):

image:
  imageType: iso
  arch: x86_64
  baseImage: SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso
  outputImageName: eib-mgmt-cluster-image.iso

其中 baseImage 是从 SUSE Customer Center 或 SUSE 下载页面下载的原始映像。outputImageName 是将用于置备管理群集的新映像的名称。

  • 操作系统部分(定义文件):

operatingSystem:
  isoConfiguration:
    installDevice: /dev/sda
  users:
  - username: root
    encryptedPassword: ${ROOT_PASSWORD}
  packages:
    packageList:
    - jq
    sccRegistrationCode: ${SCC_REGISTRATION_CODE}

其中 installDevice 是用于安装操作系统的设备,usernameencryptedPassword 是用于访问系统的身份凭证,packageList 是要安装的软件包列表(在安装过程中,需要在内部使用 jq),sccRegistrationCode 是在构建时用于获取软件包和依赖项的注册码,可从 SUSE Customer Center 获取。可以如下所示使用 openssl 命令生成加密的口令:

openssl passwd -6 MyPassword!123

此命令输出如下所示的内容:

$6$UrXB1sAGs46DOiSq$HSwi9GFJLCorm0J53nF2Sq8YEoyINhHcObHzX2R8h13mswUIsMwzx4eUzn/rRx0QPV4JIb0eWCoNrxGiKH4R31
  • Kubernetes 部分(定义文件):

kubernetes:
  version: ${KUBERNETES_VERSION}
  helm:
    charts:
      - name: cert-manager
        repositoryName: jetstack
        version: 1.14.2
        targetNamespace: cert-manager
        valuesFile: certmanager.yaml
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn-crd
        version: 103.3.0+up1.6.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn
        version: 103.3.0+up1.6.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: metal3-chart
        version: 0.7.1
        repositoryName: suse-edge-charts
        targetNamespace: metal3-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: metal3.yaml
      - name: neuvector-crd
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: neuvector
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: rancher
        version: 2.8.4
        repositoryName: rancher-prime
        targetNamespace: cattle-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: rancher.yaml
    repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      - name: rancher-charts
        url: https://charts.rancher.io/
      - name: suse-edge-charts
        url: oci://registry.suse.com/edge
      - name: rancher-prime
        url: https://charts.rancher.com/server-charts/prime
    network:
      apiHost: ${API_HOST}
      apiVIP: ${API_VIP}
    nodes:
      - hostname: mgmt-cluster1
        initializer: true
        type: server
#      - hostname: mgmt-cluster2
#        type: server
#      - hostname: mgmt-cluster3
#        type: server

其中 version 是要安装的 Kubernetes 版本。在本例中,我们将使用 RKE2 群集,因此版本必须低于 1.29(例如 v1.28.9+rke2r1),以便与 Rancher 兼容。

helm 部分包含要安装的 Helm chart 列表、要使用的储存库,以及所有 chart 和储存库的版本配置。

network 部分包含 RKE2 组件要使用网络配置,例如 apiHostapiVIPapiVIP 应是网络中未使用的 IP 地址,并且不属于 DHCP 池(如果使用 DHCP)。此外,如果我们在多节点群集中使用 apiVIP,apiVIP 将用于访问 Kubernetes API 服务器。apiHostRKE2 组件要使用的 apiVIP 的名称解析。

nodes 部分包含要在群集中使用的节点列表。nodes 部分包含要在群集中使用的节点列表。此示例使用的是单节点群集,但可以通过在列表中添加更多节点(通过取消注释相应的行),将其扩展为多节点群集。

注意
注意

节点的名称在群集中必须唯一,列表中第一个节点的 initializer 字段必须设置为 true。节点的名称必须与 network 部分中定义的主机名相同,并且与 network 部分中的文件名直接匹配。

29.3.3 Custom 文件夹

custom 文件夹包含以下子文件夹:

...
├── custom
│ ├── scripts
│ │ ├── 99-register.sh
│ │ ├── 99-mgmt-setup.sh
│ │ └── 99-alias.sh
│ └── files
│     ├── rancher.sh
│     ├── mgmt-stack-setup.service
│     ├── metal3.sh
│     └── basic-setup.sh
...
  • custom/files 文件夹包含管理群集要使用的配置文件。

  • custom/scripts 文件夹包含管理群集要使用的脚本。

custom/files 文件夹包含以下文件:

  • basic-setup.sh:包含有关要使用的 Metal3 版本的配置参数,以及 RancherMetalLB 基本参数。请仅在您要更改所要使用的组件或名称空间的版本时才修改此文件。

    #!/bin/bash
    # Pre-requisites. Cluster already running
    export KUBECTL="/var/lib/rancher/rke2/bin/kubectl"
    export KUBECONFIG="/etc/rancher/rke2/rke2.yaml"
    
    ##################
    # METAL3 DETAILS #
    ##################
    export METAL3_CHART_TARGETNAMESPACE="metal3-system"
    export METAL3_CLUSTERCTLVERSION="1.6.2"
    export METAL3_CAPICOREVERSION="1.6.2"
    export METAL3_CAPIMETAL3VERSION="1.6.0"
    export METAL3_CAPIRKE2VERSION="0.2.6"
    export METAL3_CAPIPROVIDER="rke2"
    export METAL3_CAPISYSTEMNAMESPACE="capi-system"
    export METAL3_RKE2BOOTSTRAPNAMESPACE="rke2-bootstrap-system"
    export METAL3_CAPM3NAMESPACE="capm3-system"
    export METAL3_RKE2CONTROLPLANENAMESPACE="rke2-control-plane-system"
    export METAL3_CAPI_IMAGES="registry.suse.com/edge"
    # Or registry.opensuse.org/isv/suse/edge/clusterapi/containerfile/suse for the upstream ones
    
    ###########
    # METALLB #
    ###########
    export METALLBNAMESPACE="metallb-system"
    
    ###########
    # RANCHER #
    ###########
    export RANCHER_CHART_TARGETNAMESPACE="cattle-system"
    export RANCHER_FINALPASSWORD="adminadminadmin"
    
    die(){
      echo ${1} 1>&2
      exit ${2}
    }
  • metal3.sh:包含要使用的 Metal3 组件的配置(无需修改)。在将来的版本中将替换此脚本,以改用 Rancher Turtles 来简化配置。

    #!/bin/bash
    set -euo pipefail
    
    BASEDIR="$(dirname "$0")"
    source ${BASEDIR}/basic-setup.sh
    
    METAL3LOCKNAMESPACE="default"
    METAL3LOCKCMNAME="metal3-lock"
    
    trap 'catch $? $LINENO' EXIT
    
    catch() {
      if [ "$1" != "0" ]; then
        echo "Error $1 occurred on $2"
        ${KUBECTL} delete configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE}
      fi
    }
    
    # Get or create the lock to run all those steps just in a single node
    # As the first node is created WAY before the others, this should be enough
    # TODO: Investigate if leases is better
    if [ $(${KUBECTL} get cm -n ${METAL3LOCKNAMESPACE} ${METAL3LOCKCMNAME} -o name | wc -l) -lt 1 ]; then
      ${KUBECTL} create configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE} --from-literal foo=bar
    else
      exit 0
    fi
    
    # Wait for metal3
    while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CHART_TARGETNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CHART_TARGETNAMESPACE} -l app.kubernetes.io/name=metal3-ironic -o name) --timeout=10s; do sleep 2 ; done
    
    # Get the ironic IP
    IRONICIP=$(${KUBECTL} get cm -n ${METAL3_CHART_TARGETNAMESPACE} ironic-bmo -o jsonpath='{.data.IRONIC_IP}')
    
    # If LoadBalancer, use metallb, else it is NodePort
    if [ $(${KUBECTL} get svc -n ${METAL3_CHART_TARGETNAMESPACE} metal3-metal3-ironic -o jsonpath='{.spec.type}') == "LoadBalancer" ]; then
      # Wait for metallb
      while ! ${KUBECTL} wait --for condition=ready -n ${METALLBNAMESPACE} $(${KUBECTL} get pods -n ${METALLBNAMESPACE} -l app.kubernetes.io/component=controller -o name) --timeout=10s; do sleep 2 ; done
    
      # Do not create the ippool if already created
      ${KUBECTL} get ipaddresspool -n ${METALLBNAMESPACE} ironic-ip-pool -o name || cat <<-EOF | ${KUBECTL} apply -f -
      apiVersion: metallb.io/v1beta1
      kind: IPAddressPool
      metadata:
        name: ironic-ip-pool
        namespace: ${METALLBNAMESPACE}
      spec:
        addresses:
        - ${IRONICIP}/32
        serviceAllocation:
          priority: 100
          serviceSelectors:
          - matchExpressions:
            - {key: app.kubernetes.io/name, operator: In, values: [metal3-ironic]}
    	EOF
    
      # Same for L2 Advs
      ${KUBECTL} get L2Advertisement -n ${METALLBNAMESPACE} ironic-ip-pool-l2-adv -o name || cat <<-EOF | ${KUBECTL} apply -f -
      apiVersion: metallb.io/v1beta1
      kind: L2Advertisement
      metadata:
        name: ironic-ip-pool-l2-adv
        namespace: ${METALLBNAMESPACE}
      spec:
        ipAddressPools:
        - ironic-ip-pool
    	EOF
    fi
    
    # If clusterctl is not installed, install it
    if ! command -v clusterctl > /dev/null 2>&1; then
      LINUXARCH=$(uname -m)
      case $(uname -m) in
        "x86_64")
          export GOARCH="amd64" ;;
        "aarch64")
          export GOARCH="arm64" ;;
        "*")
          echo "Arch not found, asumming amd64"
          export GOARCH="amd64" ;;
      esac
    
      # Clusterctl bin
      # Maybe just use the binary from hauler if available
      curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v${METAL3_CLUSTERCTLVERSION}/clusterctl-linux-${GOARCH} -o /usr/local/bin/clusterctl
      chmod +x /usr/local/bin/clusterctl
    fi
    
    # If rancher is deployed
    if [ $(${KUBECTL} get pods -n ${RANCHER_CHART_TARGETNAMESPACE} -l app=rancher -o name | wc -l) -ge 1 ]; then
      cat <<-EOF | ${KUBECTL} apply -f -
    	apiVersion: management.cattle.io/v3
    	kind: Feature
    	metadata:
    	  name: embedded-cluster-api
    	spec:
    	  value: false
    	EOF
    
      # Disable Rancher webhooks for CAPI
      ${KUBECTL} delete mutatingwebhookconfiguration.admissionregistration.k8s.io mutating-webhook-configuration
      ${KUBECTL} delete validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration
      ${KUBECTL} wait --for=delete namespace/cattle-provisioning-capi-system --timeout=300s
    fi
    
    # Deploy CAPI
    if [ $(${KUBECTL} get pods -n ${METAL3_CAPISYSTEMNAMESPACE} -o name | wc -l) -lt 1 ]; then
    
      # https://github.com/rancher-sandbox/cluster-api-provider-rke2#setting-up-clusterctl
      mkdir -p ~/.cluster-api
      cat <<-EOF > ~/.cluster-api/clusterctl.yaml
    	images:
    	  all:
    	    repository: ${METAL3_CAPI_IMAGES}
    	EOF
    
      # Try this command 3 times just in case, stolen from https://stackoverflow.com/a/33354419
      if ! (r=3; while ! clusterctl init \
        --core "cluster-api:v${METAL3_CAPICOREVERSION}"\
        --infrastructure "metal3:v${METAL3_CAPIMETAL3VERSION}"\
        --bootstrap "${METAL3_CAPIPROVIDER}:v${METAL3_CAPIRKE2VERSION}"\
        --control-plane "${METAL3_CAPIPROVIDER}:v${METAL3_CAPIRKE2VERSION}" ; do
                ((--r))||exit
                echo "Something went wrong, let's wait 10 seconds and retry"
                sleep 10;done) ; then
          echo "clusterctl failed"
          exit 1
      fi
    
      # Wait for capi-controller-manager
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CAPISYSTEMNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CAPISYSTEMNAMESPACE} -l cluster.x-k8s.io/provider=cluster-api -o name) --timeout=10s; do sleep 2 ; done
    
      # Wait for capm3-controller-manager, there are two pods, the ipam and the capm3 one, just wait for the first one
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CAPM3NAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CAPM3NAMESPACE} -l cluster.x-k8s.io/provider=infrastructure-metal3 -o name | head -n1 ) --timeout=10s; do sleep 2 ; done
    
      # Wait for rke2-bootstrap-controller-manager
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_RKE2BOOTSTRAPNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_RKE2BOOTSTRAPNAMESPACE} -l cluster.x-k8s.io/provider=bootstrap-rke2 -o name) --timeout=10s; do sleep 2 ; done
    
      # Wait for rke2-control-plane-controller-manager
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_RKE2CONTROLPLANENAMESPACE} $(${KUBECTL} get pods -n ${METAL3_RKE2CONTROLPLANENAMESPACE} -l cluster.x-k8s.io/provider=control-plane-rke2 -o name) --timeout=10s; do sleep 2 ; done
    
    fi
    
    # Clean up the lock cm
    
    ${KUBECTL} delete configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE}
    • rancher.sh:包含要使用的 Rancher 组件的配置(无需修改)。

      #!/bin/bash
      set -euo pipefail
      
      BASEDIR="$(dirname "$0")"
      source ${BASEDIR}/basic-setup.sh
      
      RANCHERLOCKNAMESPACE="default"
      RANCHERLOCKCMNAME="rancher-lock"
      
      if [ -z "${RANCHER_FINALPASSWORD}" ]; then
        # If there is no final password, then finish the setup right away
        exit 0
      fi
      
      trap 'catch $? $LINENO' EXIT
      
      catch() {
        if [ "$1" != "0" ]; then
          echo "Error $1 occurred on $2"
          ${KUBECTL} delete configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE}
        fi
      }
      
      # Get or create the lock to run all those steps just in a single node
      # As the first node is created WAY before the others, this should be enough
      # TODO: Investigate if leases is better
      if [ $(${KUBECTL} get cm -n ${RANCHERLOCKNAMESPACE} ${RANCHERLOCKCMNAME} -o name | wc -l) -lt 1 ]; then
        ${KUBECTL} create configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE} --from-literal foo=bar
      else
        exit 0
      fi
      
      # Wait for rancher to be deployed
      while ! ${KUBECTL} wait --for condition=ready -n ${RANCHER_CHART_TARGETNAMESPACE} $(${KUBECTL} get pods -n ${RANCHER_CHART_TARGETNAMESPACE} -l app=rancher -o name) --timeout=10s; do sleep 2 ; done
      until ${KUBECTL} get ingress -n ${RANCHER_CHART_TARGETNAMESPACE} rancher > /dev/null 2>&1; do sleep 10; done
      
      RANCHERBOOTSTRAPPASSWORD=$(${KUBECTL} get secret -n ${RANCHER_CHART_TARGETNAMESPACE} bootstrap-secret -o jsonpath='{.data.bootstrapPassword}' | base64 -d)
      RANCHERHOSTNAME=$(${KUBECTL} get ingress -n ${RANCHER_CHART_TARGETNAMESPACE} rancher -o jsonpath='{.spec.rules[0].host}')
      
      # Skip the whole process if things have been set already
      if [ -z $(${KUBECTL} get settings.management.cattle.io first-login -ojsonpath='{.value}') ]; then
        # Add the protocol
        RANCHERHOSTNAME="https://${RANCHERHOSTNAME}"
        TOKEN=""
        while [ -z "${TOKEN}" ]; do
          # Get token
          sleep 2
          TOKEN=$(curl -sk -X POST ${RANCHERHOSTNAME}/v3-public/localProviders/local?action=login -H 'content-type: application/json' -d "{\"username\":\"admin\",\"password\":\"${RANCHERBOOTSTRAPPASSWORD}\"}" | jq -r .token)
        done
      
        # Set password
        curl -sk ${RANCHERHOSTNAME}/v3/users?action=changepassword -H 'content-type: application/json' -H "Authorization: Bearer $TOKEN" -d "{\"currentPassword\":\"${RANCHERBOOTSTRAPPASSWORD}\",\"newPassword\":\"${RANCHER_FINALPASSWORD}\"}"
      
        # Create a temporary API token (ttl=60 minutes)
        APITOKEN=$(curl -sk ${RANCHERHOSTNAME}/v3/token -H 'content-type: application/json' -H "Authorization: Bearer ${TOKEN}" -d '{"type":"token","description":"automation","ttl":3600000}' | jq -r .token)
      
        curl -sk ${RANCHERHOSTNAME}/v3/settings/server-url -H 'content-type: application/json' -H "Authorization: Bearer ${APITOKEN}" -X PUT -d "{\"name\":\"server-url\",\"value\":\"${RANCHERHOSTNAME}\"}"
        curl -sk ${RANCHERHOSTNAME}/v3/settings/telemetry-opt -X PUT -H 'content-type: application/json' -H 'accept: application/json' -H "Authorization: Bearer ${APITOKEN}" -d '{"value":"out"}'
      fi
      
      # Clean up the lock cm
      ${KUBECTL} delete configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE}
    • mgmt-stack-setup.service:包含用于创建 systemd 服务,以便在首次引导期间运行脚本的配置(无需修改)。

      [Unit]
      Description=Setup Management stack components
      Wants=network-online.target
      # It requires rke2 or k3s running, but it will not fail if those services are not present
      After=network.target network-online.target rke2-server.service k3s.service
      # At least, the basic-setup.sh one needs to be present
      ConditionPathExists=/opt/mgmt/bin/basic-setup.sh
      
      [Service]
      User=root
      Type=forking
      # Metal3 can take A LOT to download the IPA image
      TimeoutStartSec=1800
      
      ExecStartPre=/bin/sh -c "echo 'Setting up Management components...'"
      # Scripts are executed in StartPre because Start can only run a single on
      ExecStartPre=/opt/mgmt/bin/rancher.sh
      ExecStartPre=/opt/mgmt/bin/metal3.sh
      ExecStart=/bin/sh -c "echo 'Finished setting up Management components'"
      RemainAfterExit=yes
      KillMode=process
      # Disable & delete everything
      ExecStartPost=rm -f /opt/mgmt/bin/rancher.sh
      ExecStartPost=rm -f /opt/mgmt/bin/metal3.sh
      ExecStartPost=rm -f /opt/mgmt/bin/basic-setup.sh
      ExecStartPost=/bin/sh -c "systemctl disable mgmt-stack-setup.service"
      ExecStartPost=rm -f /etc/systemd/system/mgmt-stack-setup.service
      
      [Install]
      WantedBy=multi-user.target

custom/scripts 文件夹包含以下文件:

  • 99-alias.sh 脚本:包含管理群集在首次引导时用来加载 kubeconfig 文件的别名(无需修改)。

    #!/bin/bash
    echo "alias k=kubectl" >> /etc/profile.local
    echo "alias kubectl=/var/lib/rancher/rke2/bin/kubectl" >> /etc/profile.local
    echo "export KUBECONFIG=/etc/rancher/rke2/rke2.yaml" >> /etc/profile.local
  • 99-mgmt-setup.sh 脚本:包含首次引导期间用于复制脚本的配置(无需修改)。

    #!/bin/bash
    
    # Copy the scripts from combustion to the final location
    mkdir -p /opt/mgmt/bin/
    for script in basic-setup.sh rancher.sh metal3.sh; do
    	cp ${script} /opt/mgmt/bin/
    done
    
    # Copy the systemd unit file and enable it at boot
    cp mgmt-stack-setup.service /etc/systemd/system/mgmt-stack-setup.service
    systemctl enable mgmt-stack-setup.service
  • 99-register.sh 脚本:包含用于通过 SCC 注册码注册系统的配置。必须正确设置 ${SCC_ACCOUNT_EMAIL}${SCC_REGISTRATION_CODE} 才能使用您的帐户注册系统。

    #!/bin/bash
    set -euo pipefail
    
    # Registration https://www.suse.com/support/kb/doc/?id=000018564
    if ! which SUSEConnect > /dev/null 2>&1; then
    	zypper --non-interactive install suseconnect-ng
    fi
    SUSEConnect --email "${SCC_ACCOUNT_EMAIL}" --url "https://scc.suse.com" --regcode "${SCC_REGISTRATION_CODE}"

29.3.4 Kubernetes 文件夹

kubernetes 文件夹包含以下子文件夹:

...
├── kubernetes
│ ├── manifests
│ │ ├── rke2-ingress-config.yaml
│ │ ├── neuvector-namespace.yaml
│ │ ├── ingress-l2-adv.yaml
│ │ └── ingress-ippool.yaml
│ ├── helm
│ │ └── values
│ │     ├── rancher.yaml
│ │     ├── neuvector.yaml
│ │     ├── metal3.yaml
│ │     └── certmanager.yaml
│ └── config
│     └── server.yaml
...

kubernetes/config 文件夹包含以下文件:

  • server.yaml:默认安装的 CNI 插件是 Cilium,因此不需要创建此文件夹和文件。如果您需要自定义 CNI 插件,可以使用 kubernetes/config 文件夹中的 server.yaml 文件。该文件包含以下信息:

    cni:
    - multus
    - cilium
注意
注意

这是一个可选文件,用于定义某些 Kubernetes 自定义设置,例如要使用的 CNI 插件,或官方文档中所述的许多选项。

kubernetes/manifests 文件夹包含以下文件:

  • rke2-ingress-config.yaml:包含用于为管理群集创建入口服务的配置(无需修改)。

    apiVersion: helm.cattle.io/v1
    kind: HelmChartConfig
    metadata:
      name: rke2-ingress-nginx
      namespace: kube-system
    spec:
      valuesContent: |-
        controller:
          config:
            use-forwarded-headers: "true"
            enable-real-ip: "true"
          publishService:
            enabled: true
          service:
            enabled: true
            type: LoadBalancer
            externalTrafficPolicy: Local
  • neuvector-namespace.yaml:包含用于创建 NeuVector 名称空间的配置(无需修改)。

    apiVersion: v1
    kind: Namespace
    metadata:
      labels:
        pod-security.kubernetes.io/enforce: privileged
      name: neuvector
  • ingress-l2-adv.yaml:包含用于为 MetalLB 组件创建 L2Advertisement 的配置(无需修改)。

    apiVersion: metallb.io/v1beta1
    kind: L2Advertisement
    metadata:
      name: ingress-l2-adv
      namespace: metallb-system
    spec:
      ipAddressPools:
        - ingress-ippool
  • ingress-ippool.yaml:包含用于为 rke2-ingress-nginx 组件创建 IPAddressPool 的配置。必须正确设置 ${INGRESS_VIP},以定义预留给 rke2-ingress-nginx 组件使用的 IP 地址。

    apiVersion: metallb.io/v1beta1
    kind: IPAddressPool
    metadata:
      name: ingress-ippool
      namespace: metallb-system
    spec:
      addresses:
        - ${INGRESS_VIP}/32
      serviceAllocation:
        priority: 100
        serviceSelectors:
          - matchExpressions:
              - {key: app.kubernetes.io/name, operator: In, values: [rke2-ingress-nginx]}

kubernetes/helm/values 文件夹包含以下文件:

  • rancher.yaml:包含用于创建 Rancher 组件的配置。必须正确设置 ${INGRESS_VIP},以定义 Rancher 组件要使用的 IP 地址。用于访问 Rancher 组件的 URL 为 https://rancher-${INGRESS_VIP}.sslip.io

    hostname: rancher-${INGRESS_VIP}.sslip.io
    bootstrapPassword: "foobar"
    replicas: 1
    global.cattle.psp.enabled: "false"
  • neuvector.yaml:包含用于创建 NeuVector 组件的配置(无需修改)。

    controller:
      replicas: 1
      ranchersso:
        enabled: true
    manager:
      enabled: false
    cve:
      scanner:
        enabled: false
        replicas: 1
    k3s:
      enabled: true
    crdwebhook:
      enabled: false
  • metal3.yaml:包含用于创建 Metal3 组件的配置。必须正确设置 ${METAL3_VIP},以定义 Metal3 组件要使用的 IP 地址。

    global:
      ironicIP: ${METAL3_VIP}
      enable_vmedia_tls: false
      additionalTrustedCAs: false
    metal3-ironic:
      global:
        predictableNicNames: "true"
      persistence:
        ironic:
          size: "5Gi"
注意
注意

媒体服务器是 Metal3 中包含的可选功能(默认处于禁用状态)。要使用该 Metal3 功能,需要在前面所述的清单中配置该功能。要使用 Metal3 媒体服务器,请指定以下变量:

  • 在 global 部分,将 enable_metal3_media_server 设置为 true 以启用媒体服务器功能。

  • 包含有关媒体服务器的以下配置,其中 ${MEDIA_VOLUME_PATH} 是媒体卷在媒体中的路径(例如 /home/metal3/bmh-image-cache

    metal3-media:
      mediaVolume:
        hostPath: ${MEDIA_VOLUME_PATH}

可以使用外部媒体服务器来存储映像,如果您要将该服务器与 TLS 配合使用,则需要修改以下配置:

  • 将前面所述 metal3.yaml 文件中的 additionalTrustedCAs 设置为 true,以启用来自外部媒体服务器的附加可信 CA。

  • kubernetes/manifests/metal3-cacert-secret.yaml 文件夹中包含以下密钥配置,以存储外部媒体服务器的 CA 证书。

    apiVersion: v1
    kind: Namespace
    metadata:
      name: metal3-system
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: tls-ca-additional
      namespace: metal3-system
    type: Opaque
    data:
      ca-additional.crt: {{ additional_ca_cert | b64encode }}

additional_ca_cert 是外部媒体服务器的 base64 编码 CA 证书。可使用以下命令对证书进行编码并手动生成密钥:

kubectl -n meta3-system create secret generic tls-ca-additional --from-file=ca-additional.crt=./ca-additional.crt
  • certmanager.yaml:包含用于创建 Cert-Manager 组件的配置(无需修改)。

    installCRDs: "true"

29.3.5 Network 文件夹

network 文件夹中的文件数与管理群集中的节点数一样多。在本例中,我们只有一个节点,因此只有一个文件,其名为 mgmt-cluster-node1.yaml。该文件的名称必须与 mgmt-cluster.yaml 定义文件的上述 network/node 部分中定义的主机名相匹配。

如果您需要自定义网络配置,例如要使用特定的静态 IP 地址(无 DHCP 的方案),可以使用 network 文件夹中的 mgmt-cluster-node1.yaml 文件。该文件包含以下信息:

  • ${MGMT_GATEWAY}:网关 IP 地址。

  • ${MGMT_DNS}:DNS 服务器 IP 地址。

  • ${MGMT_MAC}:网络接口的 MAC 地址。

  • ${MGMT_NODE_IP}:管理群集的 IP 地址。

routes:
  config:
  - destination: 0.0.0.0/0
    metric: 100
    next-hop-address: ${MGMT_GATEWAY}
    next-hop-interface: eth0
    table-id: 254
dns-resolver:
  config:
    server:
    - ${MGMT_DNS}
    - 8.8.8.8
interfaces:
- name: eth0
  type: ethernet
  state: up
  mac-address: ${MGMT_MAC}
  ipv4:
    address:
    - ip: ${MGMT_NODE_IP}
      prefix-length: 24
    dhcp: false
    enabled: true
  ipv6:
    enabled: false

如果您要使用 DHCP 获取 IP 地址,可使用以下配置(必须使用 ${MGMT_MAC} 变量正确设置 MAC 地址):

## This is an example of a dhcp network configuration for a management cluster
## interfaces:
- name: eth0
  type: ethernet
  state: up
  mac-address: ${MGMT_MAC}
  ipv4:
    dhcp: true
    enabled: true
  ipv6:
    enabled: false
注意
注意
  • 根据管理群集中的节点数,您可以创建更多文件(例如 mgmt-cluster-node2.yamlmgmt-cluster-node3.yaml 等)来配置其余节点。

  • routes 部分用于定义管理群集的路由表。

29.4 为隔离环境准备映像

本节介绍如何为隔离环境准备映像,其中只说明了与前面几节内容存在的差别。为隔离环境准备映像需要对上一节(为联网环境准备映像(第 29.3 节 “为联网环境准备映像”))的内容进行以下更改:

  • 必须修改 mgmt-cluster.yaml 文件,以包含 embeddedArtifactRegistry 部分,并将 images 字段设置为要包含在 EIB 输出映像中的所有容器映像。

  • 使用隔离环境时,必须去除 custom/scripts/99-register.sh 脚本。

  • 必须在 custom/files 文件夹中包含 custom/files/airgap-resources.tar.gz 文件,该文件包含用于在隔离环境中运行管理群集的所有资源。

  • 必须修改 custom/scripts/99-mgmt-setup.sh 脚本,以提取 airgap-resources.tar.gz 文件并将其复制到最终位置。

  • 必须修改 custom/files/metal3.sh 脚本,以使用 airgap-resources.tar.gz 文件中包含的本地资源,而不是从互联网下载资源。

29.4.1 隔离环境的目录结构

除了下面所述的差别之外,隔离环境与联网环境的目录结构在其他方面相同:

eib
|-- base-images
|   |-- SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso
|-- custom
|   |-- files
|   |   |-- airgap-resources.tar.gz
|   |   |-- basic-setup.sh
|   |   |-- metal3.sh
|   |   |-- mgmt-stack-setup.service
|   |   |-- rancher.sh
|   |-- scripts
|       |-- 99-alias.sh
|       |-- 99-mgmt-setup.sh
|-- kubernetes
|   |-- config
|   |   |-- server.yaml
|   |-- helm
|   |   |-- values
|   |       |-- certmanager.yaml
|   |       |-- metal3.yaml
|   |       |-- neuvector.yaml
|   |       |-- rancher.yaml
|   |-- manifests
|       |-- neuvector-namespace.yaml
|-- mgmt-cluster.yaml
|-- network
    |-- mgmt-cluster-network.yaml
注意
注意

在启动设置过程之前,必须从 SUSE Customer CenterSUSE 下载页面下载 SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso 映像,并且必须将它放在 base-images 文件夹中。

应检查该映像的 SHA256 校验和,确保它未遭篡改。可以在映像所下载到的位置找到校验和。

可以在 SUSE Edge GitHub 储存库中的“telco-examples”文件夹下找到目录结构的示例。

29.4.2 定义文件中的修改

必须修改 mgmt-cluster.yaml 文件,以包含 embeddedArtifactRegistry 部分,并将 images 字段设置为要包含在 EIB 输出映像中的所有容器映像。images 字段必须包含要放入输出映像中的所有容器映像的列表。下面是包含 embeddedArtifactRegistry 部分的 mgmt-cluster.yaml 文件示例:

apiVersion: 1.0
image:
  imageType: iso
  arch: x86_64
  baseImage: SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso
  outputImageName: eib-mgmt-cluster-image.iso
operatingSystem:
  isoConfiguration:
    installDevice: /dev/sda
  users:
  - username: root
    encryptedPassword: ${ROOT_PASSWORD}
  packages:
    packageList:
    - jq
    sccRegistrationCode: ${SCC_REGISTRATION_CODE}
kubernetes:
  version: ${KUBERNETES_VERSION}
  helm:
    charts:
      - name: cert-manager
        repositoryName: jetstack
        version: 1.14.2
        targetNamespace: cert-manager
        valuesFile: certmanager.yaml
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn-crd
        version: 103.3.0+up1.6.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn
        version: 103.3.0+up1.6.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: metal3-chart
        version: 0.7.1
        repositoryName: suse-edge-charts
        targetNamespace: metal3-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: metal3.yaml
      - name: neuvector-crd
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: neuvector
        version: 103.0.3+up2.7.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: rancher
        version: 2.8.4
        repositoryName: rancher-prime
        targetNamespace: cattle-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: rancher.yaml
    repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      - name: rancher-charts
        url: https://charts.rancher.io/
      - name: suse-edge-charts
        url: oci://registry.suse.com/edge
      - name: rancher-prime
        url: https://charts.rancher.com/server-charts/prime
    network:
      apiHost: ${API_HOST}
      apiVIP: ${API_VIP}
    nodes:
      - hostname: mgmt-cluster-node1
        initializer: true
        type: server
#     - hostname: mgmt-cluster-node2
#       initializer: true
#       type: server
#     - hostname: mgmt-cluster-node3
#       initializer: true
#       type: server
embeddedArtifactRegistry:
  images:
    - name: registry.rancher.com/rancher/backup-restore-operator:v4.0.2
    - name: registry.rancher.com/rancher/calico-cni:v3.27.0-rancher1
    - name: registry.rancher.com/rancher/cis-operator:v1.0.13
    - name: registry.rancher.com/rancher/coreos-kube-state-metrics:v1.9.7
    - name: registry.rancher.com/rancher/coreos-prometheus-config-reloader:v0.38.1
    - name: registry.rancher.com/rancher/coreos-prometheus-operator:v0.38.1
    - name: registry.rancher.com/rancher/flannel-cni:v0.3.0-rancher9
    - name: registry.rancher.com/rancher/fleet-agent:v0.9.4
    - name: registry.rancher.com/rancher/fleet:v0.9.4
    - name: registry.rancher.com/rancher/gitjob:v0.9.7
    - name: registry.rancher.com/rancher/grafana-grafana:7.1.5
    - name: registry.rancher.com/rancher/hardened-addon-resizer:1.8.20-build20240410
    - name: registry.rancher.com/rancher/hardened-calico:v3.27.3-build20240423
    - name: registry.rancher.com/rancher/hardened-cluster-autoscaler:v1.8.10-build20240124
    - name: registry.rancher.com/rancher/hardened-cni-plugins:v1.4.1-build20240325
    - name: registry.rancher.com/rancher/hardened-coredns:v1.11.1-build20240305
    - name: registry.rancher.com/rancher/hardened-dns-node-cache:1.22.28-build20240125
    - name: registry.rancher.com/rancher/hardened-etcd:v3.5.9-k3s1-build20240418
    - name: registry.rancher.com/rancher/hardened-flannel:v0.25.1-build20240423
    - name: registry.rancher.com/rancher/hardened-k8s-metrics-server:v0.7.1-build20240401
    - name: registry.rancher.com/rancher/hardened-kubernetes:v1.28.9-rke2r1-build20240416
    - name: registry.rancher.com/rancher/hardened-multus-cni:v4.0.2-build20240208
    - name: registry.rancher.com/rancher/hardened-node-feature-discovery:v0.14.1-build20230926
    - name: registry.rancher.com/rancher/hardened-whereabouts:v0.6.3-build20240208
    - name: registry.rancher.com/rancher/helm-project-operator:v0.2.1
    - name: registry.rancher.com/rancher/istio-kubectl:1.5.10
    - name: registry.rancher.com/rancher/jimmidyson-configmap-reload:v0.3.0
    - name: registry.rancher.com/rancher/k3s-upgrade:v1.28.9-k3s1
    - name: registry.rancher.com/rancher/klipper-helm:v0.8.3-build20240228
    - name: registry.rancher.com/rancher/klipper-lb:v0.4.7
    - name: registry.rancher.com/rancher/kube-api-auth:v0.2.1
    - name: registry.rancher.com/rancher/kubectl:v1.28.7
    - name: registry.rancher.com/rancher/library-nginx:1.19.2-alpine
    - name: registry.rancher.com/rancher/local-path-provisioner:v0.0.26
    - name: registry.rancher.com/rancher/machine:v0.15.0-rancher112
    - name: registry.rancher.com/rancher/mirrored-cluster-api-controller:v1.4.4
    - name: registry.rancher.com/rancher/nginx-ingress-controller:nginx-1.9.6-rancher1
    - name: registry.rancher.com/rancher/pause:3.6
    - name: registry.rancher.com/rancher/prom-alertmanager:v0.21.0
    - name: registry.rancher.com/rancher/prom-node-exporter:v1.0.1
    - name: registry.rancher.com/rancher/prom-prometheus:v2.18.2
    - name: registry.rancher.com/rancher/prometheus-auth:v0.2.2
    - name: registry.rancher.com/rancher/prometheus-federator:v0.3.4
    - name: registry.rancher.com/rancher/pushprox-client:v0.1.0-rancher2-client
    - name: registry.rancher.com/rancher/pushprox-proxy:v0.1.0-rancher2-proxy
    - name: registry.rancher.com/rancher/rancher-agent:v2.8.4
    - name: registry.rancher.com/rancher/rancher-csp-adapter:v3.0.1
    - name: registry.rancher.com/rancher/rancher-webhook:v0.4.5
    - name: registry.rancher.com/rancher/rancher:v2.8.4
    - name: registry.rancher.com/rancher/rke-tools:v0.1.96
    - name: registry.rancher.com/rancher/rke2-cloud-provider:v1.29.3-build20240412
    - name: registry.rancher.com/rancher/rke2-runtime:v1.28.9-rke2r1
    - name: registry.rancher.com/rancher/rke2-upgrade:v1.28.9-rke2r1
    - name: registry.rancher.com/rancher/security-scan:v0.2.15
    - name: registry.rancher.com/rancher/shell:v0.1.24
    - name: registry.rancher.com/rancher/system-agent-installer-k3s:v1.28.9-k3s1
    - name: registry.rancher.com/rancher/system-agent-installer-rke2:v1.28.9-rke2r1
    - name: registry.rancher.com/rancher/system-agent:v0.3.6-suc
    - name: registry.rancher.com/rancher/system-upgrade-controller:v0.13.1
    - name: registry.rancher.com/rancher/ui-plugin-catalog:1.3.0
    - name: registry.rancher.com/rancher/ui-plugin-operator:v0.1.1
    - name: registry.rancher.com/rancher/webhook-receiver:v0.2.5
    - name: registry.rancher.com/rancher/kubectl:v1.20.2
    - name: registry.rancher.com/rancher/mirrored-longhornio-csi-attacher:v4.4.2
    - name: registry.rancher.com/rancher/mirrored-longhornio-csi-provisioner:v3.6.2
    - name: registry.rancher.com/rancher/mirrored-longhornio-csi-resizer:v1.9.2
    - name: registry.rancher.com/rancher/mirrored-longhornio-csi-snapshotter:v6.3.2
    - name: registry.rancher.com/rancher/mirrored-longhornio-csi-node-driver-registrar:v2.9.2
    - name: registry.rancher.com/rancher/mirrored-longhornio-livenessprobe:v2.12.0
    - name: registry.rancher.com/rancher/mirrored-longhornio-backing-image-manager:v1.6.1
    - name: registry.rancher.com/rancher/mirrored-longhornio-longhorn-engine:v1.6.1
    - name: registry.rancher.com/rancher/mirrored-longhornio-longhorn-instance-manager:v1.6.1
    - name: registry.rancher.com/rancher/mirrored-longhornio-longhorn-manager:v1.6.1
    - name: registry.rancher.com/rancher/mirrored-longhornio-longhorn-share-manager:v1.6.1
    - name: registry.rancher.com/rancher/mirrored-longhornio-longhorn-ui:v1.6.1
    - name: registry.rancher.com/rancher/mirrored-longhornio-support-bundle-kit:v0.0.36
    - name: registry.suse.com/edge/cluster-api-provider-rke2-bootstrap:v0.2.6
    - name: registry.suse.com/edge/cluster-api-provider-rke2-controlplane:v0.2.6
    - name: registry.suse.com/edge/cluster-api-controller:v1.6.2
    - name: registry.suse.com/edge/cluster-api-provider-metal3:v1.6.0
    - name: registry.suse.com/edge/ip-address-manager:v1.6.0

29.4.3 custom 文件夹中的修改

  • 使用隔离环境时,必须去除 custom/scripts/99-register.sh 脚本。如目录结构中所示,99-register.sh 脚本并未包含在 custom/scripts 文件夹中。

  • 必须修改 custom/scripts/99-mgmt-setup.sh 脚本,以提取 airgap-resources.tar.gz 文件并将其复制到最终位置。下面是经过修改的、用于提取和复制 airgap-resources.tar.gz 文件的 99-mgmt-setup.sh 脚本示例:

    #!/bin/bash
    
    # Copy the scripts from combustion to the final location
    mkdir -p /opt/mgmt/bin/
    for script in basic-setup.sh rancher.sh metal3.sh; do
    	cp ${script} /opt/mgmt/bin/
    done
    
    # Copy the systemd unit file and enable it at boot
    cp mgmt-stack-setup.service /etc/systemd/system/mgmt-stack-setup.service
    systemctl enable mgmt-stack-setup.service
    
    # Extract the airgap resources
    tar zxf airgap-resources.tar.gz
    
    # Copy the clusterctl binary to the final location
    cp airgap-resources/clusterctl /opt/mgmt/bin/ && chmod +x /opt/mgmt/bin/clusterctl
    
    # Copy the clusterctl.yaml and override
    mkdir -p /root/cluster-api
    cp -r airgap-resources/clusterctl.yaml airgap-resources/overrides /root/cluster-api/
  • 必须修改 custom/files/metal3.sh 脚本,以使用 airgap-resources.tar.gz 文件中包含的本地资源,而不是从互联网下载资源。下面是经过修改的、使用本地资源的 metal3.sh 脚本示例:

    #!/bin/bash
    set -euo pipefail
    
    BASEDIR="$(dirname "$0")"
    source ${BASEDIR}/basic-setup.sh
    
    METAL3LOCKNAMESPACE="default"
    METAL3LOCKCMNAME="metal3-lock"
    
    trap 'catch $? $LINENO' EXIT
    
    catch() {
      if [ "$1" != "0" ]; then
        echo "Error $1 occurred on $2"
        ${KUBECTL} delete configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE}
      fi
    }
    
    # Get or create the lock to run all those steps just in a single node
    # As the first node is created WAY before the others, this should be enough
    # TODO: Investigate if leases is better
    if [ $(${KUBECTL} get cm -n ${METAL3LOCKNAMESPACE} ${METAL3LOCKCMNAME} -o name | wc -l) -lt 1 ]; then
      ${KUBECTL} create configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE} --from-literal foo=bar
    else
      exit 0
    fi
    
    # Wait for metal3
    while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CHART_TARGETNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CHART_TARGETNAMESPACE} -l app.kubernetes.io/name=metal3-ironic -o name) --timeout=10s; do sleep 2 ; done
    
    # If rancher is deployed
    if [ $(${KUBECTL} get pods -n ${RANCHER_CHART_TARGETNAMESPACE} -l app=rancher -o name | wc -l) -ge 1 ]; then
      cat <<-EOF | ${KUBECTL} apply -f -
    	apiVersion: management.cattle.io/v3
    	kind: Feature
    	metadata:
    	  name: embedded-cluster-api
    	spec:
    	  value: false
    	EOF
    
      # Disable Rancher webhooks for CAPI
      ${KUBECTL} delete mutatingwebhookconfiguration.admissionregistration.k8s.io mutating-webhook-configuration
      ${KUBECTL} delete validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration
      ${KUBECTL} wait --for=delete namespace/cattle-provisioning-capi-system --timeout=300s
    fi
    
    # Deploy CAPI
    if [ $(${KUBECTL} get pods -n ${METAL3_CAPISYSTEMNAMESPACE} -o name | wc -l) -lt 1 ]; then
    
      # Try this command 3 times just in case, stolen from https://stackoverflow.com/a/33354419
      if ! (r=3; while ! /opt/mgmt/bin/clusterctl init \
        --core "cluster-api:v${METAL3_CAPICOREVERSION}"\
        --infrastructure "metal3:v${METAL3_CAPIMETAL3VERSION}"\
        --bootstrap "${METAL3_CAPIPROVIDER}:v${METAL3_CAPIRKE2VERSION}"\
        --control-plane "${METAL3_CAPIPROVIDER}:v${METAL3_CAPIRKE2VERSION}"\
        --config /root/cluster-api/clusterctl.yaml ; do
                ((--r))||exit
                echo "Something went wrong, let's wait 10 seconds and retry"
                sleep 10;done) ; then
          echo "clusterctl failed"
          exit 1
      fi
    
      # Wait for capi-controller-manager
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CAPISYSTEMNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CAPISYSTEMNAMESPACE} -l cluster.x-k8s.io/provider=cluster-api -o name) --timeout=10s; do sleep 2 ; done
    
      # Wait for capm3-controller-manager, there are two pods, the ipam and the capm3 one, just wait for the first one
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CAPM3NAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CAPM3NAMESPACE} -l cluster.x-k8s.io/provider=infrastructure-metal3 -o name | head -n1 ) --timeout=10s; do sleep 2 ; done
    
      # Wait for rke2-bootstrap-controller-manager
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_RKE2BOOTSTRAPNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_RKE2BOOTSTRAPNAMESPACE} -l cluster.x-k8s.io/provider=bootstrap-rke2 -o name) --timeout=10s; do sleep 2 ; done
    
      # Wait for rke2-control-plane-controller-manager
      while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_RKE2CONTROLPLANENAMESPACE} $(${KUBECTL} get pods -n ${METAL3_RKE2CONTROLPLANENAMESPACE} -l cluster.x-k8s.io/provider=control-plane-rke2 -o name) --timeout=10s; do sleep 2 ; done
    
    fi
    
    # Clean up the lock cm
    
    ${KUBECTL} delete configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE}
  • 必须在 custom/files 文件夹中包含 custom/files/airgap-resources.tar.gz 文件,该文件包含用于在隔离环境中运行管理群集的所有资源。必须手动准备此文件,以下载所有资源并将其压缩成此单一文件。airgap-resources.tar.gz 文件包含以下资源:

    |-- clusterctl
    |-- clusterctl.yaml
    |-- overrides
        |-- bootstrap-rke2
        |   |-- v0.2.6
        |       |-- bootstrap-components.yaml
        |       |-- metadata.yaml
        |-- cluster-api
        |   |-- v1.6.2
        |       |-- core-components.yaml
        |       |-- metadata.yaml
        |-- control-plane-rke2
        |   |-- v0.2.6
        |       |-- control-plane-components.yaml
        |       |-- metadata.yaml
        |-- infrastructure-metal3
            |-- v1.6.0
                |-- cluster-template.yaml
                |-- infrastructure-components.yaml
                |-- metadata.yaml

clusterctl.yaml 文件包含的配置用于指定映像位置以及 clusterctl 工具要使用的覆盖值。overrides 文件夹包含要使用的(而不是从互联网下载的)yaml 文件清单。

providers:
  # override a pre-defined provider
  - name: "cluster-api"
    url: "/root/cluster-api/overrides/cluster-api/v1.6.2/core-components.yaml"
    type: "CoreProvider"
  - name: "metal3"
    url: "/root/cluster-api/overrides/infrastructure-metal3/v1.6.0/infrastructure-components.yaml"
    type: "InfrastructureProvider"
  - name: "rke2"
    url: "/root/cluster-api/overrides/bootstrap-rke2/v0.2.6/bootstrap-components.yaml"
    type: "BootstrapProvider"
  - name: "rke2"
    url: "/root/cluster-api/overrides/control-plane-rke2/v0.2.6/control-plane-components.yaml"
    type: "ControlPlaneProvider"
images:
  all:
    repository: registry.suse.com/edge

可以使用以下 curl 命令下载 clusterctl,以及 overrides 文件夹中包含的其他文件:

# clusterctl binary
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/1.6.2/clusterctl-linux-${GOARCH} -o /usr/local/bin/clusterct

# boostrap-components (boostrap-rke2)
curl -L https://github.com/rancher-sandbox/cluster-api-provider-rke2/releases/download/v0.2.6/bootstrap-components.yaml
curl -L https://github.com/rancher-sandbox/cluster-api-provider-rke2/releases/download/v0.2.6/metadata.yaml

# control-plane-components (control-plane-rke2)
curl -L https://github.com/rancher-sandbox/cluster-api-provider-rke2/releases/download/v0.2.6/control-plane-components.yaml
curl -L https://github.com/rancher-sandbox/cluster-api-provider-rke2/releases/download/v0.2.6/metadata.yaml

# cluster-api components
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.6.2/core-components.yaml
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.6.2/metadata.yaml

# infrastructure-components (infrastructure-metal3)
curl -L https://github.com/metal3-io/cluster-api-provider-metal3/releases/download/v1.6.0/infrastructure-components.yaml
curl -L https://github.com/metal3-io/cluster-api-provider-metal3/releases/download/v1.6.0/metadata.yaml
注意
注意

如果您要使用不同版本的组件,可以更改 URL 中的版本以下载特定版本的组件。

下载上述资源后,可以使用以下命令将其压缩成单个文件:

tar -czvf airgap-resources.tar.gz clusterctl clusterctl.yaml overrides

29.5 映像创建

按照前面的章节准备好目录结构后(适用于联网方案和隔离方案),运行以下命令来构建映像:

podman run --rm --privileged -it -v $PWD:/eib \
 registry.suse.com/edge/edge-image-builder:1.0.2 \
 build --definition-file mgmt-cluster.yaml

这会创建 ISO 输出映像文件,在本例中,根据前面所述的映像定义,该文件是 eib-mgmt-cluster-image.iso

29.6 置备管理群集

上图包含前面介绍的所有组件,可以使用虚拟机或裸机服务器(使用虚拟媒体功能)根据此图置备管理群集。

30 电信功能配置

本章将阐释部署了 ATIP 的群集上特定于电信的功能配置。

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

本章涵盖以下主题:

30.1 实时内核映像

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

实时内核有四大特性:

  • 确定性执行:

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

  • 低抖动:

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

  • 优先级继承:

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

  • 线程中断:

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

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

    注意
    注意

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

30.2 CPU 已微调配置

使用 CPU 已微调配置可以隔离 CPU 核心供实时内核使用。必须防止操作系统与实时内核使用相同的核心,因为操作系统有可能会使用这些核心,导致提高实时内核的延迟。

要启用和配置此功能,首先应该为我们想要隔离的 CPU 核心创建一个配置文件。在本例中,我们将隔离核心 1-3033-62

$ 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.

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

参数说明

isolcpus

1-30,33-62

隔离核心 1-30 和 33-62

skew_tick

1

此选项允许内核在隔离的 CPU 之间偏斜计时器中断。

nohz

on

此选项允许内核在系统空闲时在单个 CPU 上运行计时器滴答周期。

nohz_full

1-30,33-62

内核引导参数是当前用于配置完整 dynticks 及 CPU 隔离的主接口。

rcu_nocbs

1-30,33-62

此选项允许内核在系统空闲时在单个 CPU 上运行 RCU 回调。

kthread_cpus

0,31,32,63

此选项允许内核在系统空闲时在单个 CPU 上运行 kthreads。

irqaffinity

0,31,32,63

此选项允许内核在系统空闲时在单个 CPU 上运行中断。

processor.max_cstate

1

此选项防止 CPU 在空闲时进入休眠状态

intel_idle.max_cstate

0

此选项禁用 intel_idle 驱动程序并允许使用 acpi_idle

我们将使用上面所示的值隔离 60 个核心,并将其中 4 个核心用于操作系统。

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

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

GRUB_CMDLINE_LINUX="intel_iommu=on intel_pstate=passive processor.max_cstate=1 intel_idle.max_cstate=0 iommu=pt usbcore.autosuspend=-1 selinux=0 enforcing=0 nmi_watchdog=0 crashkernel=auto softlockup_panic=0 audit=0 mce=off hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 default_hugepagesz=1G kthread_cpus=0,31,32,63 irqaffinity=0,31,32,63 isolcpus=1-30,33-62 skew_tick=1 nohz_full=1-30,33-62 rcu_nocbs=1-30,33-62 rcu_nocb_poll"

更新 GRUB 配置:

$ transactional-update grub.cfg
$ reboot

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

$ cat /proc/cmdline

30.3 CNI 配置

30.3.1 Cilium

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

cni:
- cilium

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

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

cni:
- multus
- cilium
注意
注意

有关 CNI 插件的详细信息,请访问网络选项

30.4 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

可以发现许多组合,并创建资源组来为 Pod 分配一些 VF

注意
注意

有关过滤器和组的详细信息,请访问 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.5.1-build20231009-amd64
        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。

  • 如果您使用设备插件和配置映射但未使用 Helm chart 部署了 SR-IOV,则 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。

可以通过两种方式完成此操作:使用 CLI 或使用 Rancher UI

从 CLI 安装 Operator
helm repo add suse-edge https://suse-edge.github.io/charts
helm install sriov-crd suse-edge/sriov-crd -n sriov-network-operator
helm install install sriov-network-operator suse-edge/sriov-network-operator -n sriov-network-operator
从 Rancher UI 安装 Operator

安装群集后,如果您可以访问 Rancher UI,则可以通过 Rancher UI 中的应用程序选项卡安装 SR-IOV Operator

注意
注意

确保选择正确的名称空间来安装 Operator,例如 sriov-network-operator

+ image::features_sriov.png[sriov.png]

  • 检查已部署的资源 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.3.1", "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: ""

30.5 DPDK

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

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

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

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

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

  5. 包框架以一组库的形式提供,可帮助开发包处理解决方案。

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

  • 安装 DPDK 软件包:

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

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

参数说明

iommu

pt

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

intel_iommu

on

此选项允许为 VF 使用 vfio

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

GRUB_CMDLINE_LINUX="intel_iommu=on intel_pstate=passive processor.max_cstate=1 intel_idle.max_cstate=0 iommu=pt usbcore.autosuspend=-1 selinux=0 enforcing=0 nmi_watchdog=0 crashkernel=auto softlockup_panic=0 audit=0 mce=off hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 default_hugepagesz=1G kthread_cpus=0,31,32,63 irqaffinity=0,31,32,63 isolcpus=1-30,33-62 skew_tick=1 nohz_full=1-30,33-62 rcu_nocbs=1-30,33-62 rcu_nocb_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

30.6 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

on

此选项允许为 VF 使用 vfio。

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

GRUB_CMDLINE_LINUX="intel_iommu=on intel_pstate=passive processor.max_cstate=1 intel_idle.max_cstate=0 iommu=pt usbcore.autosuspend=-1 selinux=0 enforcing=0 nmi_watchdog=0 crashkernel=auto softlockup_panic=0 audit=0 mce=off hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 default_hugepagesz=1G kthread_cpus=0,31,32,63 irqaffinity=0,31,32,63 isolcpus=1-30,33-62 skew_tick=1 nohz_full=1-30,33-62 rcu_nocbs=1-30,33-62 rcu_nocb_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=

30.7 大页

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

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

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

  • 内核参数

要启用大页,应添加以下内核参数:

参数说明

hugepagesz

1G

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

hugepages

40

这是先前定义的大页数量

default_hugepagesz

1G

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

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

GRUB_CMDLINE_LINUX="intel_iommu=on intel_pstate=passive processor.max_cstate=1 intel_idle.max_cstate=0 iommu=pt usbcore.autosuspend=-1 selinux=0 enforcing=0 nmi_watchdog=0 crashkernel=auto softlockup_panic=0 audit=0 mce=off hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 default_hugepagesz=1G kthread_cpus=0,31,32,63 irqaffinity=0,31,32,63 isolcpus=1-30,33-62 skew_tick=1 nohz_full=1-30,33-62 rcu_nocbs=1-30,33-62 rcu_nocb_poll"

更新 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
...

30.8 CPU 固定配置

  • 要求

    1. 必须根据第 30.2 节 “CPU 已微调配置”一节中所述的性能配置文件微调 CPU

    2. 必须使用 CPU 管理参数配置 RKE2 群集 kubelet,为此请将以下块(示例)添加到 /etc/rancher/rke2/config.yaml 文件中:

kubelet-arg:
- "cpu-manager=true"
- "cpu-manager-policy=static"
- "cpu-manager-policy-options=full-pcpus-only=true"
- "cpu-manager-reconcile-period=0s"
- "kubelet-reserved=cpu=1"
- "system-reserved=cpu=1"
  • 在 Kubernetes 上使用 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"

30.9 可感知 NUMA 的调度

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

30.9.1 识别 NUMA 节点

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

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

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

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

30.10 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:
  repo: https://metallb.github.io/metallb/
  chart: metallb
  targetNamespace: metallb-system
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
  name: endpoint-copier-operator
  namespace: kube-system
spec:
  repo: https://suse-edge.github.io/endpoint-copier-operator
  chart: endpoint-copier-operator
  targetNamespace: endpoint-copier-operator
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

30.11 专用注册表配置

可以配置 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 注册表配置

31 全自动定向网络置备

31.1 简介

定向网络置备是用于自动置备下游群集的功能。如果您有许多下游群集需要置备并希望自动完成该过程,此功能将非常有用。

管理群集(第 29 章 “设置管理群集)会自动部署以下组件:

  • SUSE Linux Enterprise Micro RT(操作系统)。可以根据用例自定义网络、存储、用户和内核参数等配置。

  • RKE2(Kubernetes 群集)。默认的 CNI 插件为 Cilium。根据具体的用例,可以使用 Cilium+Multus 等某些 CNI 插件。

  • Longhorn(存储解决方案)。

  • NeuVector(安全解决方案)。

  • MetalLB 可用作高可用性多节点群集的负载平衡器。

注意
注意

有关 SUSE Linux Enterprise Micro 的详细信息,请参见第 7 章 “SLE Micro。有关 RKE2 的详细信息,请参见第 14 章 “RKE2。有关 Longhorn 的详细信息,请参见第 15 章 “Longhorn。有关 NeuVector 的详细信息,请参见第 16 章 “NeuVector

以下章节介绍了不同的定向网络置备工作流程,以及可添加到置备过程的一些附加功能:

31.2 为联网方案准备下游群集映像

Edge Image Builder(第 9 章 “Edge Image Builder)用于准备下游群集主机上置备的经过修改的 SLEMicro 基础映像。

可以通过 Edge Image Builder 完成大部分配置,但本指南仅介绍设置下游群集所需的最低限度配置。

31.2.1 联网方案的先决条件

31.2.2 联网方案的映像配置

运行 Edge Image Builder 时,将从主机挂载一个目录,因此需要创建一个目录结构来存储用于定义目标映像的配置文件。

├── downstream-cluster-config.yaml
├── base-images/
│   └ SLE-Micro.x86_64-5.5.0-Default-RT-GM.raw
├── network/
|   └ configure-network.sh
└── custom/
    └ scripts/
        └ 01-fix-growfs.sh

31.2.2.1 下游群集映像定义文件

downstream-cluster-config.yaml 文件是下游群集映像的主配置文件。下面是通过 Metal3 进行部署的极简示例:

apiVersion: 1.0
image:
  imageType: RAW
  arch: x86_64
  baseImage: SLE-Micro.x86_64-5.5.0-Default-RT-GM.raw
  outputImageName: eibimage-slemicro55rt-telco.raw
operatingSystem:
  kernelArgs:
    - ignition.platform.id=openstack
    - net.ifnames=1
  systemd:
    disable:
      - rebootmgr
  users:
    - username: root
      encryptedPassword: ${ROOT_PASSWORD}
      sshKeys:
      - ${USERKEY1}

${ROOT_PASSWORD} 是 root 用户的已加密口令,可用于测试/调试。可以使用 openssl passwd-6 PASSWORD 命令生成此口令

对于生产环境,建议使用可添加到 users 块的 SSH 密钥(将该块中的 ${USERKEY1} 替换为实际 SSH 密钥)。

注意
注意

net.ifnames=1 会启用可预测网络接口命名

这与 metal3 chart 的默认配置相匹配,但设置必须与配置的 chart predictableNicNames 值相匹配。

另请注意,ignition.platform.id=openstack 是必需的,如果不指定此参数,在 Metal3 自动化流程中通过 ignition 进行 SLEMicro 配置将会失败。

31.2.2.2 Growfs 脚本

目前,在置备后首次引导时,需要使用一个自定义脚本 (custom/scripts/01-fix-growfs.sh) 来增大文件系统,使之与磁盘大小匹配。01-fix-growfs.sh 脚本包含以下信息:

#!/bin/bash
growfs() {
  mnt="$1"
  dev="$(findmnt --fstab --target ${mnt} --evaluate --real --output SOURCE --noheadings)"
  # /dev/sda3 -> /dev/sda, /dev/nvme0n1p3 -> /dev/nvme0n1
  parent_dev="/dev/$(lsblk --nodeps -rno PKNAME "${dev}")"
  # Last number in the device name: /dev/nvme0n1p42 -> 42
  partnum="$(echo "${dev}" | sed 's/^.*[^0-9]\([0-9]\+\)$/\1/')"
  ret=0
  growpart "$parent_dev" "$partnum" || ret=$?
  [ $ret -eq 0 ] || [ $ret -eq 1 ] || exit 1
  /usr/lib/systemd/systemd-growfs "$mnt"
}
growfs /
注意
注意

使用相同的方法添加您自己的自定义脚本,以便在置备过程中执行。有关详细信息,请参见第 3 章 “使用 Edge Image Builder 配置独立群集

与此解决方法相关的 bug 为 https://bugzilla.suse.com/show_bug.cgi?id=1217430

31.2.2.3 电信工作负载的附加配置

要启用 dpdksr-iovFEC 等电信功能,可能需要提供附加软件包,如以下示例中所示。

apiVersion: 1.0
image:
  imageType: RAW
  arch: x86_64
  baseImage: SLE-Micro.x86_64-5.5.0-Default-RT-GM.raw
  outputImageName: eibimage-slemicro55rt-telco.raw
operatingSystem:
  kernelArgs:
    - ignition.platform.id=openstack
    - net.ifnames=1
  systemd:
    disable:
      - rebootmgr
  users:
    - username: root
      encryptedPassword: ${ROOT_PASSWORD}
      sshKeys:
      - ${user1Key1}
  packages:
    packageList:
      - jq
      - dpdk22
      - dpdk22-tools
      - libdpdk-23
      - pf-bb-config
    additionalRepos:
      - url: https://download.opensuse.org/repositories/isv:/SUSE:/Edge:/Telco/SLEMicro5.5/
    sccRegistrationCode: ${SCC_REGISTRATION_CODE}

其中 ${SCC_REGISTRATION_CODE} 是从 SUSE Customer Center 复制的注册码,软件包列表包含用于电信配置文件的最少量软件包。要使用 pf-bb-config 软件包(用于启用 FEC 功能并与驱动程序绑定),必须包含 additionalRepos 块,以添加 SUSE Edge Telco 储存库。

31.2.2.4 高级网络配置的附加脚本

如果您需要配置静态 IP 或第 31.6 节 “高级网络配置”中所述的更高级网络方案,则需要提供以下附加配置。

network 文件夹中创建以下 configure-network.sh 文件 - 这会在首次引导时使用配置驱动器数据,并使用 NM Configurator 工具来配置主机网络。

#!/bin/bash

set -eux

# Attempt to statically configure a NIC in the case where we find a network_data.json
# In a configuration drive

CONFIG_DRIVE=$(blkid --label config-2 || true)
if [ -z "${CONFIG_DRIVE}" ]; then
  echo "No config-2 device found, skipping network configuration"
  exit 0
fi

mount -o ro $CONFIG_DRIVE /mnt

NETWORK_DATA_FILE="/mnt/openstack/latest/network_data.json"

if [ ! -f "${NETWORK_DATA_FILE}" ]; then
  umount /mnt
  echo "No network_data.json found, skipping network configuration"
  exit 0
fi

DESIRED_HOSTNAME=$(cat /mnt/openstack/latest/meta_data.json | tr ',{}' '\n' | grep '\"metal3-name\"' | sed 's/.*\"metal3-name\": \"\(.*\)\"/\1/')

mkdir -p /tmp/nmc/{desired,generated}
cp ${NETWORK_DATA_FILE} /tmp/nmc/desired/${DESIRED_HOSTNAME}.yaml
umount /mnt

./nmc generate --config-dir /tmp/nmc/desired --output-dir /tmp/nmc/generated
./nmc apply --config-dir /tmp/nmc/generated

31.2.3 映像创建

按照前面的章节准备好目录结构后,运行以下命令来构建映像:

podman run --rm --privileged -it -v $PWD:/eib \
 registry.suse.com/edge/edge-image-builder:1.0.2 \
 build --definition-file downstream-cluster-config.yaml

这会根据上述定义创建名为 eibimage-slemicro55rt-telco.raw 的输出 ISO 映像文件。

然后必须通过 Web 服务器提供输出映像,该服务器可以是根据管理群集文档(注意)启用的媒体服务器容器,也可以是其他某个本地可访问的服务器。在下面的示例中,此服务器是 imagecache.local:8080

31.3 为隔离方案准备下游群集映像

Edge Image Builder(第 9 章 “Edge Image Builder)用于准备下游群集主机上置备的经过修改的 SLEMicro 基础映像。

可以通过 Edge Image Builder 完成大部分配置,但本指南仅介绍为隔离方案设置下游群集所需的最低限度配置。

31.3.1 隔离方案的先决条件

  • 需要安装 PodmanRancher Desktop 等容器运行时,以便能够运行 Edge Image Builder。

  • 必须从 SUSE Customer CenterSUSE 下载页面下载 SLE-Micro.x86_64-5.5.0-Default-RT-GM.raw 基础映像。

  • 如果您要使用 SR-IOV 或任何其他需要容器映像的工作负载,则必须部署并事先配置一个本地专用注册表(设置/未设置 TLS 和/或身份验证)。此注册表用于存储 Helm chart OCI 映像及其他映像。

31.3.2 隔离方案的映像配置

运行 Edge Image Builder 时,将从主机挂载一个目录,因此需要创建一个目录结构来存储用于定义目标映像的配置文件。

  • downstream-cluster-airgap-config.yaml 是映像定义文件,有关更多细节,请参见第 3 章 “使用 Edge Image Builder 配置独立群集

  • 下载的基础映像已经过 xz 压缩,必须使用 unxz 将其解压缩,并将其复制/移动到 base-images 文件夹中。

  • network 文件夹是可选的,有关更多细节,请参见第 31.2.2.4 节 “高级网络配置的附加脚本”

  • custom/scripts 目录包含首次引导时运行的脚本;目前需要使用 01-fix-growfs.sh 脚本来调整部署中的操作系统根分区的大小。对于隔离方案,需要使用 02-airgap.sh 脚本在映像创建过程中将映像复制到正确的位置。

  • custom/files 目录包含映像创建过程中要复制到该映像的 rke2cni 映像。

├── downstream-cluster-airgap-config.yaml
├── base-images/
│   └ SLE-Micro.x86_64-5.5.0-Default-RT-GM.raw
├── network/
|   └ configure-network.sh
└── custom/
    └ files/
    |   └ install.sh
    |   └ rke2-images-cilium.linux-amd64.tar.zst
    |   └ rke2-images-core.linux-amd64.tar.zst
    |   └ rke2-images-multus.linux-amd64.tar.zst
    |   └ rke2-images.linux-amd64.tar.zst
    |   └ rke2.linux-amd64.tar.zst
    |   └ sha256sum-amd64.txt
    └ scripts/
        └ 01-fix-growfs.sh
        └ 02-airgap.sh

31.3.2.1 下游群集映像定义文件

downstream-cluster-airgap-config.yaml 文件是下游群集映像的主配置文件,上一节(第 31.2.2.3 节 “电信工作负载的附加配置”)已介绍其内容。

31.3.2.2 Growfs 脚本

目前,在置备后首次引导时,需要使用一个自定义脚本 (custom/scripts/01-fix-growfs.sh) 来增大文件系统,使之与磁盘大小匹配。01-fix-growfs.sh 脚本包含以下信息:

#!/bin/bash
growfs() {
  mnt="$1"
  dev="$(findmnt --fstab --target ${mnt} --evaluate --real --output SOURCE --noheadings)"
  # /dev/sda3 -> /dev/sda, /dev/nvme0n1p3 -> /dev/nvme0n1
  parent_dev="/dev/$(lsblk --nodeps -rno PKNAME "${dev}")"
  # Last number in the device name: /dev/nvme0n1p42 -> 42
  partnum="$(echo "${dev}" | sed 's/^.*[^0-9]\([0-9]\+\)$/\1/')"
  ret=0
  growpart "$parent_dev" "$partnum" || ret=$?
  [ $ret -eq 0 ] || [ $ret -eq 1 ] || exit 1
  /usr/lib/systemd/systemd-growfs "$mnt"
}
growfs /

31.3.2.3 隔离脚本

在映像创建过程中,需要使用以下脚本 (custom/scripts/02-airgap.sh) 将映像复制到正确的位置:

#!/bin/bash

# create the folder to extract the artifacts there
mkdir -p /opt/rke2-artifacts
mkdir -p /var/lib/rancher/rke2/agent/images

# copy the artifacts
cp install.sh /opt/
cp rke2-images*.tar.zst rke2.linux-amd64.tar.gz sha256sum-amd64.txt /opt/rke2-artifacts/

31.3.2.4 隔离方案的自定义文件

custom/files 目录包含映像创建过程中要复制到该映像的 rke2cni 映像。为了轻松生成映像,请使用以下脚本此处的映像列表在本地准备这些映像,以生成需要包含在 custom/files 中的项目。另外,可以从此处下载最新的 rke2-install 脚本。

$ ./edge-save-rke2-images.sh -o custom/files -l ~/edge-release-rke2-images.txt

下载映像后,目录结构应如下所示:

└── custom/
    └ files/
        └ install.sh
        └ rke2-images-cilium.linux-amd64.tar.zst
        └ rke2-images-core.linux-amd64.tar.zst
        └ rke2-images-multus.linux-amd64.tar.zst
        └ rke2-images.linux-amd64.tar.zst
        └ rke2.linux-amd64.tar.zst
        └ sha256sum-amd64.txt

31.3.2.5 预加载包含隔离方案和 SR-IOV 所需映像的专用注册表(可选)

如果您要在隔离方案中使用 SR-IOV 或要使用任何其他工作负载映像,必须按照以下步骤预加载包含这些映像的本地专用注册表:

  • 下载、提取 helm-chart OCI 映像并将其推送到专用注册表

  • 下载、提取所需的其余映像并将其推送到专用注册表

可使用以下脚本下载、提取映像并将其推送到专用注册表。本节将通过一个示例来说明如何预加载 SR-IOV 映像,但您也可以使用相同的方法来预加载任何其他自定义映像:

  1. 预加载 SR-IOV 的 helm-chart OCI 映像:

    1. 必须创建一个包含所需 helm-chart OCI 映像的列表:

      $ cat > edge-release-helm-oci-artifacts.txt <<EOF
      edge/sriov-network-operator-chart:1.2.2
      edge/sriov-crd-chart:1.2.2
      EOF
    2. 使用以下脚本和上面创建的列表生成本地 tarball 文件:

      $ ./edge-save-oci-artefacts.sh -al ./edge-release-helm-oci-artifacts.txt -s registry.suse.com
      Pulled: registry.suse.com/edge/sriov-network-operator-chart:1.2.2
      Pulled: registry.suse.com/edge/sriov-crd-chart:1.2.2
      a edge-release-oci-tgz-20240705
      a edge-release-oci-tgz-20240705/sriov-network-operator-chart-1.2.2.tgz
      a edge-release-oci-tgz-20240705/sriov-crd-chart-1.2.2.tgz
    3. 使用以下脚本将 tarball 文件上载到专用注册表(例如 myregistry:5000),以预加载包含上一步骤中下载的 helm chart OCI 映像的注册表:

      $ tar zxvf edge-release-oci-tgz-20240705.tgz
      $ ./edge-load-oci-artefacts.sh -ad edge-release-oci-tgz-20240705 -r myregistry:5000
  2. 预加载 SR-IOV 所需的其余映像:

    1. 在这种情况下,必须包含电信工作负载的 sr-iov 容器映像(例如,作为参考,您可以从 helm-chart 值获取这些映像)

      $ cat > edge-release-images.txt <<EOF
      rancher/hardened-sriov-network-operator:v1.2.0-build20240327
      rancher/rancher/hardened-sriov-network-config-daemon:v1.2.0-build20240327
      rancher/hardened-sriov-cni:v1.2.0-build20240327
      rancher/hardened-ib-sriov-cni:v1.2.0-build20240327
      rancher/hardened-sriov-network-device-plugin:v1.2.0-build20240327
      rancher/hardened-sriov-network-resources-injector:v1.2.0-build20240327
      rancher/hardened-sriov-network-webhook:v1.2.0-build20240327
      EOF
    2. 必须使用以下脚本和上面创建的列表,在本地生成包含所需映像的 tarball 文件:

      $ ./edge-save-images.sh -al ./edge-release-images.txt -s registry.suse.com
      Pulled: registry.suse.com/rancher/hardened-sriov-network-operator:v1.2.0-build20240327
      Pulled: registry.suse.com/rancher/rancher/hardened-sriov-network-config-daemon:v1.2.0-build20240327
      Pulled: registry.suse.com/rancher/hardened-sriov-cni:v1.2.0-build20240327
      Pulled: registry.suse.com/rancher/hardened-ib-sriov-cni:v1.2.0-build20240327
      Pulled: registry.suse.com/rancher/hardened-sriov-network-device-plugin:v1.2.0-build20240327
      Pulled: registry.suse.com/rancher/hardened-sriov-network-resources-injector:v1.2.0-build20240327
      Pulled: registry.suse.com/rancher/hardened-sriov-network-webhook:v1.2.0-build20240327
      a edge-release-images-tgz-20240705
      a edge-release-images-tgz-20240705/hardened-sriov-network-operator-v1.2.0-build20240327.tar.gz
      a edge-release-images-tgz-20240705/hardened-sriov-network-config-daemon-v1.2.0-build20240327.tar.gz
      a edge-release-images-tgz-20240705/hardened-sriov-cni-v1.2.0-build20240327.tar.gz
      a edge-release-images-tgz-20240705/hardened-ib-sriov-cni-v1.2.0-build20240327.tar.gz
      a edge-release-images-tgz-20240705/hardened-sriov-network-device-plugin-v1.2.0-build20240327.tar.gz
      a edge-release-images-tgz-20240705/hardened-sriov-network-resources-injector-v1.2.0-build20240327.tar.gz
      a edge-release-images-tgz-20240705/hardened-sriov-network-webhook-v1.2.0-build20240327.tar.gz
    3. 使用以下脚本将 tarball 文件上载到专用注册表(例如 myregistry:5000),以预加载包含上一步骤中下载的映像的专用注册表:

      $ tar zxvf edge-release-images-tgz-20240705.tgz
      $ ./edge-load-images.sh -ad edge-release-images-tgz-20240705 -r myregistry:5000

31.3.3 为隔离方案创建映像

按照前面的章节准备好目录结构后,运行以下命令来构建映像:

podman run --rm --privileged -it -v $PWD:/eib \
 registry.suse.com/edge/edge-image-builder:1.0.2 \
 build --definition-file downstream-cluster-airgap-config.yaml

这会根据上述定义创建名为 eibimage-slemicro55rt-telco.raw 的输出 ISO 映像文件。

然后必须通过 Web 服务器提供输出映像,该服务器可以是根据管理群集文档(注意)启用的媒体服务器容器,也可以是其他某个本地可访问的服务器。在下面的示例中,此服务器是 imagecache.local:8080

31.4 使用定向网络置备来置备下游群集(单节点)

本节介绍用于通过定向网络置备自动置备单节点下游群集的工作流程。这是自动置备下游群集的最简单方法。

要求

工作流程

下图显示了用于通过定向网络置备自动置备单节点下游群集的工作流程:

ATIP 单节点群集自动置备 1

可以执行两个不同的步骤来使用定向网络置备自动置备单节点下游群集:

  1. 登记裸机主机,使其在置备过程中可用。

  2. 置备裸机主机,以安装并配置操作系统和 Kubernetes 群集。

登记裸机主机

第一步是在管理群集中登记新的裸机主机,使其可供置备。为此,必须在管理群集中创建以下文件 (bmh-example.yaml),以指定要使用的 BMC 身份凭证以及要登记的 BaremetalHost 对象:

apiVersion: v1
kind: Secret
metadata:
  name: example-demo-credentials
type: Opaque
data:
  username: ${BMC_USERNAME}
  password: ${BMC_PASSWORD}
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
  name: flexran-demo
  labels:
    cluster-role: control-plane
spec:
  online: true
  bootMACAddress: ${BMC_MAC}
  rootDeviceHints:
    deviceName: /dev/nvme0n1
  bmc:
    address: ${BMC_ADDRESS}
    disableCertificateVerification: true
    credentialsName: example-demo-credentials

其中:

  • ${BMC_USERNAME} — 新裸机主机的 BMC 用户名。

  • ${BMC_PASSWORD} — 新裸机主机的 BMC 口令。

  • ${BMC_MAC} — 要使用的新裸机主机 MAC 地址。

  • ${BMC_ADDRESS} — 裸机主机 BMCURL(例如 redfish-virtualmedia://192.168.200.75/redfish/v1/Systems/1/)。要了解有关硬件提供商支持的不同选项的详细信息,请访问此链接

创建该文件后,必须在管理群集中执行以下命令,才能在管理群集中开始登记新的裸机主机:

$ kubectl apply -f bmh-example.yaml

随后会登记新裸机主机对象,其状态将从正在注册依次更改为正在检查和可用。可使用以下命令检查状态更改:

$ kubectl get bmh
注意
注意

在验证 BMC 身份凭证之前,BaremetalHost 对象将一直处于正在注册状态。验证身份凭证后,BaremetalHost 对象的状态将更改为正在检查,此步骤可能需要一段时间(最长 20 分钟),具体取决于所用的硬件。在检查阶段,将检索硬件信息并更新 Kubernetes 对象。使用以下命令检查信息:kubectl get bmh -o yaml

置备步骤

裸机主机已登记并可供使用后,下一步是置备裸机主机,以安装并配置操作系统和 Kubernetes 群集。为此,必须在管理群集中创建以下文件 (capi-provisioning-example.yaml) 并在其中包含以下信息(可以通过联接以下块来生成 capi-provisioning-example.yaml)。

注意
注意

只需将 ${...} 中的值替换为实际值。

下面的块是群集定义,可在其中使用 podsservices 块来配置网络。此外,它还包含对要使用的控制平面和基础架构(使用 Metal3 提供程序)对象的引用。

apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: single-node-cluster
  namespace: default
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
        - 192.168.0.0/18
    services:
      cidrBlocks:
        - 10.96.0.0/12
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
    kind: RKE2ControlPlane
    name: single-node-cluster
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3Cluster
    name: single-node-cluster

Metal3Cluster 对象指定要配置的控制平面端点(请替换 ${DOWNSTREAM_CONTROL_PLANE_IP})以及 noCloudProvider,因为使用了一个裸机节点。

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3Cluster
metadata:
  name: single-node-cluster
  namespace: default
spec:
  controlPlaneEndpoint:
    host: ${DOWNSTREAM_CONTROL_PLANE_IP}
    port: 6443
  noCloudProvider: true

RKE2ControlPlane 对象指定要使用的控制平面配置,Metal3MachineTemplate 对象指定要使用的控制平面映像。此外,它还包含有关要使用的复本数(在本例中为 1)以及要使用的 CNI 插件(在本例中为 Cilium)的信息。agentConfig 块包含要使用的 Ignition 格式以及用于配置 RKE2 节点的 additionalUserData,其中包含名为 rke2-preinstall.service 的 systemd 等信息,用于在置备过程中使用 Ironic 信息自动替换 BAREMETALHOST_UUIDnode-name。最后一个信息块包含要使用的 Kubernetes 版本。${RKE2_VERSION} 是要使用的 RKE2 版本,请替换此值(例如替换为 v1.28.9+rke2r1)。

apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
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
  serverConfig:
    cni: cilium
  agentConfig:
    format: ignition
    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
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    version: ${RKE2_VERSION}
    nodeName: "localhost.localdomain"

Metal3MachineTemplate 对象指定以下信息:

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
metadata:
  name: single-node-cluster-controlplane
  namespace: default
spec:
  template:
    spec:
      dataTemplate:
        name: single-node-cluster-controlplane-template
      hostSelector:
        matchLabels:
          cluster-role: control-plane
      image:
        checksum: http://imagecache.local:8080/eibimage-slemicro55rt-telco.raw.sha256
        checksumType: sha256
        format: raw
        url: http://imagecache.local:8080/eibimage-slemicro55rt-telco.raw

Metal3DataTemplate 对象指定下游群集的 metaData

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3DataTemplate
metadata:
  name: single-node-cluster-controlplane-template
  namespace: default
spec:
  clusterName: single-node-cluster
  metaData:
    objectNames:
      - key: name
        object: machine
      - key: local-hostname
        object: machine
      - key: local_hostname
        object: machine

通过联接上述块创建该文件后,必须在管理群集中执行以下命令才能开始置备新的裸机主机:

$ kubectl apply -f capi-provisioning-example.yaml

31.5 使用定向网络置备来置备下游群集(多节点)

本节介绍用于通过定向网络置备和 MetalLB(用作负载平衡器策略)自动置备多节点下游群集的工作流程。这是自动置备下游群集的最简单方法。下图显示了用于通过定向网络置备和 MetalLB 自动置备多节点下游群集的工作流程。

要求

工作流程

下图显示了用于通过定向网络置备自动置备多节点下游群集的工作流程:

ATIP 多节点群集自动置备 1
  1. 登记三个裸机主机,使其在置备过程中可用。

  2. 置备三个裸机主机,以使用 MetalLB 安装并配置操作系统和 Kubernetes 群集。

登记裸机主机

第一步是在管理群集中登记三个裸机主机,使其可供置备。为此,必须在管理群集中创建以下文件(bmh-example-node1.yamlbmh-example-node2.yamlbmh-example-node3.yaml),以指定要使用的 BMC 身份凭证,以及要在管理群集中登记的 BaremetalHost 对象。

注意
注意
  • 只需将 ${...} 中的值替换为实际值。

  • 本节只会指导您完成一个主机的置备过程。这些步骤同样适用于另外两个节点。

apiVersion: v1
kind: Secret
metadata:
  name: node1-example-credentials
type: Opaque
data:
  username: ${BMC_NODE1_USERNAME}
  password: ${BMC_NODE1_PASSWORD}
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
  name: node1-example
  labels:
    cluster-role: control-plane
spec:
  online: true
  bootMACAddress: ${BMC_NODE1_MAC}
  bmc:
    address: ${BMC_NODE1_ADDRESS}
    disableCertificateVerification: true
    credentialsName: node1-example-credentials

其中:

  • ${BMC_NODE1_USERNAME} — 第一个裸机主机的 BMC 用户名。

  • ${BMC_NODE1_PASSWORD} — 第一个裸机主机的 BMC 口令。

  • ${BMC_NODE1_MAC} — 第一个裸机主机的要使用的 MAC 地址。

  • ${BMC_NODE1_ADDRESS} — 第一个裸机主机的 BMC 的 URL(例如 redfish-virtualmedia://192.168.200.75/redfish/v1/Systems/1/)。要了解有关硬件提供商支持的不同选项的详细信息,请访问此链接

创建该文件后,必须在管理群集中执行以下命令,才能在管理群集中开始登记裸机主机:

$ kubectl apply -f bmh-example-node1.yaml
$ kubectl apply -f bmh-example-node2.yaml
$ kubectl apply -f bmh-example-node3.yaml

随后会登记新裸机主机对象,其状态将从正在注册依次更改为正在检查和可用。可使用以下命令检查状态更改:

$ kubectl get bmh -o wide
注意
注意

在验证 BMC 身份凭证之前,BaremetalHost 对象将一直处于正在注册状态。验证身份凭证后,BaremetalHost 对象的状态将更改为正在检查,此步骤可能需要一段时间(最长 20 分钟),具体取决于所用的硬件。在检查阶段,将检索硬件信息并更新 Kubernetes 对象。使用以下命令检查信息:kubectl get bmh -o yaml

置备步骤

三个裸机主机已登记并可供使用后,下一步是置备裸机主机,以安装和配置操作系统与 Kubernetes 群集,并创建用于管理该操作系统和群集的负载平衡器。为此,必须在管理群集中创建以下文件 (capi-provisioning-example.yaml) 并在其中包含以下信息(可以通过联接以下块来生成 capi-provisioning-example.yaml)。

注意
注意
  • 只需将 ${...} 中的值替换为实际值。

  • VIP 地址是尚未分配给任何节点的预留 IP 地址,用于配置负载平衡器。

下面为群集定义,可在其中使用 podsservices 块来配置群集网络。此外,它还包含对要使用的控制平面和基础架构(使用 Metal3 提供程序)对象的引用。

apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: multinode-cluster
  namespace: default
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
        - 192.168.0.0/18
    services:
      cidrBlocks:
        - 10.96.0.0/12
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
    kind: RKE2ControlPlane
    name: multinode-cluster
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3Cluster
    name: multinode-cluster

Metal3Cluster 对象指定要配置的、使用预留的 VIP 地址(请替换 ${DOWNSTREAM_VIP_ADDRESS})的控制平面端点以及 noCloudProvider,因为使用了三个裸机节点。

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3Cluster
metadata:
  name: multinode-cluster
  namespace: default
spec:
  controlPlaneEndpoint:
    host: ${EDGE_VIP_ADDRESS}
    port: 6443
  noCloudProvider: true

RKE2ControlPlane 对象指定要使用的控制平面配置,Metal3MachineTemplate 对象指定要使用的控制平面映像。

  • 要使用的复本数(在本例中为 3)。

  • 负载平衡器要使用的广告模式(address 使用 L2 实现),以及要使用的地址(请将 ${EDGE_VIP_ADDRESS} 替换为 VIP 地址)。

  • serverConfig,其中包含要使用的 CNI 插件(在本例中为 Cilium);用于配置 VIP 地址的 tlsSan

  • agentConfig 块包含要使用的 Ignition 格式以及用于配置 RKE2 节点的 additionalUserData,其中的信息如下:

    • 名为 rke2-preinstall.service 的 systemd 服务,用于在置备过程中使用 Ironic 信息自动替换 BAREMETALHOST_UUIDnode-name

    • storage 块,其中包含用于安装 MetalLBendpoint-copier-operator 的 Helm chart。

    • metalLB 自定义资源文件,其中包含要使用的 IPaddressPoolL2Advertisement(请将 ${EDGE_VIP_ADDRESS} 替换为 VIP 地址)。

    • 用于配置 kubernetes-vip 服务的 end-svc.yaml 文件,MetalLB 使用该服务来管理 VIP 地址。

  • 最后一个信息块包含要使用的 Kubernetes 版本。${RKE2_VERSION} 是要使用的 RKE2 版本,请替换此值(例如替换为 v1.28.9+rke2r1)。

apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: RKE2ControlPlane
metadata:
  name: multinode-cluster
  namespace: default
spec:
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3MachineTemplate
    name: multinode-cluster-controlplane
  replicas: 3
  registrationMethod: "address"
  registrationAddress: ${EDGE_VIP_ADDRESS}
  serverConfig:
    cni: cilium
    tlsSan:
      - ${EDGE_VIP_ADDRESS}
      - https://${EDGE_VIP_ADDRESS}.sslip.io
  agentConfig:
    format: ignition
    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: /var/lib/rancher/rke2/server/manifests/endpoint-copier-operator.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: endpoint-copier-operator
                    namespace: kube-system
                  spec:
                    chart: oci://registry.suse.com/edge/endpoint-copier-operator-chart
                    targetNamespace: endpoint-copier-operator
                    version: 0.2.0
                    createNamespace: true
            - path: /var/lib/rancher/rke2/server/manifests/metallb.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: metallb
                    namespace: kube-system
                  spec:
                    chart: oci://registry.suse.com/edge/metallb-chart
                    targetNamespace: metallb-system
                    version: 0.14.3
                    createNamespace: true

            - path: /var/lib/rancher/rke2/server/manifests/metallb-cr.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: metallb.io/v1beta1
                  kind: IPAddressPool
                  metadata:
                    name: kubernetes-vip-ip-pool
                    namespace: metallb-system
                  spec:
                    addresses:
                      - ${EDGE_VIP_ADDRESS}/32
                    serviceAllocation:
                      priority: 100
                      namespaces:
                        - default
                      serviceSelectors:
                        - matchExpressions:
                          - {key: "serviceType", operator: In, values: [kubernetes-vip]}
                  ---
                  apiVersion: metallb.io/v1beta1
                  kind: L2Advertisement
                  metadata:
                    name: ip-pool-l2-adv
                    namespace: metallb-system
                  spec:
                    ipAddressPools:
                      - kubernetes-vip-ip-pool
            - path: /var/lib/rancher/rke2/server/manifests/endpoint-svc.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: v1
                  kind: Service
                  metadata:
                    name: kubernetes-vip
                    namespace: default
                    labels:
                      serviceType: kubernetes-vip
                  spec:
                    ports:
                    - name: rke2-api
                      port: 9345
                      protocol: TCP
                      targetPort: 9345
                    - name: k8s-api
                      port: 6443
                      protocol: TCP
                      targetPort: 6443
                    type: LoadBalancer
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    version: ${RKE2_VERSION}
    nodeName: "Node-multinode-cluster"

Metal3MachineTemplate 对象指定以下信息:

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
metadata:
  name: multinode-cluster-controlplane
  namespace: default
spec:
  template:
    spec:
      dataTemplate:
        name: multinode-cluster-controlplane-template
      hostSelector:
        matchLabels:
          cluster-role: control-plane
      image:
        checksum: http://imagecache.local:8080/eibimage-slemicro55rt-telco.raw.sha256
        checksumType: sha256
        format: raw
        url: http://imagecache.local:8080/eibimage-slemicro55rt-telco.raw

Metal3DataTemplate 对象指定下游群集的 metaData

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3DataTemplate
metadata:
  name: single-node-cluster-controlplane-template
  namespace: default
spec:
  clusterName: single-node-cluster
  metaData:
    objectNames:
      - key: name
        object: machine
      - key: local-hostname
        object: machine
      - key: local_hostname
        object: machine

通过联接上述块创建该文件后,必须在管理群集中执行以下命令才能开始置备三个新的裸机主机:

$ kubectl apply -f capi-provisioning-example.yaml

31.6 高级网络配置

定向网络置备工作流程允许使用静态 IP、绑定、VLAN 等下游群集网络配置。

以下章节将介绍使用高级网络配置置备下游群集所要执行的附加步骤。

要求

配置

基于以下两个章节的内容登记和置备主机:

需要做出以下更改才能启用高级网络配置:

  • 登记步骤:以下新示例文件中的某个密钥包含有关 networkData(用于配置下游群集的静态 IPVLAN 等设置)的信息

apiVersion: v1
kind: Secret
metadata:
  name: controlplane-0-networkdata
type: Opaque
stringData:
  networkData: |
    interfaces:
    - name: ${CONTROLPLANE_INTERFACE}
      type: ethernet
      state: up
      mtu: 1500
      mac-address: "${CONTROLPLANE_MAC}"
      ipv4:
        address:
        - ip:  "${CONTROLPLANE_IP}"
          prefix-length: "${CONTROLPLANE_PREFIX}"
        enabled: true
        dhcp: false
    - name: floating
      type: vlan
      state: up
      vlan:
        base-iface: ${CONTROLPLANE_INTERFACE}
        id: ${VLAN_ID}
    dns-resolver:
      config:
        server:
        - "${DNS_SERVER}"
    routes:
      config:
      - destination: 0.0.0.0/0
        next-hop-address: "${CONTROLPLANE_GATEWAY}"
        next-hop-interface: ${CONTROLPLANE_INTERFACE}

此文件包含用于配置下游群集的高级网络配置(例如静态 IPVLAN)的、采用 nmstate 格式的 networkData。可以看到,该示例显示了启用采用静态 IP 的接口的配置,以及启用采用基础接口的 VLAN 的配置。可以定义任何其他 nmstate 示例来配置下游群集的网络以适应特定要求。必须将示例中的以下变量替换为实际值:

  • ${CONTROLPLANE1_INTERFACE} — 用于边缘群集的控制平面接口(例如 eth0)。

  • ${CONTROLPLANE1_IP} — 用作边缘群集端点的 IP 地址(必须与 kubeapi-server 端点匹配)。

  • ${CONTROLPLANE1_PREFIX} — 用于边缘群集的 CIDR(例如,如果您要使用 /24 子网掩码,请指定 24;也可以指定 255.255.255.0)。

  • ${CONTROLPLANE1_GATEWAY} — 用于边缘群集的网关(例如 192.168.100.1)。

  • ${CONTROLPLANE1_MAC} — 用于控制平面接口的 MAC 地址(例如 00:0c:29:3e:3e:3e)。

  • ${DNS_SERVER} — 用于边缘群集的 DNS(例如 192.168.100.2)。

  • ${VLAN_ID} — 用于边缘群集的 VLAN ID(例如 100)。

另外,需要在该文件末尾的 BaremetalHost 对象中,使用 preprovisioningNetworkDataName 引用该密钥,以便能够在管理群集中登记。

apiVersion: v1
kind: Secret
metadata:
  name: example-demo-credentials
type: Opaque
data:
  username: ${BMC_USERNAME}
  password: ${BMC_PASSWORD}
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
  name: flexran-demo
  labels:
    cluster-role: control-plane
spec:
  online: true
  bootMACAddress: ${BMC_MAC}
  rootDeviceHints:
    deviceName: /dev/nvme0n1
  bmc:
    address: ${BMC_ADDRESS}
    disableCertificateVerification: true
    credentialsName: example-demo-credentials
  preprovisioningNetworkDataName: controlplane-0-networkdata
注意
注意

如果需要部署多节点群集,必须对其他节点执行相同的过程。

  • 置备步骤:必须去除与网络数据相关的信息块,因为平台会将网络数据配置包含在 controlplane-0-networkdata 密钥中。

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3DataTemplate
metadata:
  name: multinode-cluster-controlplane-template
  namespace: default
spec:
  clusterName: multinode-cluster
  metaData:
    objectNames:
      - key: name
        object: machine
      - key: local-hostname
        object: machine
      - key: local_hostname
        object: machine
注意
注意

目前不支持 Metal3DataTemplatenetworkDataMetal3 IPAM;只有通过静态密钥进行的配置才完全受支持。

31.7 电信功能(DPDK、SR-IOV、CPU 隔离、大页、NUMA 等)

定向网络置备工作流程允许将下游群集中使用的电信功能自动化,以便在这些服务器上运行电信工作负载。

要求

配置

基于以下两个章节的内容登记和置备主机:

本节将介绍以下电信功能:

  • DPDK 和 VF 创建

  • 工作负载使用的 SR-IOV 和 VF 分配

  • CPU 隔离和性能微调

  • 大页配置

  • 内核参数微调

注意
注意

有关电信功能的详细信息,请参见第 30 章 “电信功能配置

启用上述电信功能所要做出的更改都可以在 capi-provisioning-example.yaml 置备文件的 RKE2ControlPlane 块中完成。capi-provisioning-example.yaml 文件中的其余信息与置备相关章节(第 31.4 节 “使用定向网络置备来置备下游群集(单节点)”)中提供的信息相同。

明确地说,为启用电信功能而需要在该块 (RKE2ControlPlane) 中所做的更改如下:

  • 指定 preRKE2Commands,用于在 RKE2 安装过程开始之前执行命令。本例使用 modprobe 命令启用 vfio-pciSR-IOV 内核模块。

  • 指定 ignition 文件 /var/lib/rancher/rke2/server/manifests/configmap-sriov-custom-auto.yaml,用于定义要创建的并向工作负载公开的接口、驱动程序及 VF 数量。

    • 只有 sriov-custom-auto-config 配置映射中的值可以替换为实际值。

      • ${RESOURCE_NAME1} — 用于第一个 PF 接口的资源名称(例如 sriov-resource-du1)。它将添加到前缀 rancher.io 的后面,供工作负载用作标签(例如 rancher.io/sriov-resource-du1)。

      • ${SRIOV-NIC-NAME1} — 要使用的第一个 PF 接口的名称(例如 eth0)。

      • ${PF_NAME1} — 要使用的第一个物理功能 PF 的名称。可以使用此名称生成更复杂的过滤器(例如 eth0#2-5)。

      • ${DRIVER_NAME1} — 用于第一个 VF 接口的驱动程序名称(例如 vfio-pci)。

      • ${NUM_VFS1} — 要为第一个 PF 接口创建的 VF 数量(例如 8)。

  • 提供 /var/sriov-auto-filler.sh,用作高级配置映射 sriov-custom-auto-config 与包含低级硬件信息的 sriovnetworknodepolicy 之间的转换器。创建此脚本的目的是让用户免于提前知道复杂的硬件信息。不需要在此文件中进行更改,但如果我们需要启用 sr-iov 并创建 VF,则应该提供此脚本。

  • 用于启用以下功能的内核参数:

参数

说明

isolcpus

1-30,33-62

隔离核心 1-30 和 33-62。

skew_tick

1

允许内核在隔离的 CPU 之间偏斜计时器中断。

nohz

on

允许内核在系统空闲时在单个 CPU 上运行计时器滴答周期。

nohz_full

1-30,33-62

内核引导参数是当前用于配置完整 dynticks 及 CPU 隔离的主接口。

rcu_nocbs

1-30,33-62

允许内核在系统空闲时在单个 CPU 上运行 RCU 回调。

kthread_cpus

0,31,32,63

允许内核在系统空闲时在单个 CPU 上运行 kthreads。

irqaffinity

0,31,32,63

允许内核在系统空闲时在单个 CPU 上运行中断。

processor.max_cstate

1

防止 CPU 在空闲时进入休眠状态。

intel_idle.max_cstate

0

禁用 intel_idle 驱动程序并允许使用 acpi_idle。

iommu

pt

允许为 dpdk 接口使用 vfio。

intel_iommu

on

允许为 VF 使用 vfio。

hugepagesz

1G

允许将大页的大小设置为 1 G。

hugepages

40

先前定义的大页数量。

default_hugepagesz

1G

用于启用大页的默认值。

  • 以下 systemd 服务用于启用下述功能:

    • rke2-preinstall.service,用于在置备过程中使用 Ironic 信息自动替换 BAREMETALHOST_UUIDnode-name

    • cpu-performance.service,用于启用 CPU 性能微调。必须将 ${CPU_FREQUENCY} 替换为实际值(例如,替换为 2500000 会将 CPU 频率设置为 2.5GHz)。

    • cpu-partitioning.service,用于启用 CPU 核心隔离(例如 1-30,33-62)。

    • sriov-custom-auto-vfs.service,用于安装 sriov Helm chart,等待创建自定义资源并运行 /var/sriov-auto-filler.sh,以替换配置映射 sriov-custom-auto-config 中的值并创建工作负载要使用的 sriovnetworknodepolicy

  • ${RKE2_VERSION} 是要使用的 RKE2 版本,请替换此值(例如替换为 v1.28.9+rke2r1)。

做出上述所有更改后,capi-provisioning-example.yaml 中的 RKE2ControlPlane 块如下所示:

apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
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
  serverConfig:
    cni: cilium
    cniMultusEnable: true
  preRKE2Commands:
    - modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
  agentConfig:
    format: ignition
    additionalUserData:
      config: |
        variant: fcos
        version: 1.4.0
        storage:
          files:
            - path: /var/lib/rancher/rke2/server/manifests/configmap-sriov-custom-auto.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: v1
                  kind: ConfigMap
                  metadata:
                    name: sriov-custom-auto-config
                    namespace: kube-system
                  data:
                    config.json: |
                      [
                         {
                           "resourceName": "${RESOURCE_NAME1}",
                           "interface": "${SRIOV-NIC-NAME1}",
                           "pfname": "${PF_NAME1}",
                           "driver": "${DRIVER_NAME1}",
                           "numVFsToCreate": ${NUM_VFS1}
                         },
                         {
                           "resourceName": "${RESOURCE_NAME2}",
                           "interface": "${SRIOV-NIC-NAME2}",
                           "pfname": "${PF_NAME2}",
                           "driver": "${DRIVER_NAME2}",
                           "numVFsToCreate": ${NUM_VFS2}
                         }
                      ]
              mode: 0644
              user:
                name: root
              group:
                name: root
            - path: /var/lib/rancher/rke2/server/manifests/sriov-crd.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: sriov-crd
                    namespace: kube-system
                  spec:
                    chart: oci://registry.suse.com/edge/sriov-crd-chart
                    targetNamespace: sriov-network-operator
                    version: 1.2.2
                    createNamespace: true
            - path: /var/lib/rancher/rke2/server/manifests/sriov-network-operator.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: sriov-network-operator
                    namespace: kube-system
                  spec:
                    chart: oci://registry.suse.com/edge/sriov-network-operator-chart
                    targetNamespace: sriov-network-operator
                    version: 1.2.2
                    createNamespace: true
            - path: /var/sriov-auto-filler.sh
              overwrite: true
              contents:
                inline: |
                  #!/bin/bash
                  cat <<- EOF > /var/sriov-networkpolicy-template.yaml
                  apiVersion: sriovnetwork.openshift.io/v1
                  kind: SriovNetworkNodePolicy
                  metadata:
                    name: atip-RESOURCENAME
                    namespace: sriov-network-operator
                  spec:
                    nodeSelector:
                      feature.node.kubernetes.io/network-sriov.capable: "true"
                    resourceName: RESOURCENAME
                    deviceType: DRIVER
                    numVfs: NUMVF
                    mtu: 1500
                    nicSelector:
                      pfNames: ["PFNAMES"]
                      deviceID: "DEVICEID"
                      vendor: "VENDOR"
                      rootDevices:
                        - PCIADDRESS
                  EOF

                  export KUBECONFIG=/etc/rancher/rke2/rke2.yaml; export KUBECTL=/var/lib/rancher/rke2/bin/kubectl
                  while [ $(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r '.items[].status.syncStatus') != "Succeeded" ]; do sleep 1; done
                  input=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get cm sriov-custom-auto-config -n kube-system -ojson | jq -r '.data."config.json"')
                  jq -c '.[]' <<< $input | while read i; do
                    interface=$(echo $i | jq -r '.interface')
                    pfname=$(echo $i | jq -r '.pfname')
                    pciaddress=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r ".items[].status.interfaces[]|select(.name==\"$interface\")|.pciAddress")
                    vendor=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r ".items[].status.interfaces[]|select(.name==\"$interface\")|.vendor")
                    deviceid=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r ".items[].status.interfaces[]|select(.name==\"$interface\")|.deviceID")
                    resourceName=$(echo $i | jq -r '.resourceName')
                    driver=$(echo $i | jq -r '.driver')
                    sed -e "s/RESOURCENAME/$resourceName/g" \
                        -e "s/DRIVER/$driver/g" \
                        -e "s/PFNAMES/$pfname/g" \
                        -e "s/VENDOR/$vendor/g" \
                        -e "s/DEVICEID/$deviceid/g" \
                        -e "s/PCIADDRESS/$pciaddress/g" \
                        -e "s/NUMVF/$(echo $i | jq -r '.numVFsToCreate')/g" /var/sriov-networkpolicy-template.yaml > /var/lib/rancher/rke2/server/manifests/$resourceName.yaml
                  done
              mode: 0755
              user:
                name: root
              group:
                name: root
        kernel_arguments:
          should_exist:
            - intel_iommu=on
            - intel_pstate=passive
            - processor.max_cstate=1
            - intel_idle.max_cstate=0
            - iommu=pt
            - mce=off
            - hugepagesz=1G hugepages=40
            - hugepagesz=2M hugepages=0
            - default_hugepagesz=1G
            - kthread_cpus=${NON-ISOLATED_CPU_CORES}
            - irqaffinity=${NON-ISOLATED_CPU_CORES}
            - isolcpus=${ISOLATED_CPU_CORES}
            - nohz_full=${ISOLATED_CPU_CORES}
            - rcu_nocbs=${ISOLATED_CPU_CORES}
            - rcu_nocb_poll
            - nosoftlockup
            - nohz=on
        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
            - name: cpu-performance.service
              enabled: true
              contents: |
                [Unit]
                Description=CPU perfomance
                Wants=network-online.target
                After=network.target network-online.target
                [Service]
                User=root
                Type=forking
                TimeoutStartSec=900
                ExecStart=/bin/sh -c "cpupower frequency-set -g performance; cpupower frequency-set -u ${CPU_FREQUENCY}; cpupower frequency-set -d ${CPU_FREQUENCY}"
                RemainAfterExit=yes
                KillMode=process
                [Install]
                WantedBy=multi-user.target
            - name: cpu-partitioning.service
              enabled: true
              contents: |
                [Unit]
                Description=cpu-partitioning
                Wants=network-online.target
                After=network.target network-online.target
                [Service]
                Type=oneshot
                User=root
                ExecStart=/bin/sh -c "echo isolated_cores=${ISOLATED_CPU_CORES} > /etc/tuned/cpu-partitioning-variables.conf"
                ExecStartPost=/bin/sh -c "tuned-adm profile cpu-partitioning"
                ExecStartPost=/bin/sh -c "systemctl enable tuned.service"
                [Install]
                WantedBy=multi-user.target
            - name: sriov-custom-auto-vfs.service
              enabled: true
              contents: |
                [Unit]
                Description=SRIOV Custom Auto VF Creation
                Wants=network-online.target  rke2-server.target
                After=network.target network-online.target rke2-server.target
                [Service]
                User=root
                Type=forking
                TimeoutStartSec=900
                ExecStart=/bin/sh -c "while ! /var/lib/rancher/rke2/bin/kubectl --kubeconfig=/etc/rancher/rke2/rke2.yaml wait --for condition=ready nodes --all ; do sleep 2 ; done"
                ExecStartPost=/bin/sh -c "while [ $(/var/lib/rancher/rke2/bin/kubectl --kubeconfig=/etc/rancher/rke2/rke2.yaml get sriovnetworknodestates.sriovnetwork.openshift.io --ignore-not-found --no-headers -A | wc -l) -eq 0 ]; do sleep 1; done"
                ExecStartPost=/bin/sh -c "/var/sriov-auto-filler.sh"
                RemainAfterExit=yes
                KillMode=process
                [Install]
                WantedBy=multi-user.target
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    version: ${RKE2_VERSION}
    nodeName: "localhost.localdomain"

通过联接上述块创建该文件后,必须在管理群集中执行以下命令才能开始使用电信功能置备新的下游群集:

$ kubectl apply -f capi-provisioning-example.yaml

31.8 专用注册表

可以配置专用注册表作为工作负载使用的映像的镜像。

为此,我们可以创建密钥,并在其中包含有关下游群集要使用的专用注册表的信息。

apiVersion: v1
kind: Secret
metadata:
  name: private-registry-cert
  namespace: default
data:
  tls.crt: ${TLS_CERTIFICATE}
  tls.key: ${TLS_KEY}
  ca.crt: ${CA_CERTIFICATE}
type: kubernetes.io/tls
---
apiVersion: v1
kind: Secret
metadata:
  name: private-registry-auth
  namespace: default
data:
  username: ${REGISTRY_USERNAME}
  password: ${REGISTRY_PASSWORD}

tls.crttls.keyca.crt 是用于对专用注册表进行身份验证的证书。usernamepassword 是用于对专用注册表进行身份验证的身份凭证。

注意
注意

必须以 base64 格式对 tls.crttls.keyca.crtusernamepassword 进行编码才能在密钥中使用它们。

做出上述所有更改后,capi-provisioning-example.yaml 中的 RKE2ControlPlane 块如下所示:

apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
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
  privateRegistriesConfig:
    mirrors:
      "registry.example.com":
        endpoint:
          - "https://registry.example.com:5000"
    configs:
      "registry.example.com":
        authSecret:
          apiVersion: v1
          kind: Secret
          namespace: default
          name: private-registry-auth
        tls:
          tlsConfigSecret:
            apiVersion: v1
            kind: Secret
            namespace: default
            name: private-registry-cert
  serverConfig:
    cni: cilium
  agentConfig:
    format: ignition
    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
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    version: ${RKE2_VERSION}
    nodeName: "localhost.localdomain"

其中,registry.example.com 是下游群集使用的专用注册表的示例名称,应将其替换为实际值。

31.9 在隔离方案中置备下游群集

定向网络置备工作流程允许在隔离方案中自动置备下游群集。

31.9.1 隔离方案的要求

  1. 使用 EIB 生成的原始映像必须包含用于在隔离方案中运行下游群集的特定容器映像(helm-chart OCI 和容器映像)。有关详细信息,请参见第 31.3 节 “为隔离方案准备下游群集映像”一节。

  2. 如果使用 SR-IOV 或任何其他自定义工作负载,则必须按照有关预加载专用注册表的章节(第 31.3.2.5 节 “预加载包含隔离方案和 SR-IOV 所需映像的专用注册表(可选)”)中所述,在专用注册表中预加载用于运行工作负载的映像。

31.9.2 在隔离方案中登记裸机主机

在管理群集中登记裸机主机的过程与上一节(第 31.4 节 “使用定向网络置备来置备下游群集(单节点)”)中所述的过程相同。

31.9.3 在隔离方案中置备下游群集

需要做出一些重要更改才能在隔离方案中置备下游群集:

  1. capi-provisioning-example.yaml 文件中的 RKE2ControlPlane 块必须包含 spec.agentConfig.airGapped: true 指令。

  2. 必须按照有关专用注册表的章节(第 31.8 节 “专用注册表”)中所述,将专用注册表配置包含在 capi-provisioning-airgap-example.yaml 文件中的 RKE2ControlPlane 块中。

  3. 如果您正在使用 SR-IOV 或任何其他需要安装 helm-chart 的 AdditionalUserData 配置(combustion 脚本),则必须修改配置内容以引用专用注册表,而不是使用公共注册表。

以下示例显示了 capi-provisioning-airgap-example.yaml 文件的 AdditionalUserData 块中的 SR-IOV 配置,以及为了引用专用注册表而需要做出的修改

  • 专用注册表密钥引用

  • 在 Helm-Chart 定义中使用专用注册表而不是公共 OCI 映像。

# secret to include the private registry certificates
apiVersion: v1
kind: Secret
metadata:
  name: private-registry-cert
  namespace: default
data:
  tls.crt: ${TLS_BASE64_CERT}
  tls.key: ${TLS_BASE64_KEY}
  ca.crt: ${CA_BASE64_CERT}
type: kubernetes.io/tls
---
# secret to include the private registry auth credentials
apiVersion: v1
kind: Secret
metadata:
  name: private-registry-auth
  namespace: default
data:
  username: ${REGISTRY_USERNAME}
  password: ${REGISTRY_PASSWORD}
---
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
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
  privateRegistriesConfig:       # Private registry configuration to add your own mirror and credentials
    mirrors:
      docker.io:
        endpoint:
          - "https://$(PRIVATE_REGISTRY_URL)"
    configs:
      "192.168.100.22:5000":
        authSecret:
          apiVersion: v1
          kind: Secret
          namespace: default
          name: private-registry-auth
        tls:
          tlsConfigSecret:
            apiVersion: v1
            kind: Secret
            namespace: default
            name: private-registry-cert
          insecureSkipVerify: false
  serverConfig:
    cni: cilium
    cniMultusEnable: true
  preRKE2Commands:
    - modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
  agentConfig:
    airGapped: true       # Airgap true to enable airgap mode
    format: ignition
    additionalUserData:
      config: |
        variant: fcos
        version: 1.4.0
        storage:
          files:
            - path: /var/lib/rancher/rke2/server/manifests/configmap-sriov-custom-auto.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: v1
                  kind: ConfigMap
                  metadata:
                    name: sriov-custom-auto-config
                    namespace: sriov-network-operator
                  data:
                    config.json: |
                      [
                         {
                           "resourceName": "${RESOURCE_NAME1}",
                           "interface": "${SRIOV-NIC-NAME1}",
                           "pfname": "${PF_NAME1}",
                           "driver": "${DRIVER_NAME1}",
                           "numVFsToCreate": ${NUM_VFS1}
                         },
                         {
                           "resourceName": "${RESOURCE_NAME2}",
                           "interface": "${SRIOV-NIC-NAME2}",
                           "pfname": "${PF_NAME2}",
                           "driver": "${DRIVER_NAME2}",
                           "numVFsToCreate": ${NUM_VFS2}
                         }
                      ]
              mode: 0644
              user:
                name: root
              group:
                name: root
            - path: /var/lib/rancher/rke2/server/manifests/sriov.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: v1
                  data:
                    .dockerconfigjson: ${REGISTRY_AUTH_DOCKERCONFIGJSON}
                  kind: Secret
                  metadata:
                    name: privregauth
                    namespace: kube-system
                  type: kubernetes.io/dockerconfigjson
                  ---
                  apiVersion: v1
                  kind: ConfigMap
                  metadata:
                    namespace: kube-system
                    name: example-repo-ca
                  data:
                    ca.crt: |-
                      -----BEGIN CERTIFICATE-----
                      ${CA_BASE64_CERT}
                      -----END CERTIFICATE-----
                  ---
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: sriov-crd
                    namespace: kube-system
                  spec:
                    chart: oci://${PRIVATE_REGISTRY_URL}/sriov-crd
                    dockerRegistrySecret:
                      name: privregauth
                    repoCAConfigMap:
                      name: example-repo-ca
                    createNamespace: true
                    set:
                      global.clusterCIDR: 192.168.0.0/18
                      global.clusterCIDRv4: 192.168.0.0/18
                      global.clusterDNS: 10.96.0.10
                      global.clusterDomain: cluster.local
                      global.rke2DataDir: /var/lib/rancher/rke2
                      global.serviceCIDR: 10.96.0.0/12
                    targetNamespace: sriov-network-operator
                    version: ${SRIOV_CRD_VERSION}
                  ---
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: sriov-network-operator
                    namespace: kube-system
                  spec:
                    chart: oci://${PRIVATE_REGISTRY_URL}/sriov-network-operator
                    dockerRegistrySecret:
                      name: privregauth
                    repoCAConfigMap:
                      name: example-repo-ca
                    createNamespace: true
                    set:
                      global.clusterCIDR: 192.168.0.0/18
                      global.clusterCIDRv4: 192.168.0.0/18
                      global.clusterDNS: 10.96.0.10
                      global.clusterDomain: cluster.local
                      global.rke2DataDir: /var/lib/rancher/rke2
                      global.serviceCIDR: 10.96.0.0/12
                    targetNamespace: sriov-network-operator
                    version: ${SRIOV_OPERATOR_VERSION}
              mode: 0644
              user:
                name: root
              group:
                name: root
            - path: /var/sriov-auto-filler.sh
              overwrite: true
              contents:
                inline: |
                  #!/bin/bash
                  cat <<- EOF > /var/sriov-networkpolicy-template.yaml
                  apiVersion: sriovnetwork.openshift.io/v1
                  kind: SriovNetworkNodePolicy
                  metadata:
                    name: atip-RESOURCENAME
                    namespace: sriov-network-operator
                  spec:
                    nodeSelector:
                      feature.node.kubernetes.io/network-sriov.capable: "true"
                    resourceName: RESOURCENAME
                    deviceType: DRIVER
                    numVfs: NUMVF
                    mtu: 1500
                    nicSelector:
                      pfNames: ["PFNAMES"]
                      deviceID: "DEVICEID"
                      vendor: "VENDOR"
                      rootDevices:
                        - PCIADDRESS
                  EOF

                  export KUBECONFIG=/etc/rancher/rke2/rke2.yaml; export KUBECTL=/var/lib/rancher/rke2/bin/kubectl
                  while [ $(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r '.items[].status.syncStatus') != "Succeeded" ]; do sleep 1; done
                  input=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get cm sriov-custom-auto-config -n sriov-network-operator -ojson | jq -r '.data."config.json"')
                  jq -c '.[]' <<< $input | while read i; do
                    interface=$(echo $i | jq -r '.interface')
                    pfname=$(echo $i | jq -r '.pfname')
                    pciaddress=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r ".items[].status.interfaces[]|select(.name==\"$interface\")|.pciAddress")
                    vendor=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r ".items[].status.interfaces[]|select(.name==\"$interface\")|.vendor")
                    deviceid=$(${KUBECTL} --kubeconfig=${KUBECONFIG} get sriovnetworknodestates.sriovnetwork.openshift.io -n sriov-network-operator -ojson | jq -r ".items[].status.interfaces[]|select(.name==\"$interface\")|.deviceID")
                    resourceName=$(echo $i | jq -r '.resourceName')
                    driver=$(echo $i | jq -r '.driver')
                    sed -e "s/RESOURCENAME/$resourceName/g" \
                        -e "s/DRIVER/$driver/g" \
                        -e "s/PFNAMES/$pfname/g" \
                        -e "s/VENDOR/$vendor/g" \
                        -e "s/DEVICEID/$deviceid/g" \
                        -e "s/PCIADDRESS/$pciaddress/g" \
                        -e "s/NUMVF/$(echo $i | jq -r '.numVFsToCreate')/g" /var/sriov-networkpolicy-template.yaml > /var/lib/rancher/rke2/server/manifests/$resourceName.yaml
                  done
              mode: 0755
              user:
                name: root
              group:
                name: root
        kernel_arguments:
          should_exist:
            - intel_iommu=on
            - intel_pstate=passive
            - processor.max_cstate=1
            - intel_idle.max_cstate=0
            - iommu=pt
            - mce=off
            - hugepagesz=1G hugepages=40
            - hugepagesz=2M hugepages=0
            - default_hugepagesz=1G
            - kthread_cpus=${NON-ISOLATED_CPU_CORES}
            - irqaffinity=${NON-ISOLATED_CPU_CORES}
            - isolcpus=${ISOLATED_CPU_CORES}
            - nohz_full=${ISOLATED_CPU_CORES}
            - rcu_nocbs=${ISOLATED_CPU_CORES}
            - rcu_nocb_poll
            - nosoftlockup
            - nohz=on
        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
            - name: cpu-partitioning.service
              enabled: true
              contents: |
                [Unit]
                Description=cpu-partitioning
                Wants=network-online.target
                After=network.target network-online.target
                [Service]
                Type=oneshot
                User=root
                ExecStart=/bin/sh -c "echo isolated_cores=${ISOLATED_CPU_CORES} > /etc/tuned/cpu-partitioning-variables.conf"
                ExecStartPost=/bin/sh -c "tuned-adm profile cpu-partitioning"
                ExecStartPost=/bin/sh -c "systemctl enable tuned.service"
                [Install]
                WantedBy=multi-user.target
            - name: sriov-custom-auto-vfs.service
              enabled: true
              contents: |
                [Unit]
                Description=SRIOV Custom Auto VF Creation
                Wants=network-online.target  rke2-server.target
                After=network.target network-online.target rke2-server.target
                [Service]
                User=root
                Type=forking
                TimeoutStartSec=900
                ExecStart=/bin/sh -c "while ! /var/lib/rancher/rke2/bin/kubectl --kubeconfig=/etc/rancher/rke2/rke2.yaml wait --for condition=ready nodes --all ; do sleep 2 ; done"
                ExecStartPost=/bin/sh -c "while [ $(/var/lib/rancher/rke2/bin/kubectl --kubeconfig=/etc/rancher/rke2/rke2.yaml get sriovnetworknodestates.sriovnetwork.openshift.io --ignore-not-found --no-headers -A | wc -l) -eq 0 ]; do sleep 1; done"
                ExecStartPost=/bin/sh -c "/var/sriov-auto-filler.sh"
                RemainAfterExit=yes
                KillMode=process
                [Install]
                WantedBy=multi-user.target
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    version: ${RKE2_VERSION}
    nodeName: "localhost.localdomain"

32 生命周期操作

本章介绍已部署的 ATIP 群集的生命周期管理操作。

32.1 管理群集升级

管理群集的升级涉及到多个组件。有关需要升级的常规组件的列表,请参见 Day 2 管理群集(第 24 章 “管理群集)文档。

下面介绍了特定于此设置的组件的升级过程。

升级 Metal3

要升级 Metal3,请使用以下命令更新 Helm 储存库缓存,并从 Helm chart 储存库提取用于安装 Metal3 的最新 chart:

helm repo update
helm fetch suse-edge/metal3

然后,最简单的升级方式是将当前配置导出到某个文件,然后使用该文件升级 Metal3 版本。如果需要对新版本进行任何更改,可以先编辑该文件,然后再升级。

helm get values metal3 -n metal3-system -o yaml > metal3-values.yaml
helm upgrade metal3 suse-edge/metal3 \
  --namespace metal3-system \
  -f metal3-values.yaml \
  --version=0.7.1

32.2 下游群集升级

升级下游群集涉及到更新多个组件。以下章节介绍了每个组件的升级过程。

升级操作系统

对于此过程,请参考此章节来构建包含新操作系统版本的新映像。使用 EIB 生成此新映像后,下一置备阶段将使用提供的新操作系统版本。下一步骤将使用新映像来升级节点。

升级 RKE2 群集

需要做出以下更改才能使用自动化工作流程升级 RKE2 群集:

  • 按照此章节中所示更改 capi-provisioning-example.yaml 中的 RKE2ControlPlane 块:

    • 在规范文件中添加部署策略。

    • RKE2 群集的版本更改为新版本(请替换以下代码中的 ${RKE2_NEW_VERSION})。

apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
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
  serverConfig:
    cni: cilium
  rolloutStrategy:
    rollingUpdate:
      maxSurge: 0
  agentConfig:
    format: ignition
    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
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    version: ${RKE2_NEW_VERSION}
    nodeName: "localhost.localdomain"
  • 按照此章节中所示更改 capi-provisioning-example.yaml 中的 Metal3MachineTemplate 块:

    • 将映像名称与校验和更改为在上一步骤中生成的新版本。

    • 将指令 nodeReuse 设置为 true,以避免创建新节点。

    • 将指令 automatedCleaningMode 设置为 metadata,以启用节点自动清理。

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
metadata:
  name: single-node-cluster-controlplane
  namespace: default
spec:
  nodeReuse: True
  template:
    spec:
      automatedCleaningMode: metadata
      dataTemplate:
        name: single-node-cluster-controlplane-template
      hostSelector:
        matchLabels:
          cluster-role: control-plane
      image:
        checksum: http://imagecache.local:8080/${NEW_IMAGE_GENERATED}.sha256
        checksumType: sha256
        format: raw
        url: http://imagecache.local:8080/${NEW_IMAGE_GENERATED}.raw

完成这些更改后,可以使用以下命令将 capi-provisioning-example.yaml 文件应用于群集:

kubectl apply -f capi-provisioning-example.yaml

第 VII 部分 附录

  • 33 发行说明
  • SUSE Edge 3.0 是紧密集成且经过全面验证的端到端解决方案,用于解决在边缘处部署基础架构和云原生应用程序时存在的独特挑战。其核心作用是提供一个有主见但高度灵活、高度可缩放且安全的平台,涵盖初始部署映像的构建、节点置备和初始配置、应用程序部署、可观测性和生命周期管理。

33 发行说明

33.1 摘要

SUSE Edge 3.0 是紧密集成且经过全面验证的端到端解决方案,用于解决在边缘处部署基础架构和云原生应用程序时存在的独特挑战。其核心作用是提供一个有主见但高度灵活、高度可缩放且安全的平台,涵盖初始部署映像的构建、节点置备和初始配置、应用程序部署、可观测性和生命周期管理。

该解决方案的设计考虑到了客户的需求和期望千差万别,因此不存在“以一应百”的边缘平台。边缘部署促使我们解决并不断设想出一些极具挑战性的问题,包括大规模可伸缩性、网络受限情况下的可用性、物理空间限制、新的安全威胁和攻击途径、硬件体系结构和系统资源的差异、部署旧式基础架构和应用程序并与之连接的要求,以及使用寿命较长的客户解决方案。

SUSE Edge 一开始就构建于同类最佳的开源软件基础之上,与我们 30 年来提供安全、稳定且经认证的 SUSE Linux 平台的历史,以及通过 Rancher 产品组合提供高度可缩放且功能丰富的 Kubernetes 管理经验相一致。SUSE Edge 是基于这些功能构建的,可以提供满足众多细分市场需求的功能,包括零售、医疗、交通、物流、电信、智能制造和工业物联网。

注意
注意

SUSE 自适应电信基础架构平台 (ATIP) 是 SUSE Edge 的衍生产品(或下游产品),它进一步经过优化并包含更多组件,使平台能够解决电信用例的要求。除非明确说明,否则所有发行说明都适用于 SUSE Edge 3.0 和 SUSE ATIP 3.0。

33.2 简介

除非明确指定和说明,否则下面的发行说明在所有体系结构中都是相同的,并且最新版本以及所有其他 SUSE 产品的发行说明始终在 https://www.suse.com/releasenotes 上在线提供。

说明项只会列出一次,但是,非常重要并且属于多个章节的说明项可能会在多处提到。发行说明通常只会列出两个后续版本之间发生的更改。本发行说明可能重复了旧产品版本的发行说明中的某些重要说明项。为了方便识别这些说明项,发行说明中会通过一条备注来指出这一点。

但是,重复的说明项只是出于便利而提供的。因此,如果您跳过了一个或多个版本,另请查看已跳过的版本的发行说明。如果您只阅读当前版本的发行说明,可能会疏忽对系统行为造成影响的重要更改。

33.3 版本 3.0.0

发布日期:2024 年 4 月 26 日

摘要:SUSE Edge 3.0.0 是 SUSE Edge 3.0 产品组合中的第一个版本。

33.3.1 新功能

  • 不适用 - 这是 3.0.z 随附的第一个版本。

33.3.2 Bug 和安全修复

  • 不适用 - 这是 3.0.z 随附的第一个版本。

33.3.3 组件版本

下表描述了构成 3.0.0 版本的各个组件,包括版本、Helm chart 版本(如果适用),以及可从中提取二进制格式的已发布项目的位置。有关用法和部署示例,请参见相关文档。

名称

版本

Helm Chart 版本

项目位置(URL/映像)

SLE Micro

5.5(最新)

不适用

SLE Micro 下载页面
SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso (sha256 4f672a4a0f8ec421e7c25797def05598037c56b7f306283566a9f921bdce904a)
SLE-Micro.x86_64-5.5.0-Default-RT-SelfInstall-GM2.install.iso (sha256 527a5a7cdbf11e3e6238e386533755257676ad8b4c80be3b159d0904cb637678)
SLE-Micro.x86_64-5.5.0-Default-GM.raw.xz (sha256 13243a737ca219bad6a7aa41fa747c06e8b825fef10a756cf4d575f4493ed68b)
SLE-Micro.x86_64-5.5.0-Default-RT-GM.raw.xz (sha256 6c2af94e7ac785c8f6a276032c8e6a4b493c294e6cd72809c75089522f01bc93)

SUSE Manager

4.3.11

不适用

SUSE Manager 下载页面

K3s

1.28.8

不适用

上游 K3s 版本

RKE2

1.28.8

不适用

上游 RKE2 版本

Rancher Prime

2.8.3

2.8.3

Rancher 2.8.3 映像
Rancher Prime Helm 储存库

Longhorn

1.6.1

103.3.0

Longhorn 1.6.1 映像
Longhorn Helm 储存库

NM Configurator

0.2.3

不适用

NMConfigurator 上游版本

NeuVector

5.3.0

103.0.3

registry.suse.com/rancher/mirrored-neuvector-controller:5.3.0
registry.suse.com/rancher/mirrored-neuvector-enforcer:5.3.0
registry.suse.com/rancher/mirrored-neuvector-manager:5.3.0
registry.suse.com/rancher/mirrored-neuvector-prometheus-exporter:5.3.0
registry.suse.com/rancher mirrored-neuvector-registry-adapter:0.1.1-s1
registry.suse.com/rancher/mirrored-neuvector-scanner:latest
registry.suse.com/rancher/mirrored-neuvector-updater:latest

群集 API (CAPI)

1.6.2

不适用

registry.suse.com/edge/cluster-api-controller:1.6.2
registry.suse.com/edge/cluster-api-provider-metal3:1.6.0
registry.suse.com/edge/cluster-api-provider-rke2-bootstrap:0.2.6

Metal3

1.16.0

0.6.5

registry.suse.com/edge/metal3-chart:0.6.5
registry.suse.com/edge/baremetal-operator:0.5.1
registry.suse.com/edge/cluster-api-provider-rke2-controlplane:0.2.6
registry.suse.com/edge/ip-address-manager:1.6.0
registry.suse.com/edge/ironic:23.0.1.2
registry.suse.com/edge/ironic-ipa-downloader:1.3.1
registry.suse.com/edge/kube-rbac-proxy:v0.14.2
registry.suse.com/edge/mariadb:10.6.15.1

MetalLB

0.14.3

0.14.3

registry.suse.com/edge/metallb-chart:0.14.3
registry.suse.com/edge/metallb-controller:v0.14.3
registry.suse.com/edge/metallb-speaker:v0.14.3
registry.suse.com/edge/frr:8.4
registry.suse.com/edge/frr-k8s:v0.0.8

Elemental

1.4.3

103.1.0

registry.suse.com/rancher/elemental-operator-chart:1.4.3
registry.suse.com/rancher/elemental-operator-crds-chart:1.4.3
registry.suse.com/rancher/elemental-operator:1.4.3

Edge Image Builder

1.0.1

不适用

registry.suse.com/edge/edge-image-builder:1.0.1

KubeVirt

1.1.1

0.2.4

registry.suse.com/edge/kubevirt-chart:0.2.4
registry.suse.com/suse/sles/15.5/virt-operator:1.1.1
registry.suse.com/suse/sles/15.5/virt-api:1.1.1
registry.suse.com/suse/sles/15.5/virt-controller:1.1.1
registry.suse.com/suse/sles/15.5/virt-exportproxy:1.1.1
registry.suse.com/suse/sles/15.5/virt-exportserver:1.1.1
registry.suse.com/suse/sles/15.5/virt-handler:1.1.1
registry.suse.com/suse/sles/15.5/virt-launcher:1.1.1

KubeVirt 仪表板扩展

1.0.0

1.0.0

registry.suse.com/edge/kubevirt-dashboard-extension-chart:1.0.0

Containerized Data Importer

1.58.0

0.2.3

registry.suse.com/edge/cdi-chart:0.2.3
registry.suse.com/suse/sles/15.5/cdi-operator:1.58.0
registry.suse.com/suse/sles/15.5/cdi-controller:1.58.0
registry.suse.com/suse/sles/15.5/cdi-importer:1.58.0
registry.suse.com/suse/sles/15.5/cdi-cloner:1.58.0
registry.suse.com/suse/sles/15.5/cdi-apiserver:1.58.0
registry.suse.com/suse/sles/15.5/cdi-uploadserver:1.58.0
registry.suse.com/suse/sles/15.5/cdi-uploadproxy:1.58.0

Endpoint Copier Operator

0.2.0

0.2.0

registry.suse.com/edge/endpoint-copier-operator:v0.2.0
registry.suse.com/edge/endpoint-copier-operator-chart:0.2.0

Akri(技术预览)

0.12.20

0.12.20

registry.suse.com/edge/akri-chart:0.12.20
registry.suse.com/edge/akri-dashboard-extension-chart:1.0.0
registry.suse.com/edge/akri-agent:v0.12.20
registry.suse.com/edge/akri-controller:v0.12.20
registry.suse.com/edge/akri-debug-echo-discovery-handler:v0.12.20
registry.suse.com/edge/akri-onvif-discovery-handler:v0.12.20
registry.suse.com/edge/akri-opcua-discovery-handler:v0.12.20
registry.suse.com/edge/akri-udev-discovery-handler:v0.12.20
registry.suse.com/edge/akri-webhook-configuration:v0.12.20

注意
注意

各个 SUSE Edge z-stream 版本紧密集成,并已作为版本受控的堆栈进行全面测试。将任何一个组件升级到其他版本(而不是上面列出的版本)都可能会导致系统停机。虽然可以在未经测试的配置中运行 Edge 群集,但我们不建议这样做,而且这样可能需要花费更长的时间来通过支持渠道获得问题的解决方法。

33.4 版本 3.0.1

发布日期:2024 年 6 月 14 日

摘要:SUSE Edge 3.0.1 是 SUSE Edge 3.0 产品组合中的第一个 z-stream 版本。

33.4.1 新功能

  • Elemental 和 EIB 现在支持对不受管主机执行节点重置

  • 现已包含 SR-IOV 网络运营商 chart

  • Metal3 chart 现在支持提供额外的可信 CA 证书

  • NM Configurator 现在支持在不指定任何 MAC 的情况下应用统一配置

  • 为 EIB 添加了 version 子命令;版本还会自动包含在 EIB 构建的每个映像中

33.4.2 Bug 和安全修复

33.4.3 组件版本

下表描述了构成 3.0.1 版本的各个组件,包括版本、Helm chart 版本(如果适用),以及可从中提取二进制格式的已发布项目的位置。有关用法和部署示例,请参见相关文档。

名称

版本

Helm Chart 版本

项目位置(URL/映像)

SLE Micro

5.5(最新)

不适用

SLE Micro 下载页面
SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM2.install.iso (sha256 4f672a4a0f8ec421e7c25797def05598037c56b7f306283566a9f921bdce904a)
SLE-Micro.x86_64-5.5.0-Default-RT-SelfInstall-GM2.install.iso (sha256 527a5a7cdbf11e3e6238e386533755257676ad8b4c80be3b159d0904cb637678)
SLE-Micro.x86_64-5.5.0-Default-GM.raw.xz (sha256 13243a737ca219bad6a7aa41fa747c06e8b825fef10a756cf4d575f4493ed68b)
SLE-Micro.x86_64-5.5.0-Default-RT-GM.raw.xz (sha256 6c2af94e7ac785c8f6a276032c8e6a4b493c294e6cd72809c75089522f01bc93)

SUSE Manager

4.3.11

不适用

SUSE Manager 下载页面

K3s

1.28.9

不适用

上游 K3s 版本

RKE2

1.28.9

不适用

上游 RKE2 版本

Rancher Prime

2.8.4

2.8.4

Rancher 2.8.4 映像
Rancher Prime Helm 储存库

Longhorn

1.6.1

103.3.0

Longhorn 1.6.1 映像
Longhorn Helm 储存库

NM Configurator

0.3.0

不适用

NMConfigurator 上游版本

NeuVector

5.3.0

103.0.3

registry.suse.com/rancher/mirrored-neuvector-controller:5.3.0
registry.suse.com/rancher/mirrored-neuvector-enforcer:5.3.0
registry.suse.com/rancher/mirrored-neuvector-manager:5.3.0
registry.suse.com/rancher/mirrored-neuvector-prometheus-exporter:5.3.0
registry.suse.com/rancher mirrored-neuvector-registry-adapter:0.1.1-s1
registry.suse.com/rancher/mirrored-neuvector-scanner:latest
registry.suse.com/rancher/mirrored-neuvector-updater:latest

群集 API (CAPI)

1.6.2

不适用

registry.suse.com/edge/cluster-api-controller:1.6.2
registry.suse.com/edge/cluster-api-provider-metal3:1.6.0
registry.suse.com/edge/cluster-api-provider-rke2-bootstrap:0.2.6

Metal3

1.16.0

0.7.1

registry.suse.com/edge/metal3-chart:0.7.1
registry.suse.com/edge/baremetal-operator:0.5.1
registry.suse.com/edge/cluster-api-provider-rke2-controlplane:0.2.6
registry.suse.com/edge/ip-address-manager:1.6.0
registry.suse.com/edge/ironic:23.0.2.1
registry.suse.com/edge/ironic-ipa-downloader:1.3.2
registry.suse.com/edge/kube-rbac-proxy:v0.14.2 +.1 registry.suse.com/edge/mariadb:10.6.15.1

MetalLB

0.14.3

0.14.3

registry.suse.com/edge/metallb-chart:0.14.3
registry.suse.com/edge/metallb-controller:v0.14.3
registry.suse.com/edge/metallb-speaker:v0.14.3
registry.suse.com/edge/frr:8.4
registry.suse.com/edge/frr-k8s:v0.0.8

Elemental

1.4.4

103.1.0

registry.suse.com/rancher/elemental-operator-chart:1.4.4
registry.suse.com/rancher/elemental-operator-crds-chart:1.4.4
registry.suse.com/rancher/elemental-operator:1.4.4

Edge Image Builder

1.0.2

不适用

registry.suse.com/edge/edge-image-builder:1.0.2

KubeVirt

1.1.1

0.2.4

registry.suse.com/edge/kubevirt-chart:0.2.4
registry.suse.com/suse/sles/15.5/virt-operator:1.1.1
registry.suse.com/suse/sles/15.5/virt-api:1.1.1
registry.suse.com/suse/sles/15.5/virt-controller:1.1.1
registry.suse.com/suse/sles/15.5/virt-exportproxy:1.1.1
registry.suse.com/suse/sles/15.5/virt-exportserver:1.1.1
registry.suse.com/suse/sles/15.5/virt-handler:1.1.1
registry.suse.com/suse/sles/15.5/virt-launcher:1.1.1

KubeVirt 仪表板扩展

1.0.0

1.0.0

registry.suse.com/edge/kubevirt-dashboard-extension-chart:1.0.0

Containerized Data Importer

1.58.0

0.2.3

registry.suse.com/edge/cdi-chart:0.2.3
registry.suse.com/suse/sles/15.5/cdi-operator:1.58.0
registry.suse.com/suse/sles/15.5/cdi-controller:1.58.0
registry.suse.com/suse/sles/15.5/cdi-importer:1.58.0
registry.suse.com/suse/sles/15.5/cdi-cloner:1.58.0
registry.suse.com/suse/sles/15.5/cdi-apiserver:1.58.0
registry.suse.com/suse/sles/15.5/cdi-uploadserver:1.58.0
registry.suse.com/suse/sles/15.5/cdi-uploadproxy:1.58.0

Endpoint Copier Operator

0.2.0

0.2.0

registry.suse.com/edge/endpoint-copier-operator:v0.2.0
registry.suse.com/edge/endpoint-copier-operator-chart:0.2.0

Akri(技术预览)

0.12.20

0.12.20

registry.suse.com/edge/akri-chart:0.12.20
registry.suse.com/edge/akri-dashboard-extension-chart:1.0.0
registry.suse.com/edge/akri-agent:v0.12.20
registry.suse.com/edge/akri-controller:v0.12.20
registry.suse.com/edge/akri-debug-echo-discovery-handler:v0.12.20
registry.suse.com/edge/akri-onvif-discovery-handler:v0.12.20
registry.suse.com/edge/akri-opcua-discovery-handler:v0.12.20
registry.suse.com/edge/akri-udev-discovery-handler:v0.12.20
registry.suse.com/edge/akri-webhook-configuration:v0.12.20

SR-IOV Network Operator

1.2.2

1.2.2+up0.1.0

registry.suse.com/edge/sriov-network-operator-chart:1.2.2
registry.suse.com/edge/sriov-crd-chart:1.2.2

33.5 组件校验

可以使用软件材料清单 (SBOM) 数据来校验上述组件 - 例如,如下所述使用 cosign

SUSE 签名密钥来源下载 SUSE Edge 容器公共密钥:

> cat key.pem
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7N0S2d8LFKW4WU43bq7Z
IZT537xlKe17OQEpYjNrdtqnSwA0/jLtK83m7bTzfYRK4wty/so0g3BGo+x6yDFt
SVXTPBqnYvabU/j7UKaybJtX3jc4SjaezeBqdi96h6yEslvg4VTZDpy6TFP5ZHxZ
A0fX6m5kU2/RYhGXItoeUmL5hZ+APYgYG4/455NBaZT2yOywJ6+1zRgpR0cRAekI
OZXl51k0ebsGV6ui/NGECO6MB5e3arAhszf8eHDE02FeNJw5cimXkgDh/1Lg3KpO
dvUNm0EPWvnkNYeMCKR+687QG0bXqSVyCbY6+HG/HLkeBWkv6Hn41oeTSLrjYVGa
T3zxPVQM726sami6pgZ5vULyOleQuKBZrlFhFLbFyXqv1/DokUqEppm2Y3xZQv77
fMNogapp0qYz+nE3wSK4UHPd9z+2bq5WEkQSalYxadyuqOzxqZgSoCNoX5iIuWte
Zf1RmHjiEndg/2UgxKUysVnyCpiWoGbalM4dnWE24102050Gj6M4B5fe73hbaRlf
NBqP+97uznnRlSl8FizhXzdzJiVPcRav1tDdRUyDE2XkNRXmGfD3aCmILhB27SOA
Lppkouw849PWBt9kDMvzelUYLpINYpHRi2+/eyhHNlufeyJ7e7d6N9VcvjR/6qWG
64iSkcF2DTW61CN5TrCe0k0CAwEAAQ==
-----END PUBLIC KEY-----

校验容器映像哈希,例如,使用 crane 进行校验:

> crane digest registry.suse.com/edge/baremetal-operator:0.5.1
sha256:13e8b2c59aeb503f8adaac095495007071559c9d6d8ef5a7cb1ce6fd1430c782

使用 cosign 进行校验:

> cosign verify-attestation --type spdxjson --key key.pem registry.suse.com/edge/baremetal-operator@sha256:13e8b2c59aeb503f8adaac095495007071559c9d6d8ef5a7cb1ce6fd1430c782 > /dev/null
#
Verification for registry.suse.com/edge/baremetal-operator@sha256:13e8b2c59aeb503f8adaac095495007071559c9d6d8ef5a7cb1ce6fd1430c782 --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The claims were present in the transparency log
  - The signatures were integrated into the transparency log when the certificate was valid
  - The signatures were verified against the specified public key

按照上游文档中所述提取 SBOM 数据:

> cosign verify-attestation --type spdxjson --key key.pem registry.suse.com/edge/baremetal-operator@sha256:13e8b2c59aeb503f8adaac095495007071559c9d6d8ef5a7cb1ce6fd1430c782 | jq '.payload | @base64d | fromjson | .predicate'

33.6 升级步骤

有关如何升级到新 z-stream 版本的细节,请参见 Day 2 文档。

33.7 已知限制

除非另有说明,否则下述限制适用于 3.0.0 版本和所有后续 z-stream 版本。

  • Akri 的第一个版本是作为技术预览产品发布的,不涵盖在标准支持范围内。

  • SUSE Edge 中使用的 Rancher UI 扩展目前无法通过 Rancher 商城部署,必须手动部署。Rancher 问题 #29105

  • 如果您使用的是 NVIDIA GPU,则由于缺少 SELinux 策略,无法在 containerd 层启用 SELinux。Bugzilla #1222725

  • 如果使用 Metal3 和群集 API (CAPI) 进行部署,则安装后不会自动将群集导入 Rancher。此问题在将来的版本中会得到解决。

33.8 产品支持生命周期

SUSE Edge 享有 SUSE 有口皆碑的支持。SUSE 是广受认可的技术领导者,其在提供企业级支持服务方面拥有经受考验的历史。有关详细信息,请参见 https://www.suse.com/lifecycle 和支持策略页面 (https://www.suse.com/support/policy.html)。如果您在提交支持案例、SUSE 如何划分严重性级别或支持范围方面有任何疑问,请参见技术支持手册 (https://www.suse.com/support/handbook/)。

在本文档发布时,SUSE Edge 的每个次要版本(例如“3.0”)提供 12 个月的生产支持,最初 6 个月提供“全面支持”,随后 6 个月提供“维护支持”。在“全面支持”涵盖期间,SUSE 可能会引入新功能(但不会破坏现有功能)、引入 bug 修复及提供安全补丁。在“维护支持”涵盖期间,只会引入关键的安全修复和 bug 修复,其他修复由我们自行决定是否提供。

除非明确说明,否则列出的所有组件均被视为正式发布 (GA),并涵盖在 SUSE 的标准支持范围内。某些组件可能以“技术预览”版本的形式列出,SUSE 通过此类版本让客户提前体验尚未正式发布的特性和功能以进行评估,但这些组件没有标准支持政策的保障,不建议将其用于生产用例。SUSE 非常欢迎各位对技术预览组件的改进提供反馈和建议,但如果技术预览功能无法满足客户的需求或者达不到我们要求的成熟度,SUSE 保留在正式发布之前弃用该功能的权利。

请注意,SUSE 必须偶尔弃用功能或更改 API 规范。弃用功能或更改 API 的原因包括相应功能已更新或由新的实现取代、有新的功能集、上游技术不再可用,或者上游社区引入了不兼容的更改。在给定的次要版本 (x.z) 中,这种情况预期永远不会发生,因此所有 z-stream 版本都将保持 API 兼容性和原有功能。SUSE 将努力在发行说明中提供弃用警告并发出充足的通告,同时提供解决方法、建议和缓解措施,以最大程度地减少服务中断。

SUSE Edge 团队也欢迎社区提出反馈,你们可以在 https://www.github.com/suse-edge 中的相应代码储存库内提出问题。

33.9 获取源代码

本 SUSE 产品包含根据 GNU 通用公共许可证 (GPL) 和其他各种开源许可证授权给 SUSE 的材料。GPL 要求 SUSE 提供与 GPL 授权材料对应的源代码,而 SUSE 必须遵守其他所有开源许可要求。因此,SUSE 将提供所有源代码,一般情况下,这些源代码可以在相关组件的 SUSE Edge GitHub 储存库 (https://www.github.com/suse-edge) 和 SUSE Rancher GitHub 储存库 (https://www.github.com/rancher) 中找到,具体对于 SLE Micro 而言,这些源代码可以在 https://www.suse.com/download/sle-micro 上的“Medium 2”中下载。