|Index|SUSE Edge 文档|快速入门|使用 Edge Image Builder 的独立集群
适用范围 SUSE Edge 3.6

2 使用 Edge Image Builder 的独立集群

Edge Image Builder (EIB) 是一款简化了为引导机器生成定制化、即开即用 (CRB) 磁盘镜像流程的工具,即使在完全隔离的环境中也能使用。EIB 用于为所有三种 SUSE Edge 部署足迹创建部署镜像,因为它足够灵活,既能提供最小化的自定义(例如添加用户或设置时区),也能提供全面配置的镜像(例如设置复杂的网络配置、部署多节点 Kubernetes 集群、部署客户工作负载,以及通过 Rancher/Elemental 和 SUSE Multi-Linux Manager 注册到集中式管理平台)。EIB 作为容器镜像运行,使其在不同平台间具有极高的可移植性,并确保所有必需的依赖项都是自包含的,对用于操作该工具的系统所安装的软件包影响极小。

注意
注意

对于多节点场景,EIB 会自动部署 MetalLB 和 Endpoint Copier Operator,以便使用相同构建镜像配置的主机能够自动加入 Kubernetes 集群。

有关更多信息,请阅读 Edge Image Builder 简介 (第 8 章 “Edge Image Builder”)。

警告
警告

Edge Image Builder 1.3.3.1 支持自定义 SUSE Linux Micro 6.2 镜像。 不支持较旧的版本,例如 SUSE Linux Enterprise Micro 5.5 或 6.0。

2.1 先决条件

注意
注意

对于非生产用途,可以使用 openSUSE Leap 15.6 或 openSUSE Tumbleweed 作为构建主机。 只要有兼容的容器运行时,其他操作系统也可能可以运行。

2.1.1 获取 EIB 镜像

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

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

2.2 创建镜像配置目录

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

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

在上一步中,我们创建了一个“base-images”目录,用于存放 SUSE Linux Micro 6.2 输入镜像,现在让我们确保该镜像已复制到配置目录中:

cp /path/to/SL-Micro.x86_64-6.2-Base-SelfInstall-GM.install.iso $CONFIG_DIR/base-images/slemicro.iso
注意
注意

在 EIB 运行期间,原始基础镜像 不会 被修改;系统会在 EIB 配置目录的根目录下创建一个包含所需配置的新的自定义版本。

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

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

2.3 创建镜像定义文件

定义文件描述了 Edge Image Builder 支持的大多数可配置选项,选项的完整示例可以在 此处 找到,我们建议您查看 上游构建镜像指南,以获取比我们下面要介绍的示例更全面的示例。让我们从一个非常基础的操作系统镜像定义文件开始:

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

此定义指定我们正在为 AMD64/Intel 64 系统生成输出镜像。将用作进一步修改基础的镜像是一个名为 slemicro.iso 的 iso 镜像,预计位于 $CONFIG_DIR/base-images/slemicro.iso。它还概述了在 EIB 完成镜像修改后,输出镜像将被命名为 eib-image.iso,并默认驻留在 $CONFIG_DIR 中。

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

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

在接下来的章节中,我们将介绍几个常见操作的示例:

2.3.1 配置操作系统 (OS)

EIB operatingSystem 部分旨在配置操作系统的安装位置、镜像大小等。 这是一个可选部分,除非应用了一个或多个自定义设置,否则不应包含该部分。

apiVersion: 1.3
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-Base-RT-SelfInstall.iso
operatingSystem:
  isoConfiguration:
    installDevice: /dev/disk/by-id/ata-QEMU_HARDDISK_111-disk1 # first defined disk

特定于类型的配置:根据所自定义镜像的类型,可以包含以下可选部分之一。

  • isoConfiguration - 可选;此部分中的配置仅适用于 ISO 映像。

  • installDevice - 可选;指定应用作安装设备的磁盘。这必须是一个块设备,并且默认会自动擦除磁盘上找到的任何数据。 此外,指定此属性会触发 GRUB 覆盖,以自动安装操作系统,而不是提示用户开始安装,从而实现完全无人值守的自动化安装。如果省略,系统会提示用户从 GRUB 菜单中选择“安装”选项,并要求用户选择安装磁盘,并确认在此过程中将擦除该设备。

    注意
    注意

    installDevice 部分中使用的设备可以指定为 /dev/sda,或者使用 /dev/disk/by-id、/dev/disk/by-path 命名方式,以确保使用正确的设备。 如果使用 libvirt 虚拟机,则可以在为虚拟机创建磁盘时指定 serial 属性值(例如 serial=111-disk1),以便将其用于 installDevice 值,并使用 by-id 命名方式,例如 /dev/disk/by-id/ata-QEMU_HARDDISK_111-disk1(如果使用 ATA 设备,libvirt 会自动为 ATA 设备添加 ata-QEMU_HARDDISK_ 前缀,或为 virtio 设备添加 virtio- 前缀,有关更多信息,请参阅 #17670 virtio issue)。

  • rawConfiguration - 可选;此部分中的配置仅适用于 RAW 镜像。

  • diskSize - 可选;设置所需的原始磁盘镜像大小,EIB 会将生成的镜像调整为此大小。这一点很重要,以确保您的磁盘镜像足够大,能够容纳嵌入镜像中的任何工件。建议将其设置为略小于您的 SD 卡大小(如果直接写入磁盘,则为块设备大小),因为系统会在启动时自动扩展以填满块设备的大小。这是可选的,但强烈建议设置。指定为一个整数,并以“M”(兆字节)、“G”(吉字节)或“T”(太字节)作为后缀(例如)“32G”)。

  • luksKey - 加密镜像必需;用于加密原始镜像的给定 LUKS 密钥,这是 EIB 完成构建过程所必需的。

  • expandEncryptedPartition - 可选;默认禁用,启用后,会自动将加密分区扩展至其最大大小。例如,如果 diskSize 为 25G 且此字段为 true,EIB 将在构建过程中将加密分区扩展至 25G。

2.3.2 配置操作系统用户

EIB 允许您预配置具有登录信息(例如密码或 SSH 密钥)的用户,包括设置固定的 root 密码。作为本示例的一部分,我们将固定 root 密码,第一步是使用 OpenSSL 创建一个单向加密密码:

openssl passwd -6 SecurePassword

这将输出类似以下内容:

$6$G392FCbxVgn[...]Y7zTXnC1

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

apiVersion: 1.3
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$G392FCbxVgn[...]Y7zTXnC1
注意
注意

还可以添加其他用户、创建主目录、设置用户 ID、添加 SSH 密钥认证以及修改组信息。请参阅 上游构建镜像指南 以获取更多示例。

2.3.3 配置操作系统时间

time 部分是可选的,但强烈建议进行配置,以避免证书和时钟偏差带来的潜在问题。EIB 将根据此处的参数配置 chronyd 和 /etc/localtime。

operatingSystem:
  time:
    timezone: Europe/London
    ntp:
      forceWait: true
      pools:
        - 2.suse.pool.ntp.org
      servers:
        - 10.0.0.1
        - 10.0.0.2
  • timezone 以“地区/地点”格式指定时区(例如“欧洲/伦敦”)。可以通过在 Linux 系统上运行 timedatectl list-timezones 来找到完整列表。

  • ntp - 定义与配置 NTP(使用 chronyd)相关的属性:

  • forceWait - 请求 chronyd 在启动其他服务之前尝试同步时间源,超时时间为 180 秒。

  • pools - 指定 chronyd 将用作数据源的池列表(使用 iburst 以缩短初始同步所需的时间)。

  • servers - 指定 chronyd 将用作数据源的服务器列表(使用 iburst 以缩短初始同步所需的时间)。

注意
注意

本示例中提供的值仅供参考。请根据您的具体要求进行调整。

2.3.4 添加证书

存储在 certificates 目录中且扩展名为“.pem”或“.crt”的证书文件将被安装到节点系统范围的证书存储中:

.
├── definition.yaml
└── certificates
    ├── my-ca.pem
    └── my-ca.crt

有关更多信息,请参阅 “使用 TLS 证书保护通信”指南。

2.3.5 添加操作系统文件

放置在镜像配置目录中 os-files 目录下的文件会自动复制到所构建镜像的文件系统中。 复制时将保留完全相同的目录结构。 例如,如果文件存在于名为 os-files/etc 的子目录中,它将被放置在所构建镜像的 /etc 目录中。

注意
注意

如果 os-files 目录存在,它不能为空。

.
├── definition.yaml
└── os-files
    └── etc
        └── ssh
            └── sshd_config

2.3.6 配置 RPM 软件包

EIB 的主要功能之一是提供一种机制,将额外的软件包添加到镜像中,以便在安装完成后,系统能够立即利用已安装的软件包。EIB 允许用户指定以下内容:

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

  • 用于搜索这些软件包的网络存储库

  • 用于搜索官方 SUSE 存储库中列出软件包的 SUSE 客户中心 (SCC) 凭据

  • 通过 $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.3
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$G392FCbxVgn[...]Y7zTXnC1
  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 > $CONFIG_DIR/rpms/gpg-keys/nvidia.gpg
警告
警告

通过此方法添加额外的 RPM 旨在用于添加受支持的第三方组件或用户提供(并维护)的软件包;此机制不应用于添加通常在 SUSE Linux Micro 上不受支持的软件包。如果使用此机制添加来自 openSUSE 存储库(不受支持)的组件(包括来自较新版本或服务包的组件),您最终可能会得到不受支持的配置,特别是当依赖项解析导致操作系统核心部分被替换时,即使生成的系统看起来运行正常。如果您不确定,请联系您的 SUSE 代表,以协助确定您所需配置的可支持性。

注意
注意

更全面的指南及其他示例可以在 上游安装软件包指南 中找到。

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

EIB 的另一个功能是能够使用它来自动化部署“就地引导”(即不需要任何形式的集中式管理基础设施来协调)的单节点和多节点高可用 Kubernetes 集群。这种方法背后的主要驱动因素是针对隔离部署或网络受限环境,但它也可用作快速启动独立集群的一种方式,即使在可以使用完整且不受限制的网络访问的情况下也是如此。

此方法不仅能够部署自定义操作系统,还能够指定 Kubernetes 配置、通过 Helm chart 提供的任何额外分层组件,以及通过提供的 Kubernetes 清单提供的任何用户工作负载。然而,使用此方法背后的设计原则是我们默认假设用户想要进行隔离部署。因此,镜像定义中指定的任何项目都将被拉取到镜像中,其中包括用户提供的工作负载。EIB 确保定义所需的任何已发现镜像都会被复制到本地,并由生成的已部署系统中的嵌入式镜像注册表提供服务。

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

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

最终的完整定义文件现在应如下所示:

apiVersion: 1.3
image:
  imageType: iso
  arch: x86_64
  baseImage: slemicro.iso
  outputImageName: eib-image.iso
operatingSystem:
  users:
    - username: root
      encryptedPassword: $6$G392FCbxVgn[...]Y7zTXnC1
  packages:
    packageList:
      - nvidia-container-toolkit
    additionalRepos:
      - url: https://nvidia.github.io/libnvidia-container/stable/rpm/x86_64
kubernetes:
  version: v1.35.4+k3s1
  manifests:
    urls:
      - https://k8s.io/examples/application/nginx-app.yaml
  helm:
    charts:
      - name: kubevirt
        version: 306.0.2+up0.7.0
        repositoryName: suse-edge
    repositories:
      - name: suse-edge
        url: oci://registry.suse.com/edge/charts
注意
注意

有关多节点部署、自定义网络以及 Helm chart 选项/值的更多示例,请参阅 上游文档。

2.3.8 配置网络

在本快速入门的最后一个示例中,让我们配置当系统使用 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: 192.168.122.1
    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 钩子将通用配置应用于所有节点 - 有关更多详细信息,请参阅 网络指南 (第 9 章 “边缘网络”)。

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

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

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

注意
注意

有关上述配置的更全面解释和此功能的示例,请参阅 边缘网络组件 (第 9 章 “边缘网络”)。

2.4 构建镜像

现在我们已经有了基础镜像和供 EIB 使用的镜像定义,让我们继续构建镜像。为此,我们只需使用 podman 调用带有“build”命令的 EIB 容器,并指定定义文件:

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

命令的输出应类似于:

Setting up Podman API listener...
Downloading file: dl-manifest-1.yaml 100% (498/498 B, 9.5 MB/s)
Pulling selected Helm charts... 100% (1/1, 43 it/min)
Generating image customization components...
Identifier ................... [SUCCESS]
Custom Files ................. [SKIPPED]
Time ......................... [SKIPPED]
Network ...................... [SUCCESS]
Groups ....................... [SKIPPED]
Users ........................ [SUCCESS]
Proxy ........................ [SKIPPED]
Resolving package dependencies...
Rpm .......................... [SUCCESS]
Os Files ..................... [SKIPPED]
Systemd ...................... [SKIPPED]
Fips ......................... [SKIPPED]
Elemental .................... [SKIPPED]
Suma ......................... [SKIPPED]
Populating Embedded Artifact Registry... 100% (3/3, 10 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% (657/657 MB, 48 MB/s)
Downloading file: rke2-images-cilium.linux-amd64.tar.zst 100% (368/368 MB, 48 MB/s)
Downloading file: rke2.linux-amd64.tar.gz 100% (35/35 MB, 50 MB/s)
Downloading file: sha256sum-amd64.txt 100% (4.3/4.3 kB, 6.2 MB/s)
Kubernetes ................... [SUCCESS]
Certificates ................. [SKIPPED]
Cleanup ...................... [SKIPPED]
Building ISO image...
Kernel Params ................ [SKIPPED]
Build complete, the image can be found at: eib-image.iso

构建的 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/ 中创建一个带时间戳的文件夹,其中包含构建日志、构建期间使用的工件,以及包含添加到 CRB 镜像的所有脚本和工件的 combustion 和 artefacts 目录。

此目录的内容应如下所示:

├── 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:<version>-registry.tar.zst
│   │   │   ├── rancher_kubectl:<version>-registry.tar.zst
│   │   │   └── registry.suse.com_suse_sles_15.6_virt-operator:<version>-registry.tar.zst
│   │   │── rpms/
│   │   │   └── rpm-repo
│   │   │       ├── addrepo0
│   │   │       │   ├── nvidia-container-toolkit-<version>.rpm
│   │   │       │   ├── nvidia-container-toolkit-base-<version>.rpm
│   │   │       │   ├── libnvidia-container1-<version>.rpm
│   │   │       │   └── libnvidia-container-tools-<version>.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.yaml
│   ├── createrepo.log
│   ├── eib-build.log
│   ├── embedded-registry.log
│   ├── helm
│   │   └── kubevirt
│   │       └── kubevirt-0.4.0.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. 部署 SUSE Linux Micro 6.2

  2. 配置 root 密码

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

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

  5. 安装单节点 RKE2

  6. 配置静态网络

  7. 安装 KubeVirt

  8. 部署用户提供的清单

2.5 调试镜像构建过程

如果镜像构建过程失败,请参考 上游调试指南。

2.6 测试您新构建的镜像

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