]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
gh actions: build images separately by arch. Use gh arm64 runners
authorromeroalx <alexis.romero@open-xchange.com>
Wed, 20 Aug 2025 09:28:22 +0000 (11:28 +0200)
committerromeroalx <alexis.romero@open-xchange.com>
Tue, 9 Sep 2025 10:27:14 +0000 (12:27 +0200)
.github/workflows/build-docker-images.yml

index 80e1c62f28965974b378bf0426b7ff67596afe18..0817982f9de08d7129d17cfe512d86a5c351a574 100644 (file)
@@ -68,12 +68,34 @@ jobs:
         run: |
           [[ "${REF}" == "master" ]] || git describe --tags --exact-match
 
-  build:
-    name: build docker image for a product
+  prepare-runner-os-list:
+    name: generate runner list
     runs-on: ubuntu-24.04
-    needs: validate-push-image
     outputs:
-      image-digest: ${{ steps.build-image.outputs.digest }}
+      runnerlist: ${{ steps.get-runnerlist.outputs.runnerlist }}
+    steps:
+      - run: sudo apt-get update && sudo apt-get -y install jo
+      - id: get-runnerlist
+        run: |
+          runner_os_arch=()
+          [[ -n "${{ contains(inputs.platforms, 'amd64') || '' }}" ]] && runner_os_arch+=($(jo arch=linux/amd64 runner=ubuntu-24.04))
+          [[ -n "${{ contains(inputs.platforms, 'arm64') || '' }}" ]] && runner_os_arch+=($(jo arch=linux/arm64 runner=ubuntu-24.04-arm))
+          echo "runnerlist=$(jo -a ${runner_os_arch[@]})" >> "$GITHUB_OUTPUT"
+          # Fail if there are no runners for the requested architecture
+          if [[ -z "${runner_os_arch[@]}" ]]; then
+            echo "No runners available for ${{ inputs.platforms }}" && exit 1
+          fi
+
+  build:
+    name: build ${{ matrix.platform.arch }} docker image for a product
+    runs-on: ${{ matrix.platform.runner }}
+    needs:
+      - validate-push-image
+      - prepare-runner-os-list
+    strategy:
+      fail-fast: false
+      matrix:
+        platform: ${{ fromJson(needs.prepare-runner-os-list.outputs.runnerlist) }}
     steps:
       - uses: actions/checkout@v4
         with:
@@ -81,14 +103,10 @@ jobs:
           submodules: recursive
           ref: ${{ inputs.ref }}
           persist-credentials: false
-      - name: Set up QEMU
-        uses: docker/setup-qemu-action@v3
-        with:
-          platforms: linux/arm64/v8
       - name: Set up Docker Buildx for multi-platform builds
         uses: docker/setup-buildx-action@v3
-        with:
-          platforms: ${{ inputs.platforms }}
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v3
       - name: Login to Docker Hub
         if: ${{ inputs.push }}
         uses: docker/login-action@v3
@@ -100,18 +118,18 @@ jobs:
         uses: docker/metadata-action@v5
         with:
           images: ${{ secrets.DOCKERHUB_ORGANIZATION_NAME || 'powerdns' }}/${{ inputs.image-name }}
-          tags: ${{ inputs.image-tags }}
       - name: Build and load powerdns product images
         id: build-image
         uses: docker/build-push-action@v6
         with:
           context: .
           file: Dockerfile-${{ inputs.product }}
-          platforms: ${{ inputs.platforms }}
+          platforms: ${{ matrix.platform.arch }}
           push: ${{ inputs.push }}
           sbom: true
-          tags: ${{ steps.meta.outputs.tags }}
+          tags: ${{ secrets.DOCKERHUB_ORGANIZATION_NAME || 'powerdns' }}/${{ inputs.image-name }}
           build-args: ${{ inputs.build-args }}
+          outputs: type=image,push-by-digest=true,name-canonical=true
       - name: Update repo description
         if: ${{ inputs.push }}
         uses: peter-evans/dockerhub-description@v4
@@ -120,37 +138,70 @@ jobs:
           password: ${{ secrets.DOCKERHUB_TOKEN }}
           repository: ${{ secrets.DOCKERHUB_ORGANIZATION_NAME }}/${{ inputs.image-name }}
           short-description: ${{ inputs.image-description }}
+      - name: Export output digest
+        run: |
+          mkdir -p ${{ runner.temp }}/digests
+          digest="${{ steps.build-image.outputs.digest }}"
+          touch "${{ runner.temp }}/digests/${digest#sha256:}"
+          # generate suffix for digest file 
+          platform=${{ matrix.platform.arch }}
+          echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
+      - name: Upload digest
+        uses: actions/upload-artifact@v4
+        with:
+          name: digests-${{ inputs.product }}-${{ env.PLATFORM_PAIR }}
+          path: ${{ runner.temp }}/digests/*
+          if-no-files-found: error
+          retention-days: 1
 
-  prepare-test-runner-os-list:
-    name: generate runner list
+  publish-tag:
+    name: Generate and publish tag for multi-platform image
+    runs-on: ubuntu-24.04
     if: ${{ inputs.push }}
     needs: build
-    runs-on: ubuntu-24.04
     outputs:
-      runnerlist: ${{ steps.get-runnerlist.outputs.runnerlist }}
-      skiptests: ${{ steps.get-runnerlist.outputs.skiptests }}
+      image-digest: ${{ steps.get-image-digest.outputs.image-digest }}
     steps:
-      - run: sudo apt-get update && sudo apt-get -y install jo
-      - id: get-runnerlist
+      - name: Download digests
+        uses: actions/download-artifact@v4
+        with:
+          path: ${{ runner.temp }}/digests
+          pattern: digests-${{ inputs.product }}-*
+          merge-multiple: true
+      - name: Login to Docker Hub
+        if: ${{ inputs.push }}
+        uses: docker/login-action@v3
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v3
+      - name: Docker meta
+        id: meta
+        uses: docker/metadata-action@v5
+        with:
+          images: ${{ secrets.DOCKERHUB_ORGANIZATION_NAME }}/${{ inputs.image-name }}
+          tags: ${{ inputs.image-tags }}
+      - name: Create manifest list and push
+        working-directory: ${{ runner.temp }}/digests
         run: |
-          runner_os=()
-          [[ -n "${{ contains(inputs.platforms, 'amd64') && 'ubuntu-24.04' || '' }}" ]] && runner_os+=('ubuntu-24.04')
-          [[ -n "${{ vars.ARM64_USE_UBICLOUD == '1' && contains(inputs.platforms, 'arm64') || '' }}" ]] && runner_os+=('ubicloud-standard-2-arm')
-          echo "runnerlist=$(jo -a ${runner_os[@]})" >> "$GITHUB_OUTPUT"
-          # Skip tests if no runner is suitable for running them. Set a default runner to avoid CI failure
-          if [[ -z "${runner_os[@]}" ]]; then
-            echo "runnerlist=$(jo -a ubuntu-24.04)" >> "$GITHUB_OUTPUT"
-            echo "skiptests=1" >> "$GITHUB_OUTPUT"
-          fi
+          docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
+            $(printf '${{ secrets.DOCKERHUB_ORGANIZATION_NAME }}/${{ inputs.image-name }}@sha256:%s ' *)
+      - name: Get image digest
+        id: get-image-digest
+        run: |
+          echo "image-digest=$(docker buildx imagetools inspect ${{ secrets.DOCKERHUB_ORGANIZATION_NAME }}/${{ inputs.image-name }}:${{ steps.meta.outputs.version }} --format="{{json .Manifest}}" | jq -r .digest)" >> "$GITHUB_OUTPUT"
 
   test-uploaded-images:
-    name: test uploaded images
-    if: ${{ inputs.push && ! needs.prepare-test-runner-os-list.outputs.skiptests }}
-    needs: [build, prepare-test-runner-os-list]
-    runs-on: ${{ matrix.runner-os }}
+    name: test ${{ matrix.platform.arch }} uploaded images
+    if: ${{ inputs.push }}
+    needs:
+      - prepare-runner-os-list
+      - publish-tag
+    runs-on: ${{ matrix.platform.runner }}
     strategy:
       matrix:
-        runner-os: ${{ fromJson(needs.prepare-test-runner-os-list.outputs.runnerlist )}}
+        platform: ${{ fromJson(needs.prepare-runner-os-list.outputs.runnerlist) }}
       fail-fast: false
     env:
       INPUT_IMAGE_NAME: ${{ inputs.image-name }}
@@ -162,12 +213,12 @@ jobs:
           image_name="${{ secrets.DOCKERHUB_ORGANIZATION_NAME }}/${INPUT_IMAGE_NAME}"
           for tag in `echo "${INPUT_IMAGE_TAGS}" | tr '\n' ' '`; do
             echo 'Testing: '${image_name}':'${tag};
-            # pdns-auth image returns a 134 exit code
-            docker run ${image_name}:${tag} --version || [ "$?" == "134" ]
+            # recent pdns-auth images of tags older than 4.9.x image return a exit code 99
+            docker run ${image_name}:${tag} --version || [ "$?" == "99" ]
           done
       - name: Check image digest matches
         env:
-          EXPECTED_DIGEST: ${{ needs.build.outputs.image-digest }}
+          EXPECTED_DIGEST: ${{ needs.publish-tag.outputs.image-digest }}
         run: |
           image_name="${{ secrets.DOCKERHUB_ORGANIZATION_NAME }}/${INPUT_IMAGE_NAME}"
           for tag in `echo "${INPUT_IMAGE_TAGS}" | tr '\n' ' '`; do