diff --git a/build/ci/github-actions/multi-platform.md b/build/ci/github-actions/multi-platform.md index dd3882b033..626223b889 100644 --- a/build/ci/github-actions/multi-platform.md +++ b/build/ci/github-actions/multi-platform.md @@ -58,18 +58,15 @@ In the previous example, each platform is built on the same runner which can take a long time depending on the number of platforms and your Dockerfile. To solve this issue you can use a matrix strategy to distribute the build for -each platform across multiple runners and merge the resulting manifests into a -single image using the [`buildx imagetools create` command](../../../engine/reference/commandline/buildx_imagetools_create.md). +each platform across multiple runners and create manifest list using the +[`buildx imagetools create` command](../../../engine/reference/commandline/buildx_imagetools_create.md). The following workflow will build the image for each platform on a dedicated -runner using a matrix strategy and upload the resulting images as artifacts. -Then, the `push` job will download the images, load them into the local Docker -daemon, push them to a temporary local registry so Buildx can create a manifest -list and push it to Docker Hub. It will copy the images from the local -registry to Docker Hub as well. +runner using a matrix strategy and push by digest. Then, the `merge` job will +create a manifest list and push it to Docker Hub. -Using a local registry is useful, so we don't create unecessary tags for each -platform on the remote registry. Only `user/app:latest` will be created. +This example also uses the [`metadata` action](https://github.com/docker/metadata-action) +to set tags and labels. {% raw %} ```yaml @@ -81,9 +78,7 @@ on: - "main" env: - TMP_LOCAL_IMAGE: localhost:5000/user/app REGISTRY_IMAGE: user/app - REGISTRY_TAG: latest jobs: build: @@ -101,12 +96,11 @@ jobs: name: Checkout uses: actions/checkout@v3 - - name: Prepare - run: | - mkdir -p /tmp/images - platform=${{ matrix.platform }} - echo "TARFILE=${platform//\//-}.tar" >> $GITHUB_ENV - echo "TAG=${{ env.TMP_LOCAL_IMAGE }}:${platform//\//-}" >> $GITHUB_ENV + name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY_IMAGE }} - name: Set up QEMU uses: docker/setup-qemu-action@v2 @@ -114,48 +108,55 @@ jobs: name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - name: Build + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push by digest + id: build uses: docker/build-push-action@v4 with: context: . platforms: ${{ matrix.platform }} - tags: ${{ env.TAG }} - outputs: type=docker,dest=/tmp/images/${{ env.TARFILE }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true - - name: Upload image + name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + - + name: Upload digest uses: actions/upload-artifact@v3 with: - name: images - path: /tmp/images/${{ env.TARFILE }} + name: digests + path: /tmp/digests/* if-no-files-found: error retention-days: 1 - push: + merge: runs-on: ubuntu-latest needs: - build - services: - registry: - image: registry:2 - ports: - - 5000:5000 steps: - - name: Download images + name: Download digests uses: actions/download-artifact@v3 with: - name: images - path: /tmp/images + name: digests + path: /tmp/digests - - name: Load images - run: | - for image in /tmp/images/*.tar; do - docker load -i $image - done + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 - - name: Push images to local registry - run: | - docker push -a ${{ env.TMP_LOCAL_IMAGE }} + name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY_IMAGE }} - name: Login to Docker Hub uses: docker/login-action@v2 @@ -164,12 +165,13 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Create manifest list and push + working-directory: /tmp/digests run: | - docker buildx imagetools create -t ${{ env.REGISTRY_IMAGE }}:${{ env.REGISTRY_TAG }} \ - $(docker image ls --format '{{.Repository}}:{{.Tag}}' '${{ env.TMP_LOCAL_IMAGE }}' | tr '\n' ' ') + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) - name: Inspect image run: | - docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ env.REGISTRY_TAG }} + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} ``` {% endraw %}