From 3aaee2f95653b0f65c07dd078d737996d5f4b014 Mon Sep 17 00:00:00 2001 From: Patrick Stephens Date: Mon, 27 Jan 2025 10:22:47 +0000 Subject: [PATCH] workflows: split container builds per-arch Signed-off-by: Patrick Stephens --- .github/workflows/call-build-images.yaml | 189 ++++++++++++++++------- 1 file changed, 135 insertions(+), 54 deletions(-) diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index 4f8c9b9323f..95a47dab255 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -33,11 +33,6 @@ on: type: string required: false default: "" - platforms: - description: The platforms to build for - type: string - required: false - default: 'linux/amd64, linux/arm64, linux/arm/v7, linux/s390x' secrets: token: description: The Github token or similar to authenticate with for the registry. @@ -74,25 +69,34 @@ jobs: replace-with: "$1" flags: "g" - # This is the intended approach to multi-arch image and all the other checks scanning, - # signing, etc only trigger from this. - call-build-images: - needs: - - call-build-images-meta - name: Multiarch container images to GHCR - runs-on: ubuntu-latest-8-cores - environment: ${{ inputs.environment }} + # Taken from https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners + # We split this out to make it easier to restart just one of them if it fails and do all in parallel + call-build-single-arch-container-images: + # Allow us to continue to create a manifest if we want + continue-on-error: true permissions: contents: read packages: write - outputs: - production-digest: ${{ steps.build_push.outputs.digest }} - debug-digest: ${{ steps.debug_build_push.outputs.digest }} + strategy: + fail-fast: false + matrix: + platform: + - amd64 + - arm64 + - arm/v7 + - s390x + target: + - production + - debug + name: ${{ matrix.platform }} container image build for ${{ matrix.target }} + # Use GitHub Actions ARM hosted runners + runs-on: ${{ (contains(matrix.platform, 'arm') && 'ubuntu-22.04-arm') || 'ubuntu-latest' }} steps: - - name: Checkout code for modern style builds + - name: Checkout code uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} + token: ${{ secrets.token }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -103,30 +107,20 @@ jobs: - name: Log in to the Container registry uses: docker/login-action@v3 with: - registry: ${{ inputs.registry }} - username: ${{ inputs.username }} + registry: ghcr.io + username: ${{ github.actor }} password: ${{ secrets.token }} - - name: Extract metadata from Github - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ inputs.registry }}/${{ inputs.image }} - tags: | - raw,${{ inputs.version }} - raw,${{ needs.call-build-images-meta.outputs.major-version }} - raw,latest - - - name: Build the production images - id: build_push + - name: Build and push by digest the standard ${{ matrix.target }} image + id: build uses: docker/build-push-action@v6 with: + # Use path context rather than Git context as we want local files file: ./dockerfiles/Dockerfile context: . - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: ${{ inputs.platforms }} - target: production + target: ${{ matrix.target }} + outputs: type=image,name=${{ inputs.registry }}/${{ inputs.image }},push-by-digest=true,name-canonical=true,push=true + platforms: linux/${{ matrix.platform }} # Must be disabled to provide legacy format images from the registry provenance: false push: true @@ -135,6 +129,82 @@ jobs: FLB_NIGHTLY_BUILD=${{ inputs.unstable }} RELEASE_VERSION=${{ inputs.version }} + - name: Export ${{ matrix.target }} digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + shell: bash + + - name: Upload ${{ matrix.target }} digest + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.target }}-digests-${{ (contains(matrix.platform, 'arm/v7') && 'arm-v7') || matrix.platform }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + # Take the digests and produce a multi-arch manifest from them. + call-build-container-image-manifests: + permissions: + contents: read + packages: write + name: Upload multi-arch container image manifests + runs-on: ubuntu-latest + needs: + - call-build-images-meta + - call-build-single-arch-container-images + steps: + - name: Extract metadata from Github + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ inputs.registry }}/${{ inputs.image }} + tags: | + raw,${{ inputs.version }} + raw,${{ needs.call-build-images-meta.outputs.major-version }} + raw,latest + + - name: Download production digests + uses: actions/download-artifact@v4 + with: + pattern: production-digests-* + path: /tmp/production-digests + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.token }} + + - name: Create production manifest + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ inputs.registry }}/${{ inputs.image }}@sha256:%s ' *) + shell: bash + working-directory: /tmp/production-digests + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ inputs.registry }}/${{ inputs.image }}:${{ steps.meta.outputs.version }} + shell: bash + + # Take the digests and produce a multi-arch manifest from them. + call-build-debug-container-image-manifests: + permissions: + contents: read + packages: write + name: Upload debug multi-arch container image manifests + runs-on: ubuntu-latest + needs: + - call-build-images-meta + - call-build-single-arch-container-images + steps: - id: debug-meta uses: docker/metadata-action@v5 with: @@ -144,28 +214,39 @@ jobs: raw,${{ needs.call-build-images-meta.outputs.major-version }}-debug raw,latest-debug - - name: Build the debug multi-arch images - id: debug_build_push - uses: docker/build-push-action@v6 + - name: Download debug digests + uses: actions/download-artifact@v4 with: - file: ./dockerfiles/Dockerfile - context: . - tags: ${{ steps.debug-meta.outputs.tags }} - labels: ${{ steps.debug-meta.outputs.labels }} - platforms: ${{ inputs.platforms }} - # Must be disabled to provide legacy format images from the registry - provenance: false - target: debug - push: true - load: false - build-args: | - FLB_NIGHTLY_BUILD=${{ inputs.unstable }} - RELEASE_VERSION=${{ inputs.version }} + pattern: production-digests-* + path: /tmp/debug-digests + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.token }} + + - name: Create debug manifest + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ inputs.registry }}/${{ inputs.image }}@sha256:%s ' *) + shell: bash + working-directory: /tmp/debug-digests + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ inputs.registry }}/${{ inputs.image }}:${{ steps.debug-meta.outputs.version }} + shell: bash call-build-images-generate-schema: needs: - call-build-images-meta - - call-build-images + - call-build-container-image-manifests runs-on: ubuntu-latest environment: ${{ inputs.environment }} permissions: @@ -195,7 +276,7 @@ jobs: call-build-images-scan: needs: - call-build-images-meta - - call-build-images + - call-build-container-image-manifests name: Trivy + Dockle image scan runs-on: ubuntu-latest environment: ${{ inputs.environment }} @@ -230,7 +311,7 @@ jobs: call-build-images-sign: needs: - call-build-images-meta - - call-build-images + - call-build-container-image-manifests name: Deploy and sign multi-arch container image manifests permissions: contents: read