From f5ca3743fd8d4dd9e5b43a80bc486e131b6435f2 Mon Sep 17 00:00:00 2001 From: nitrobass24 Date: Mon, 6 Apr 2026 22:39:15 -0500 Subject: [PATCH] Speed up Docker build: native arm64 runner instead of QEMU Build each architecture on its own native runner (ubuntu-24.04 for amd64, ubuntu-24.04-arm for arm64) in parallel, export as OCI tarballs, then merge into a multi-arch manifest at publish time. Eliminates ~25 minutes of QEMU emulation overhead. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 83 ++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 005d36b92..21773598e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -147,8 +147,18 @@ jobs: run: yarn run build --env production docker-build: - name: Build Docker Image - runs-on: ubuntu-latest + name: Build Docker (${{ matrix.arch }}) + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - arch: amd64 + runner: ubuntu-24.04 + platform: linux/amd64 + - arch: arm64 + runner: ubuntu-24.04-arm + platform: linux/arm64 permissions: contents: read @@ -158,9 +168,6 @@ jobs: with: fetch-depth: 1 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -180,26 +187,27 @@ jobs: uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=sha,prefix= - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=${{ steps.version.outputs.version }},enable=${{ inputs.version != '' }} - - name: Build Docker image + - name: Build and export uses: docker/build-push-action@v6 with: context: . - platforms: linux/amd64,linux/arm64 + platforms: ${{ matrix.platform }} push: false - tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | VERSION=${{ steps.version.outputs.version }} VERSION_BRANCH=${{ github.ref_name }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=gha,scope=${{ matrix.arch }} + cache-to: type=gha,scope=${{ matrix.arch }},mode=max + outputs: type=oci,dest=/tmp/image-${{ matrix.arch }}.tar + + - name: Upload image artifact + uses: actions/upload-artifact@v4 + with: + name: docker-image-${{ matrix.arch }} + path: /tmp/image-${{ matrix.arch }}.tar + retention-days: 1 docker-publish: name: Publish Docker Image @@ -210,13 +218,17 @@ jobs: packages: write steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Download amd64 image + uses: actions/download-artifact@v4 with: - fetch-depth: 1 + name: docker-image-amd64 + path: /tmp - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + - name: Download arm64 image + uses: actions/download-artifact@v4 + with: + name: docker-image-arm64 + path: /tmp - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -251,15 +263,20 @@ jobs: type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} type=raw,value=${{ steps.version.outputs.version }},enable=${{ inputs.version != '' }} - - name: Push Docker image - uses: docker/build-push-action@v6 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - VERSION=${{ steps.version.outputs.version }} - VERSION_BRANCH=${{ github.ref_name }} - cache-from: type=gha + - name: Load and push multi-arch manifest + run: | + # Import OCI images into buildx store + docker buildx imagetools create \ + --tag "$FIRST_TAG" \ + oci-archive:///tmp/image-amd64.tar \ + oci-archive:///tmp/image-arm64.tar + + # Apply all remaining tags + for tag in $ALL_TAGS; do + if [ "$tag" != "$FIRST_TAG" ]; then + docker buildx imagetools create --tag "$tag" "$FIRST_TAG" + fi + done + env: + FIRST_TAG: ${{ fromJSON(steps.meta.outputs.json).tags[0] }} + ALL_TAGS: ${{ join(fromJSON(steps.meta.outputs.json).tags, ' ') }}