From c82fd45173d517f8358f9f98277bbc9a89f0527c Mon Sep 17 00:00:00 2001 From: Arlind-dev Date: Fri, 22 May 2026 01:03:24 +0200 Subject: [PATCH] ci: build multi-arch images via matrix and digest merge --- .github/workflows/cicd.yml | 111 ++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 15 deletions(-) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 54816bfb5..23e448048 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -106,43 +106,124 @@ jobs: NODE_ENV: test build: - runs-on: ubuntu-24.04-arm permissions: contents: read packages: write id-token: write + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-24.04 + platform_pair: amd64 + - platform: linux/arm64 + runner: ubuntu-24.04-arm + platform_pair: arm64 + runs-on: ${{ matrix.runner }} steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set lowercase image name + id: image + run: echo "name=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + + - name: Login to GHCR + if: github.event_name == 'push' + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Docker meta id: meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 with: - images: | - ghcr.io/${{ github.repository }} - tags: | - type=raw,value={{sha}} - type=raw,value=latest + images: ${{ steps.image.outputs.name }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + with: + context: . + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,name=${{ steps.image.outputs.name }},push-by-digest=true,name-canonical=true,push=${{ github.event_name == 'push' }} + cache-from: type=gha,scope=${{ matrix.platform_pair }} + cache-to: type=gha,mode=max,scope=${{ matrix.platform_pair }} + + - name: Export digest + if: github.event_name == 'push' + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + if: github.event_name == 'push' + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v6.0.1 + with: + name: digest-${{ matrix.platform_pair }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + build-merge: + if: github.event_name == 'push' + needs: [build] + runs-on: ubuntu-24.04 + permissions: + contents: read + packages: write + + steps: + - name: Set lowercase image name + id: image + run: echo "name=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT" + + - name: Download digests + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + pattern: digest-* + path: /tmp/digests + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Login to GHCR - if: github.ref == 'refs/heads/main' uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and maybe Push Docker image - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + - name: Docker meta + id: meta + uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 with: - push: ${{ github.ref == 'refs/heads/main' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - #cache-from: type=gha - #cache-to: type=gha,mode=max + images: ${{ steps.image.outputs.name }} + tags: | + type=raw,value={{sha}} + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} + + - name: Create and push manifest + working-directory: /tmp/digests + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}') \ + $(printf '${{ steps.image.outputs.name }}@sha256:%s ' *) deploy: if: github.ref == 'refs/heads/main' - needs: [lint, test, typecheck, build] + needs: [lint, test, typecheck, build-merge] runs-on: ubuntu-slim environment: name: prod