Skip to content

Latest commit

 

History

History
172 lines (151 loc) · 5.37 KB

File metadata and controls

172 lines (151 loc) · 5.37 KB

Multiplatform Dev Container Builds

Building dev containers to support multiple platforms (aka CPU architectures) is possible with the devcontainers/ci GitHub Action/Azure DevOps Task, but requires other actions/tasks to be run beforehand and has several caveats.

General Notes/Caveats

  • Multiplatform builds utilize emulation to build on architectures not native to the system the build is running on. This will significantly increase build times over native, single architecture builds.
  • If you are using runCmd, the command will only be run on the architecure of the system the build is running on. This means that, if you are using runCmd to test the image, there may be bugs on the alternate platforms that will not be caught by your test suite. Manual post-build testing is advised.
  • As of October 2022, all hosted servers for GitHub Actions and Azure Pipelines are x86_64 only. If you want to automatically run runCmd-based tests on your devcontainer on another architecure, you'll need a self-hosted runner on that architecture. It is possible that there will be future support for hosted arm64 machines, see here for a tracking issue for Linux.

GitHub Actions Example

name: 'build'
on:
  pull_request:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout (GitHub)
        uses: actions/checkout@v3
      - name: Set up QEMU for multi-architecture builds
        uses: docker/setup-qemu-action@v3
      - name: Setup Docker buildx for multi-architecture builds
        uses: docker/setup-buildx-action@v3
        with:
          use: true
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and release devcontainer Multi-Platform
        uses: devcontainers/[email protected]
        with:
          imageName: ghcr.io/UserNameHere/ImageNameHere
          platform: linux/amd64,linux/arm64

Azure DevOps Task Example

trigger:
- main

pool:
  vmImage: ubuntu-latest

jobs:
- job: BuildContainerImage
  displayName: Build Container Image
  timeoutInMinutes: 0
  steps:
  - checkout: self
  - task: Docker@2
    displayName: Login to Container Registry
    inputs:
      command: login
      containerRegistry: RegistryNameHere
  - script: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
    displayName: Set up QEMU
  - script: docker buildx create --use
    displayName: Set up docker buildx
  - task: DevcontainersCi@0
    inputs:
      imageName: UserNameHere/ImageNameHere
      platform: linux/amd64,linux/arm64

Native Multi-Platform Builds (Matrix Strategy)

Instead of using QEMU emulation on a single runner, you can use native runners in a matrix strategy. Each runner builds for its own architecture and pushes a platform-specific image. A final job then merges the per-platform images into a single multi-arch manifest.

Benefits

  • Faster builds -- no emulation overhead since each runner compiles natively.
  • More reliable -- native compilation avoids QEMU compatibility issues.
  • Flexible runners -- works with GitHub's hosted ARM runners (ubuntu-24.04-arm) or self-hosted ARM agents.

GitHub Actions Example

jobs:
  build:
    strategy:
      matrix:
        include:
          - runner: ubuntu-latest
            platform: linux/amd64
            platformTag: linux-amd64
          - runner: ubuntu-24.04-arm
            platform: linux/arm64
            platformTag: linux-arm64
    runs-on: ${{ matrix.runner }}
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/setup-buildx-action@v3
      - uses: devcontainers/[email protected]
        with:
          imageName: ghcr.io/example/myimage
          platform: ${{ matrix.platform }}
          platformTag: ${{ matrix.platformTag }}
          push: always

  manifest:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/setup-buildx-action@v3
      - uses: devcontainers/[email protected]
        with:
          imageName: ghcr.io/example/myimage
          mergeTag: linux-amd64,linux-arm64

Azure DevOps Pipelines Example

stages:
- stage: Build
  jobs:
  - job: BuildAmd64
    pool:
      vmImage: ubuntu-latest
    steps:
    - task: DevcontainersCi@0
      inputs:
        imageName: myregistry.azurecr.io/devcontainer
        platform: linux/amd64
        platformTag: linux-amd64
        push: always

  - job: BuildArm64
    pool:
      vmImage: ubuntu-latest
    steps:
    - task: DevcontainersCi@0
      inputs:
        imageName: myregistry.azurecr.io/devcontainer
        platform: linux/arm64
        platformTag: linux-arm64
        push: always

- stage: Manifest
  dependsOn: Build
  jobs:
  - job: MergeManifest
    pool:
      vmImage: ubuntu-latest
    steps:
    - task: DevcontainersCi@0
      inputs:
        imageName: myregistry.azurecr.io/devcontainer
        mergeTag: linux-amd64,linux-arm64