2424jobs :
2525 test :
2626 runs-on : ubuntu-latest
27+ permissions :
28+ contents : read
29+ packages : write
2730 steps :
31+ # GitHub gives only repository complete in <owner>/<repo> format.
32+ # Need some manual shenanigans
33+ # Set IMAGE_NAME so we can push to <owner>/<repo>/<image>
34+ # Transform os/arch to os-arch for suffix target
35+ - name : Set ENV variables
36+ run : |
37+ echo "IMAGE_NAME=${GITHUB_REPOSITORY#$GITHUB_REPOSITORY_OWNER/}" >> $GITHUB_ENV
38+
2839 - name : Checkout repository
2940 uses : actions/checkout@v4
3041
42+ # Login against a Docker registry
43+ # https://github.com/docker/login-action
44+ - name : Log into registry ${{ env.REGISTRY }}
45+ uses : docker/login-action@v3.3.0
46+ with :
47+ registry : ${{ env.REGISTRY }}
48+ username : ${{ github.actor }}
49+ password : ${{ secrets.GITHUB_TOKEN }}
50+
3151 # This might be unnecessary as tests are not
3252 # multiplatform
3353 - name : Setup Docker buildx
@@ -43,17 +63,18 @@ jobs:
4363 load : true
4464 target : dev
4565 tags : ${{ env.TEST_TAG }}
46- cache-from : type=gha
47- cache-to : type=gha ,mode=max
66+ cache-from : type=registry,ref=${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-cache:tests
67+ cache-to : type=registry,ref=${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-cache:tests ,mode=max
4868
4969 # This is a barrier check to make sure we push a functional
5070 # docker image, we can avoid linting
5171 - name : Run tests in the test image
5272 run : |
5373 docker run --rm ${{ env.TEST_TAG }} make ci-test
5474
55- build :
56- runs-on : ubuntu-latest
75+ # Inspired to https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
76+ build-arch :
77+ runs-on : ${{ matrix.arch.runner }}
5778 needs : test
5879 permissions :
5980 contents : read
@@ -63,24 +84,120 @@ jobs:
6384 id-token : write
6485 strategy :
6586 matrix :
87+ arch :
88+ - platform : linux/amd64
89+ runner : ubuntu-latest
90+ - platform : linux/arm64
91+ # There is no latest for ARM yet
92+ # https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
93+ runner : ubuntu-24.04-arm
6694 docker_target :
6795 - migrations
6896 - http
6997 - socketio
7098 - dramatiq
7199 steps :
72100 # GitHub gives only repository complete in <owner>/<repo> format.
73- # Need some manual sheanigans
101+ # Need some manual shenanigans
74102 # Set IMAGE_NAME so we can push to <owner>/<repo>/<image>
103+ # Transform os/arch to os-arch for suffix target
75104 - name : Set ENV variables
76105 run : |
77106 echo "IMAGE_NAME=${GITHUB_REPOSITORY#$GITHUB_REPOSITORY_OWNER/}" >> $GITHUB_ENV
107+ platform=${{ matrix.arch.platform }}
108+ echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
78109
79110 - name : Checkout repository
80111 uses : actions/checkout@v4
81112
82- - name : Set up QEMU
83- uses : docker/setup-qemu-action@v3
113+ # Install the cosign tool
114+ # https://github.com/sigstore/cosign-installer
115+ - name : Install cosign
116+ uses : sigstore/cosign-installer@v3.8.1
117+
118+ - name : Setup Docker buildx
119+ uses : docker/setup-buildx-action@v3.10.0
120+
121+ # Login against a Docker registry
122+ # https://github.com/docker/login-action
123+ - name : Log into registry ${{ env.REGISTRY }}
124+ uses : docker/login-action@v3.3.0
125+ with :
126+ registry : ${{ env.REGISTRY }}
127+ username : ${{ github.actor }}
128+ password : ${{ secrets.GITHUB_TOKEN }}
129+
130+ # We extract metadata without tags for single image
131+ - name : Extract Docker metadata
132+ id : meta
133+ uses : docker/metadata-action@v5.7.0
134+ with :
135+ # list of Docker images to use as base name for tags
136+ # <registry/<owner>/<repo_name>/<repo_name>-<target>
137+ images : |
138+ ${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-${{ matrix.docker_target }}
139+
140+
141+ # This build an image WITHOUT tags and outputs the digests, so that we can aggragate them later
142+ - name : Build and push production image
143+ id : build-and-push
144+ uses : docker/build-push-action@v6.15.0
145+ with :
146+ context : .
147+ target : ${{ matrix.docker_target }}
148+ platforms : ${{ matrix.arch.platform }}
149+ outputs : type=image,push-by-digest=true,name-canonical=true,push=true
150+ tags : ${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-${{ matrix.docker_target }}
151+ labels : ${{ steps.meta.outputs.labels }}
152+ cache-from : type=registry,ref=${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-cache:buildcache-${{ matrix.docker_target }}-${{ env.PLATFORM_PAIR }}
153+ cache-to : type=registry,ref=${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-cache:buildcache-${{ matrix.docker_target }}-${{ env.PLATFORM_PAIR }},mode=max
154+
155+ - name : Export digest
156+ run : |
157+ mkdir -p ${{ runner.temp }}/digests/${{ matrix.docker_target }}
158+ digest="${{ steps.build-and-push.outputs.digest }}"
159+ touch "${{ runner.temp }}/digests/${{ matrix.docker_target }}/${digest#sha256:}"
160+
161+ - name : Upload digest
162+ uses : actions/upload-artifact@v4
163+ with :
164+ name : digests-${{ env.PLATFORM_PAIR }}
165+ path : ${{ runner.temp }}/digests/${{ matrix.docker_target }}/*
166+ if-no-files-found : error
167+ retention-days : 1
168+
169+
170+ aggregate-manifests :
171+ runs-on : ubuntu-latest
172+ needs : build-arch
173+ permissions :
174+ contents : read
175+ packages : write
176+ # This is used to complete the identity challenge
177+ # with sigstore/fulcio when running outside of PRs.
178+ id-token : write
179+ strategy :
180+ matrix :
181+ docker_target :
182+ - migrations
183+ - http
184+ - socketio
185+ - dramatiq
186+
187+ steps :
188+ # GitHub gives only repository complete in <owner>/<repo> format.
189+ # Need some manual sheanigans
190+ # Set IMAGE_NAME so we can push to <owner>/<repo>/<image>
191+ - name : Set ENV variables
192+ run : |
193+ echo "IMAGE_NAME=${GITHUB_REPOSITORY#$GITHUB_REPOSITORY_OWNER/}" >> $GITHUB_ENV
194+
195+ - name : Download digests
196+ uses : actions/download-artifact@v4
197+ with :
198+ path : ${{ runner.temp }}/digests/${{ matrix.docker_target }}
199+ pattern : digests-*
200+ merge-multiple : true
84201
85202 # Install the cosign tool
86203 # https://github.com/sigstore/cosign-installer
@@ -115,20 +232,15 @@ jobs:
115232 type=raw,value={{branch}}-latest
116233 type=raw,value={{branch}}-{{date 'YYYYMMDDHHmmss'}}
117234
118- # Build and push Docker image with Buildx
119- # https://github.com/docker/build-push-action
120- - name : Build and push production image
121- id : build-and-push
122- uses : docker/build-push-action@v6.15.0
123- with :
124- context : .
125- target : ${{ matrix.docker_target }}
126- platforms : linux/amd64,linux/arm64
127- push : true
128- tags : ${{ steps.meta.outputs.tags }}
129- labels : ${{ steps.meta.outputs.labels }}
130- cache-from : type=gha
131- cache-to : type=gha,mode=max
235+ - name : Create manifest list and push
236+ working-directory : ${{ runner.temp }}/digests/${{ matrix.docker_target }}
237+ run : |
238+ docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
239+ $(printf '${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-${{ matrix.docker_target }}@sha256:%s ' *)
240+
241+ - name : Inspect image
242+ run : |
243+ docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}/${{ env.IMAGE_NAME }}-${{ matrix.docker_target }}:${{ steps.meta.outputs.version }}
132244
133245 # TODO: Implement signature using generated key: https://docs.sigstore.dev/signing/quickstart/#signing-with-a-generated-key
134246
@@ -141,12 +253,11 @@ jobs:
141253 env :
142254 # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
143255 TAGS : ${{ steps.meta.outputs.tags }}
144- DIGEST : ${{ steps.build-and-push.outputs.digest }}
145256 # This step uses the identity token to provision an ephemeral certificate
146257 # against the sigstore community Fulcio instance.
147258 run : |
148259 images=""
149260 for tag in ${TAGS}; do
150- images+="${tag}@${DIGEST} "
261+ images+="${tag}@$(docker buildx imagetools inspect --format '{{json .Manifest.Digest}}' ${tag} | xargs) "
151262 done
152263 cosign sign --yes ${images}
0 commit comments