Build multi-architecture images
This document covers methods for building multi architecture images in Harness with or without Docker layer caching (DLC).
With DLC
If you're using self-hosted infrastructure, turn on the feature flag CI_ENABLE_DLC_SELF_HOSTED. To enable this flag, contact Harness Support.
- Open your Build and Push an image to Docker Registry step.
- Select Enable Docker Layer caching. To learn more, go to Docker layer caching.
- Open the Optional Configuration dropdown at the bottom of the step.
- Add a variable under Environment Variables.
- Enter PLUGIN_PLATFORMfor your Key.
- Enter your architectures as a comma separated list as your Value. For example, linux/amd64,linux/arm64.
Without DLC
If you're using Kubernetes infrastructure, turn on the feature flag CI_USE_BUILDX_ON_K8. To enable this flag, contact Harness Support.
- Open your Build and Push an image to Docker Registry step.
- Open the Optional Configuration dropdown at the bottom of the step.
- Add two variables under Environment Variables.
- Enter PLUGIN_PLATFORMfor your first Key.
- Then, enter your architectures as a comma separated list as your Value. For example, linux/amd64,linux/arm64.
- Enter PLUGIN_BUILDER_DRIVERfor your second variable's Key.
- Then, enter docker-containerfor your second variable's Value.
Deprecated Methods
Deprecated method of building multi-arch images on Kubernetes infrastructure
The following method for building multi-arch images is not recommended.
To build multi-architecture images in a CI pipeline, use a separate stage to build and push each architecture.
For example, the following pipeline has two stages. The two stages have similar components, but they differ according to the architecture of the image that the stage builds. Each stage has:
- A variation of a Kubernetes cluster build infrastructure. Notice that each stage uses a different Kubernetes cluster connector (infrastructure.spec.connectorRef) and other settings due to the different architecture requirements.
- A Run step that prepares the Dockerfile.
- A Build and Push step that builds and uploads the image. If the images are uploaded to the same repository, use tagsto differentiate them, such as1.0-linux-amd64and1.0-linux-arm64.
pipeline:
  allowStageExecutions: true
  projectIdentifier: default
  orgIdentifier: default
  identifier: CI_MultiArch
  name: CI_MultiArch
  tags:
    CI: ""
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODEBASE_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
  stages:
    - stage:
        name: K8
        identifier: upload
        type: CI
        spec:
          cloneCodebase: true
          infrastructure:
            type: KubernetesDirect
            spec:
              connectorRef: k8Linux
              namespace: <+input>
              runAsUser: ""
              automountServiceAccountToken: true
              nodeSelector: {}
              containerSecurityContext:
                runAsUser: ""
              os: Linux
          execution:
            steps:
              - step:
                  type: Run
                  name: CreateDockerFile
                  identifier: CreateDockerFile
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: alpine:latest
                    command: |-
                      touch harnessDockerfileui
                      cat > harnessDockerfileui <<- EOM
                      FROM alpine:latest AS dev-env
                      ARG foo
                      RUN echo "$foo bar"
                      ENTRYPOINT ["pwd"]
                      FROM alpine:latest AS release-env
                      ARG hello
                      RUN echo "$hello world"
                      ENTRYPOINT ["ls"]
                      EOM
                      cat harnessDockerfileui
                    resources:
                      limits:
                        memory: 100M
              - step:
                  type: BuildAndPushDockerRegistry
                  name: DockerPushStep
                  identifier: DockerPushStep
                  spec:
                    connectorRef: YOUR_DOCKER_CONNECTOR_ID
                    repo: my-repo/ci-demo
                    tags:
                      - "1.0-linux-amd64"
                    dockerfile: harnessDockerfileui
                    target: dev-env
                    resources:
                      limits:
                        memory: 100M
    - stage:
        name: K8s Linux arm
        identifier: CI_Golden_ARM
        type: CI
        spec:
          cloneCodebase: true
          infrastructure:
            type: KubernetesDirect
            spec:
              connectorRef: k8sarm
              namespace: ci-gold-arm-delegate
              automountServiceAccountToken: true
              tolerations:
                - effect: NoSchedule
                  key: kubernetes.io/arch
                  operator: Equal
                  value: arm64
              nodeSelector:
                kubernetes.io/arch: arm64
              os: Linux
          execution:
            steps:
              - step:
                  type: Run
                  name: CreateDockerFile
                  identifier: CreateDockerFile
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: alpine:latest
                    command: |-
                      touch harnessDockerfileui
                      cat > harnessDockerfileui <<- EOM
                      FROM alpine:latest AS dev-env
                      ARG foo
                      RUN echo "$foo bar"
                      ENTRYPOINT ["pwd"]
                      FROM alpine:latest AS release-env
                      ARG hello
                      RUN echo "$hello world"
                      ENTRYPOINT ["ls"]
                      EOM
                      cat harnessDockerfileui
                    resources:
                      limits:
                        memory: 100M
              - step:
                  type: BuildAndPushDockerRegistry
                  name: DockerPushStep
                  identifier: DockerPushStep
                  spec:
                    connectorRef: YOUR_DOCKER_CONNECTOR_ID
                    repo: my-repo/ci-demo
                    tags:
                      - "1.0-linux-arm64"
                    dockerfile: harnessDockerfileui
                    target: dev-env
                    resources:
                      limits:
                        memory: 100M