Help Center/ Cloud Container Engine/ Best Practices/ Container/ Using a Dual-Architecture Image (x86 and Arm)
Updated on 2026-08-17 GMT+08:00

Using a Dual-Architecture Image (x86 and Arm)

Huawei Cloud CCE allows x86 and Arm nodes to coexist within the same cluster. However, because the instruction sets of these two architectures are incompatible, x86 images cannot run on Arm nodes, and Arm images cannot run on x86 nodes. If a workload's image does not match the target node's architecture, deployment will fail in heterogeneous clusters.

To address this, you can build a dual-architecture image that supports both x86 and Arm under a single image path. The kubelet automatically pulls the image matching the node's architecture, enabling one-time configuration with full-architecture compatibility.

How It Works

The core mechanism of a dual-architecture image leverages the Docker manifest list. This associates a single logical image name, for example, defaultbackend:1.5 with multiple physical images, such as defaultbackend-linux-amd64:1.5 and defaultbackend-linux-arm64:1.5. When deploying a workload, you specify only one image path without configuring node affinity rules. This simplifies the workload specification and improves maintainability. When a pod is scheduled to an Arm node, the container runtime automatically pulls the Arm image. When scheduled to an x86 node, it pulls the x86 image.

Prerequisites

  • When using Docker to create a dual-architecture image, ensure the Docker client version is later than 18.03.
  • You have logged in to the SWR image repository and have push permissions.

Using nerdctl to Build an Image

Use nerdctl with a Dockerfile to build dual-architecture images from the command line. The CLI syntax is compatible with Docker's. This method is applicable to containerd environments.

Step 1: Install nerdctl and Start BuildKit

  1. Log in to the VM where containerd is installed.
  2. Download and install nerdctl.

    # Download the nerdctl installation package.
    wget https://github.com/containerd/nerdctl/releases/download/v2.3.1/nerdctl-full-2.3.1-linux-amd64.tar.gz
    # Install the nerdctl command and other dependencies.
    tar -zxf nerdctl-full-2.3.1-linux-amd64.tar.gz -C /usr/local
    # Start and run buildkitd to build an image.
    cp /usr/local/lib/systemd/system/buildkit.service /lib/systemd/system/
    systemctl enable buildkit --now

  3. Check whether the installation is successful.

    nerdctl version

    Information similar to the following is displayed:

Step 2: Use QEMU to Build a Simulated Architecture Environment

Use QEMU to build a simulated architecture environment.

nerdctl run –-network none --privileged --rm tonistiigi/binfmt:master --install all
ls -1 /proc/sys/fs/binfmt_misc/qemu* 

The following output should be displayed:

/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

Step 3: Create and Push a Dual-Architecture Image

  1. Download the multi-architecture base image.

    nerdctl pull -–platform=amd64,arm64 alpine

  2. Build a multi-architecture image.

    Write a Dockerfile to build a multi-architecture image.

    nerdctl build --platform=amd64,arm64 -t foo:latest ./

  3. Push the image to SWR. For details, see Pushing an Image.

    # Replace the SWR address and organization name with the actual ones.
    nerdctl login -u xxx -p xxx swr.ap-southeast-1.myhuaweicloud.com
    nerdctl tag foo:latest swr.ap-southeast-1.myhuaweicloud.com/test/foo:v1
    nerdctl push --all-platforms swr.ap-southeast-1.myhuaweicloud.com/test/foo:v1

  4. View the created manifest list.

    nerdctl manifest inspect ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION}

Using Docker to Build Dual-Architecture Images

Use the command line and a Dockerfile to build dual-architecture images. A server with Docker installed is required.

Step 1: Enable Docker

  1. Log in to the VM where Docker is installed.
  2. Enable Docker.

    # Enable Docker temporarily for the current terminal session.
    export DOCKER_CLI_EXPERIMENTAL=enabled

  3. Verify that Docker is enabled.

    docker version --format '{{.Client.Experimental}}' 

    If true is displayed, Docker has been enabled.

Step 2: Build and Upload Single-Architecture Images for x86 and Arm

In this example, defaultbackend-linux-amd64:1.5 and defaultbackend-linux-arm64:1.5 are the x86 and Arm images, respectively.

Tag the images and push them to SWR. For details, see Pushing an Image.

# Define variables. Replace the placeholder values with your actual data.
REGISTRY="swr.ap-southeast-1.myhuaweicloud.com"  # Your SWR repository address
NAMESPACE="test-namespace"                  # Your SWR organization
IMAGE_NAME="defaultbackend"                 # Image name
VERSION="1.5"                               # Version

# ---- Process the AMD64 (x86) image. ----
# Add the full SWR tag to the local image.
docker tag defaultbackend-linux-amd64:${VERSION} ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-amd64:${VERSION}
# Push the image.
docker push ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-amd64:${VERSION}

# ---- Process the Arm64 image. ----
docker tag defaultbackend-linux-arm64:${VERSION} ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-arm64:${VERSION}
docker push ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}-linux-arm64:${VERSION}

Step 3: Create and Push a Manifest List

Create a dual-architecture manifest list and upload it to SWR. Associate the two single-architecture images with a single logical image name.

  1. Create a manifest list.

    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: modifies the manifest if it already exists.
    • --insecure: allows interaction with HTTP repositories. SWR typically uses HTTPS, but this parameter is included for compatibility and does not cause errors when HTTPS is used.

  2. Annotate each image in the manifest list with its OS architecture.

    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. Push the manifest list to SWR.

    docker manifest push -p --insecure ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION}
    • -p: pushes the manifest list rather than the image content, which was already pushed in the previous step.

  4. View the created manifest list.

    docker manifest inspect ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${VERSION}

Step 4: Use the Dual-Architecture Image in CCE

After completing the preceding steps, you can reference the same logical image path when creating a workload in CCE.

  • When a pod using this image is scheduled to an x86 node, the swr.ap-southeast-1.myhuaweicloud.com/test-namespace/defaultbackend-linux-amd64:1.5 image is pulled automatically.
  • When a pod using this image is scheduled to an Arm node, the swr.ap-southeast-1.myhuaweicloud.com/test-namespace/defaultbackend-linux-arm64:1.5 image is pulled automatically.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: defaultbackend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: defaultbackend
  template:
    metadata:
      labels:
        app: defaultbackend
    spec:
      containers:
      # Directly use the dual-architecture image path.
      - image: swr.ap-southeast-1.myhuaweicloud.com/test-namespace/defaultbackend:1.5
        name: nginx
      # You do not need to configure nodeSelector. The kubelet automatically pulls the image matching the node's architecture. However, if you need to restrict pod scheduling to nodes of a specific architecture, affinity rules are still required.
      # nodeSelector:      # Optional. If you need to restrict pod scheduling to nodes of a specific architecture, add a nodeSelector.
      #   kubernetes.io/arch: arm64   # Forcibly schedule pods to Arm nodes.
      imagePullSecrets:
      - name: default-secret

FAQs

Do I Need to Configure Node Affinity After Using a Dual-Architecture Image?

Not necessarily. Configure node affinity based on your deployment requirements.

  • No configuration required: If your cluster contains both x86 and Arm nodes and the pod architecture is not a concern, you only need to specify a dual-architecture image. No affinity configuration is necessary. The scheduler automatically assigns the pod to an available node, and the kubelet automatically pulls the appropriate image.
  • Configuration required: If a workload must run on a specific architecture, for example, due to legacy binary dependencies that support only x86, you must configure node affinity. In this case, the dual-architecture image ensures that the correct image is pulled once the pod is scheduled to the target node.

How Do I Check Whether an Image Supports Dual Architectures?

Run the following command to inspect the image manifest:
docker manifest inspect <image-path>

Check whether the returned manifest list contains entries whose platform.architecture field is set to amd64 or arm64.