
# CCE中使用x86和ARM双架构镜像
华为云CCE支持x86与ARM节点混部在同一集群。但两种架构的指令集不兼容，导致x86镜像无法在ARM节点上运行，反之ARM镜像无法在x86节点上运行。如果镜像与节点架构不适配，就容易造成工作负载在拥有x86与ARM节点的集群中部署失败。
为解决这一问题，您可以构建x86和ARM双架构镜像，使用同一个镜像地址，Kubelet会根据节点架构自动拉取对应版本的镜像，实现一次配置，全架构运行。
#### 工作原理
双架构镜像的核心原理是利用Docker的Manifest List功能，将一个逻辑镜像名（如defaultbackend:1.5）关联到多个物理镜像（如defaultbackend-linux-amd64:1.5、defaultbackend-linux-arm64:1.5）。这样在描述工作负载时，可以使用同一个镜像地址，且不用配置亲和性，工作负载描述文件更简洁更容易维护。当Pod调度到ARM架构节点时拉取ARM架构的镜像，当Pod调度到x86架构节点时拉取x86架构的镜像。
![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002576186576.png "点击放大")
#### 前提条件
- 使用Docker制作双架构镜像时，Docker客户端版本需要大于18.03。
- 已登录目标SWR镜像仓库，并有推送权限。
 
#### 使用nerdctl构建双架构镜像
使用nerdctl构建双架构镜像使用命令行和Dockerfile构建容器镜像，命令风格与docker兼容。适用于在containerd环境下制作容器镜像。
#### 步骤一：安装nerdctl并启动buildkit
1. 登录已安装containerd的虚拟机。
2. 下载并安装nerdctl。 
   ```
   # 下载nerdctl安装包 
   wget https://github.com/containerd/nerdctl/releases/download/v2.3.1/nerdctl-full-2.3.1-linux-amd64.tar.gz
   # 安装nerdctl命令以及其他依赖
   tar -zxf nerdctl-full-2.3.1-linux-amd64.tar.gz -C /usr/local
   # 启动并运行buildkitd，用以构建镜像
   cp /usr/local/lib/systemd/system/buildkit.service /lib/systemd/system/
   systemctl enable buildkit --now
   ```
   
   
3. 验证是否安装成功。 
   ```
   nerdctl version
   ```
   输出如下：
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002661903971.png)
   
   
 
#### 步骤二：通过QEMU构建模拟架构环境
通过QEMU构建模拟架构环境：
```
nerdctl run –-network none --privileged --rm tonistiigi/binfmt:master --install all
ls -1 /proc/sys/fs/binfmt_misc/qemu*
```
应输出如下内容：
```
/proc/sys/fs/binfmt_misc/qemu-aarch64
/proc/sys/fs/binfmt_misc/qemu-arm
/proc/sys/fs/binfmt_misc/qemu-loongarch64
/proc/sys/fs/binfmt_misc/qemu-mips64
/proc/sys/fs/binfmt_misc/qemu-mips64el
/proc/sys/fs/binfmt_misc/qemu-ppc64le
/proc/sys/fs/binfmt_misc/qemu-riscv64
/proc/sys/fs/binfmt_misc/qemu-s390x
```
#### 步骤三：创建并推送双架构镜像
1. 下载多架构的基础镜像。 
   ```
   nerdctl pull -–platform=amd64,arm64 alpine
   ```
   
   
2. 构建多架构镜像。 
   编写好Dockerfile文件，构建多架构镜像。
   ```
   nerdctl build --platform=amd64,arm64 -t foo:latest ./
   ```
   
   
3. 推送镜像到SWR，上传镜像的具体方法请参见[客户端上传镜像](https://support.huaweicloud.com/usermanual-swr/swr_01_0011.html)。
   
   ```
   # 实际操作中需要替换成实际使用的swr地址及组织名称
   nerdctl login -u xxx -p xxx swr.cn-north-4.myhuaweicloud.com
   nerdctl tag foo:latest swr.cn-north-4.myhuaweicloud.com/test/foo:v1
   nerdctl push --all-platforms swr.cn-north-4.myhuaweicloud.com/test/foo:v1
   ```
   
   
4. 查看已创建的Manifest列表。 
   ```
   nerdctl manifest inspect ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION}
   ```
   
   
 
#### 使用Docker构建双架构镜像
使用命令行和Dockerfile构建容器镜像，需要已经安装好Docker的服务器。
#### 步骤一：开启Docker功能
1. 登录已安装Docker的虚拟机。
2. 开启Docker功能。 
   ```
   # 临时开启（当前终端会话有效）
   export DOCKER_CLI_EXPERIMENTAL=enabled
   ```
   
   
3. 验证是否开启成功。 
   ```
   docker version --format '{{.Client.Experimental}}'
   ```
   应输出true则表示开启成功。
   
   
 
#### 步骤二：构建并上传x86与ARM单体镜像
本示例中已经构建好了defaultbackend-linux-amd64:1.5和defaultbackend-linux-arm64:1.5两个镜像，分别是x86架构和ARM架构。
将它们重命名（打标签） 并推送到SWR仓库，如下所示。上传镜像的具体方法请参见[客户端上传镜像](https://support.huaweicloud.com/usermanual-swr/swr_01_0011.html)。
```
# 定义变量，请替换为你的实际信息
REGISTRY="swr.cn-north-4.myhuaweicloud.com"  # 你的SWR仓库地址
NAMESPACE="test-namespace"                  # 你的SWR组织
IMAGE_NAME="defaultbackend"                 # 镜像名
VERSION="1.5"                               # 版本号
# ---- 处理 AMD64 (x86) 镜像 ----
# 给本地镜像打上SWR的完整标签
docker tag defaultbackend-linux-amd64:${VERSION} ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-amd64:${VERSION}
# 上传
docker push ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-amd64:${VERSION}
# ---- 处理 ARM64 镜像 ----
docker tag defaultbackend-linux-arm64:${VERSION} ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-arm64:${VERSION}
docker push ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-arm64:${VERSION}
```
#### 步骤三：创建并推送Manifest列表
创建双架构Manifest列表并上传，将上面两个镜像关联到一个逻辑镜像名下。
1. 创建Manifest列表。 
   ```
   docker manifest create --amend --insecure \
       ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION} \
       ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-amd64:${VERSION} \
       ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-arm64:${VERSION}
   ```
   - --amend: 如果manifest存在则修改。
   
   - --insecure: 允许与HTTP仓库交互（通常SWR是HTTPS，但保留参数不报错）。
   
   
   
   
2. 为Manifest列表中的每个镜像标注操作系统架构。 
   ```
   docker manifest annotate ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION} \
       ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-amd64:${VERSION} --arch amd64
   docker manifest annotate ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION} \
       ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-arm64:${VERSION} --arch arm64
   ```
   
   
3. 推送Manifest列表到SWR。 
   ```
   docker manifest push -p --insecure ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION}
   ```
   - -p：推送列表本身，而不是镜像内容（内容已在上步推送）。
   
   
   
   
4. 查看已创建的Manifest列表。 
   ```
   docker manifest inspect ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION}
   ```
   
   
 
#### 步骤四：在CCE中使用双架构镜像
完成上述操作后，在CCE中创建工作负载时可以直接使用同一个逻辑镜像地址：
- 当Pod调度到x86架构的节点时，会拉取swr.cn-north-4.myhuaweicloud.com/test-namespace/defaultbackend-linux-amd64:1.5这个镜像。
- 当Pod调度到ARM架构的节点时，会拉取swr.cn-north-4.myhuaweicloud.com/test-namespace/defaultbackend-linux-arm64:1.5这个镜像。
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: defaultbackend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: defaultbackend
  template:
    metadata:
      labels:
        app: defaultbackend
    spec:
      containers:
      # 直接使用双架构镜像地址
      - image: swr.cn-north-4.myhuaweicloud.com/test-namespace/defaultbackend:1.5
        name: nginx
      # 可无需配置 nodeSelector，Kubelet会自动选择正确架构的镜像，但如果需要控制Pod调度到特定架构节点，仍需配合亲和性
      # nodeSelector:      # 可选：若仍想强制调度到某类节点，可添加nodeSelector
      #   kubernetes.io/arch: arm64   # 强制调度到ARM节点
      imagePullSecrets:
      - name: default-secret
```
#### 常见问题
#### 使用双架构镜像后是否还需要配置节点亲和性？
不一定。您可以根据实际需求进行选择。
- 无需配置：如果您的集群既有x86又有ARM节点，且不关心Pod具体跑在哪种架构上，仅需使用双架构镜像，无需任何亲和配置，调度器自动分配，Kubelet自动选镜像。
- 仍需配置：如果您必须让某个工作负载跑在x86节点上（例如某些旧版二进制依赖），则仍需要配置节点亲和性，此时双架构镜像可保证应用在x86节点上能拉取到正确镜像。
 
#### 如何验证镜像是否支持双架构？
您可以使用以下命令进行查询：
```
docker manifest inspect <镜像地址>
```
查看返回的manifests列表中是否包含platform.architecture为amd64和arm64的条目。
