dockergithub-actionsbuildx

Github docker/build-push-action with multiple architectures is slow


I am building a docker image as a step in my CD in github actions and I recently enabled multiple architecture builds because I am on an M2 Mac and so I would like arm builds as well. I noticed that after enabling that my build times sky-rocketed.

Am I doing something wrong or is this to be expected?

Step:

# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
  id: build-and-push
  uses: docker/build-push-action@v5.1.0
  with:
    context: ./src
    push: ${{ github.event_name != 'pull_request' }}
    tags: ${{ steps.meta.outputs.tags }}
    labels: ${{ steps.meta.outputs.labels }}
    platforms: linux/amd64,linux/arm64
    cache-from: type=gha
    cache-to: type=gha,mode=max

I do also notice that I see these messages now:

#19 7.855 warning Pattern ["string-width@^4.1.0"] is trying to unpack in the same destination "/usr/local/share/.cache/yarn/v6/npm-string-width-cjs-4.2.3-269c7117d27b05ad2e536830a8ec895ef9c6d010-integrity/node_modules/string-width-cjs" as pattern ["string-width-cjs@npm:string-width@^4.2.0"]. This could result in non-deterministic behavior, skipping.

Solution

  • Building Docker images for multiple architectures can indeed increase the build time, especially if you're doing it on a single machine. This is because Docker has to build a separate image for each architecture, which can be time-consuming.

    When you build for multiple architectures, Docker uses QEMU to emulate the target architecture. This emulation process can be slower than native builds, especially for complex applications.

    If the increased build time is a problem, you might consider a few options:

    To take advantage of GitHub Actions' parallelism, you could split the builds into separate jobs and use a build matrix to specify the different architectures. Here's an example of how you might set this up:

    name: Build Docker Images
    
    on: [push, pull_request]
    
    jobs:
      build:
        runs-on: ubuntu-latest
        strategy:
          matrix:
            architecture: [amd64, arm64]
        steps:
        - uses: actions/checkout@v2
    
        - name: Set up Docker Buildx
          uses: docker/setup-buildx-action@v1
    
        - name: Build and push Docker image
          uses: docker/build-push-action@v2
          with:
            context: .
            push: true
            tags: user/app:${{ matrix.architecture }}
            platforms: linux/${{ matrix.architecture }}
    

    The parallelism in this GitHub Actions workflow is determined by the strategy.matrix key.


    solving lowercase github.repository_owner:

    This is how you can run a shell script to convert your username to a lowercase env variable.

    - name: Lowercase GitHub username
      run: echo "DOCKER_USERNAME=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
    
    - name:
      ...
      tags: ${{ env.DOCKER_USERNAME }}/your-image-name:${{ steps.meta.outputs.tags }}
    

    In GitHub Actions, the GITHUB_ENV is a special environment file. When you write a string to this file in the format NAME=VALUE. The env context is a context available in GitHub Actions that contains the environment variables available to the runner. When you write to the GITHUB_ENV file, the environment variables you set are added to this context.