11name : Docker Bake Build and Push
2-
2+ # This is mostly taken from
3+ # here: https://docs.docker.com/build/ci/github-actions/multi-platform/#with-bake
34on :
45 push :
56 branches : [ main ]
1112 REGISTRY : ghcr.io/nersc/interactem
1213
1314jobs :
14- bake-platform :
15+ prepare :
16+ runs-on : ubuntu-latest
17+ permissions :
18+ contents : read
19+ outputs :
20+ tag : ${{ steps.meta.outputs.tag }}
21+ services : ${{ steps.services.outputs.services }}
22+ all-images : ${{ steps.services.outputs.all-images }}
23+ steps :
24+ - name : Checkout
25+ uses : actions/checkout@v4
26+ with :
27+ submodules : false
28+
29+ - name : Set up Docker Buildx
30+ uses : docker/setup-buildx-action@v3
31+
32+ - name : Extract metadata
33+ id : meta
34+ run : |
35+ TAG=$(git rev-parse --short=6 HEAD)
36+ echo "tag=${TAG}" >> $GITHUB_OUTPUT
37+ echo "Generated tag: ${TAG}"
38+
39+ - name : Define services
40+ id : services
41+ run : |
42+ # Extract services from the prod group in docker-bake.hcl
43+ SERVICES=$(docker buildx bake prod --print | jq -cr '[.group.prod.targets[]]')
44+ echo "Services found: ${SERVICES}"
45+ echo "services=${SERVICES}" >> $GITHUB_OUTPUT
46+
47+ # Create combined list including base image for merge-manifests
48+ ALL_IMAGES=$(echo ${SERVICES} | jq -c '. + ["interactem"]')
49+ echo "All images (including base): ${ALL_IMAGES}"
50+ echo "all-images=${ALL_IMAGES}" >> $GITHUB_OUTPUT
51+ working-directory : ./docker
52+
53+ build-base :
54+ needs : prepare
1555 strategy :
1656 matrix :
1757 include :
@@ -41,41 +81,46 @@ jobs:
4181 username : ${{ github.actor }}
4282 password : ${{ secrets.GHCR_PAT }}
4383
44- - name : Extract metadata
45- id : meta
46- run : |
47- # Generate tag from git commit hash (short)
48- TAG=$(git rev-parse --short=6 HEAD)
49- echo "tag=${TAG}" >> $GITHUB_OUTPUT
50- echo "Generated tag: ${TAG}"
51-
52- - name : Build ${{ matrix.platform }} base image
84+ - name : Build and push base image by digest
85+ id : bake
5386 uses : docker/bake-action@v6
5487 with :
5588 source : .
5689 files : ./docker/docker-bake.hcl
5790 targets : base
5891 set : |
5992 *.platform=${{ matrix.docker-platform }}
93+ ${{ github.event_name != 'pull_request' && '*.output=type=image,push-by-digest=true,name-canonical=true,push=true' || '' }}
94+ *.tags=${{ env.REGISTRY }}/interactem
6095 env :
61- TAG : ${{ steps.meta .outputs.tag }}
96+ TAG : ${{ needs.prepare .outputs.tag }}
6297 CACHE_PLATFORM : ${{ matrix.platform }}
6398
64- - name : Build ${{ matrix.platform }} images
65- uses : docker/bake-action@v6
99+ - name : Export digest
100+ if : github.event_name != 'pull_request'
101+ run : |
102+ mkdir -p /tmp/digests
103+ digest="${{ fromJSON(steps.bake.outputs.metadata).base['containerimage.digest'] }}"
104+ touch "/tmp/digests/${digest#sha256:}"
105+
106+ - name : Upload digest
107+ if : github.event_name != 'pull_request'
108+ uses : actions/upload-artifact@v4
66109 with :
67- source : .
68- files : ./docker/docker-bake.hcl
69- targets : prod
70- set : |
71- *.platform=${{ matrix.docker-platform }}
72- env :
73- TAG : ${{ steps.meta.outputs.tag }}
74- CACHE_PLATFORM : ${{ matrix.platform }}
110+ name : interactem-digest-${{ matrix.platform }}
111+ path : /tmp/digests/*
112+ if-no-files-found : error
113+ retention-days : 1
75114
76- bake-push :
77- needs : bake-platform
78- runs-on : ubuntu-24.04-arm
115+ build-services :
116+ needs : [prepare, build-base]
117+ strategy :
118+ matrix :
119+ platform :
120+ - { name: amd64, runner: ubuntu-24.04, docker: linux/amd64 }
121+ - { name: arm64, runner: ubuntu-24.04-arm, docker: linux/arm64 }
122+ service : ${{ fromJson(needs.prepare.outputs.services) }}
123+ runs-on : ${{ matrix.platform.runner }}
79124 permissions :
80125 contents : read
81126 packages : write
@@ -95,22 +140,74 @@ jobs:
95140 username : ${{ github.actor }}
96141 password : ${{ secrets.GHCR_PAT }}
97142
98- - name : Extract metadata
99- id : meta
100- run : |
101- # Generate tag from git commit hash (short)
102- TAG=$(git rev-parse --short=6 HEAD)
103- echo "tag=${TAG}" >> $GITHUB_OUTPUT
104- echo "Generated tag: ${TAG}"
105-
106- - name : Build and push multiplatform images
143+ - name : Build and push ${{ matrix.service }} by digest
144+ id : bake
107145 uses : docker/bake-action@v6
108146 with :
109147 source : .
110148 files : ./docker/docker-bake.hcl
111- push : ${{ github.event_name != 'pull_request' }}
112- targets : prod
149+ targets : ${{ matrix.service }}
113150 set : |
114- *.cache-to=
151+ *.platform=${{ matrix.platform.docker }}
152+ ${{ github.event_name != 'pull_request' && '*.output=type=image,push-by-digest=true,name-canonical=true,push=true' || '' }}
153+ *.tags=${{ env.REGISTRY }}/${{ matrix.service }}
115154 env :
116- TAG : ${{ steps.meta.outputs.tag }}
155+ TAG : ${{ needs.prepare.outputs.tag }}
156+ CACHE_PLATFORM : ${{ matrix.platform.name }}
157+
158+ - name : Export digest
159+ if : github.event_name != 'pull_request'
160+ run : |
161+ mkdir -p /tmp/digests
162+ digest="${{ fromJSON(steps.bake.outputs.metadata)[matrix.service]['containerimage.digest'] }}"
163+ touch "/tmp/digests/${digest#sha256:}"
164+
165+ - name : Upload digest
166+ if : github.event_name != 'pull_request'
167+ uses : actions/upload-artifact@v4
168+ with :
169+ name : ${{ matrix.service }}-digest-${{ matrix.platform.name }}
170+ path : /tmp/digests/*
171+ if-no-files-found : error
172+ retention-days : 1
173+
174+ merge-manifests :
175+ if : github.event_name != 'pull_request'
176+ needs : [prepare, build-base, build-services]
177+ runs-on : ubuntu-latest
178+ permissions :
179+ contents : read
180+ packages : write
181+ strategy :
182+ matrix :
183+ service : ${{ fromJson(needs.prepare.outputs.all-images) }}
184+ steps :
185+ - name : Set up Docker Buildx
186+ uses : docker/setup-buildx-action@v3
187+
188+ - name : Login to GitHub Container Registry
189+ uses : docker/login-action@v3
190+ with :
191+ registry : ${{ env.REGISTRY }}
192+ username : ${{ github.actor }}
193+ password : ${{ secrets.GHCR_PAT }}
194+
195+ - name : Download digests
196+ uses : actions/download-artifact@v4
197+ with :
198+ path : /tmp/digests
199+ pattern : ${{ matrix.service }}-digest-*
200+ merge-multiple : true
201+
202+ - name : Create manifest list and push
203+ working-directory : /tmp/digests
204+ run : |
205+ # Create manifest
206+ docker buildx imagetools create \
207+ -t ${{ env.REGISTRY }}/${{ matrix.service }}:${{ needs.prepare.outputs.tag }} \
208+ -t ${{ env.REGISTRY }}/${{ matrix.service }}:latest \
209+ $(printf '${{ env.REGISTRY }}/${{ matrix.service }}@sha256:%s ' *)
210+
211+ - name : Inspect image
212+ run : |
213+ docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ matrix.service }}:${{ needs.prepare.outputs.tag }}
0 commit comments