Skip to content

Commit 403b825

Browse files
authored
fix: build arm64 base images natively (#77)
The multi-arch base image workflow was timing out in the emulated arm64 agents image build. Split each image into native amd64 and arm64 builds and merge their digests into the published tags afterward.
1 parent ac10564 commit 403b825

File tree

1 file changed

+302
-21
lines changed

1 file changed

+302
-21
lines changed

.github/workflows/base-image.yml

Lines changed: 302 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,243 @@ permissions:
1616
packages: write
1717

1818
jobs:
19-
build:
20-
runs-on: ubuntu-latest
19+
build-alpine:
20+
name: build (alpine, ${{ matrix.platform }})
21+
runs-on: ${{ matrix.runner }}
22+
env:
23+
IMAGE_NAME: alpine
24+
DOCKERFILE: images/Dockerfile.base-image
25+
REPOSITORY: ghcr.io/buildkite/cleanroom-base/alpine
2126
strategy:
2227
fail-fast: false
2328
matrix:
2429
include:
25-
- image_name: alpine
26-
dockerfile: images/Dockerfile.base-image
27-
repository: ghcr.io/buildkite/cleanroom-base/alpine
28-
- image_name: alpine-docker
29-
dockerfile: images/Dockerfile.base-image-docker
30-
repository: ghcr.io/buildkite/cleanroom-base/alpine-docker
31-
- image_name: alpine-agents
32-
dockerfile: images/Dockerfile.base-image-agents
33-
repository: ghcr.io/buildkite/cleanroom-base/alpine-agents
30+
- platform: linux/amd64
31+
platform_key: linux-amd64
32+
runner: ubuntu-24.04
33+
- platform: linux/arm64
34+
platform_key: linux-arm64
35+
runner: ubuntu-24.04-arm
36+
steps:
37+
- uses: actions/checkout@v4
38+
39+
- uses: docker/setup-buildx-action@v3
40+
41+
- uses: docker/login-action@v3
42+
with:
43+
registry: ghcr.io
44+
username: ${{ github.actor }}
45+
password: ${{ secrets.GITHUB_TOKEN }}
46+
47+
- uses: docker/build-push-action@v6
48+
id: build
49+
with:
50+
context: .
51+
file: ${{ env.DOCKERFILE }}
52+
platforms: ${{ matrix.platform }}
53+
outputs: type=image,name=${{ env.REPOSITORY }},push-by-digest=true,name-canonical=true,push=true
54+
55+
- name: Export image digest
56+
run: |
57+
set -euo pipefail
58+
mkdir -p "$RUNNER_TEMP/digests"
59+
digest="${{ steps.build.outputs.digest }}"
60+
if [[ -z "$digest" ]]; then
61+
echo "build digest missing" >&2
62+
exit 1
63+
fi
64+
touch "$RUNNER_TEMP/digests/${digest#sha256:}"
65+
66+
- uses: actions/upload-artifact@v4
67+
with:
68+
name: digests-${{ env.IMAGE_NAME }}-${{ matrix.platform_key }}
69+
path: ${{ runner.temp }}/digests/*
70+
if-no-files-found: error
71+
retention-days: 1
72+
73+
merge-alpine:
74+
name: merge (alpine)
75+
runs-on: ubuntu-24.04
76+
needs: build-alpine
77+
env:
78+
IMAGE_NAME: alpine
79+
DOCKERFILE: images/Dockerfile.base-image
80+
REPOSITORY: ghcr.io/buildkite/cleanroom-base/alpine
81+
steps:
82+
- uses: actions/checkout@v4
83+
84+
- name: Compute base image tag
85+
id: meta
86+
run: |
87+
echo "base_tag=$(scripts/base-image-tag.sh '${{ env.IMAGE_NAME }}' '${{ env.DOCKERFILE }}')" >> "$GITHUB_OUTPUT"
88+
89+
- uses: actions/download-artifact@v4
90+
with:
91+
pattern: digests-${{ env.IMAGE_NAME }}-*
92+
path: ${{ runner.temp }}/digests
93+
merge-multiple: true
94+
95+
- uses: docker/setup-buildx-action@v3
96+
97+
- uses: docker/login-action@v3
98+
with:
99+
registry: ghcr.io
100+
username: ${{ github.actor }}
101+
password: ${{ secrets.GITHUB_TOKEN }}
102+
103+
- name: Create manifest list
104+
working-directory: ${{ runner.temp }}/digests
105+
env:
106+
BASE_TAG: ${{ steps.meta.outputs.base_tag }}
107+
run: |
108+
set -euo pipefail
109+
shopt -s nullglob
110+
digests=(*)
111+
if [[ ${#digests[@]} -eq 0 ]]; then
112+
echo "no digests downloaded" >&2
113+
exit 1
114+
fi
115+
refs=()
116+
for digest in "${digests[@]}"; do
117+
refs+=("${REPOSITORY}@sha256:${digest}")
118+
done
119+
docker buildx imagetools create \
120+
-t "${REPOSITORY}:latest" \
121+
-t "${REPOSITORY}:${BASE_TAG}" \
122+
-t "${REPOSITORY}:${GITHUB_SHA}" \
123+
"${refs[@]}"
124+
125+
- name: Inspect manifest list
126+
run: docker buildx imagetools inspect "${REPOSITORY}:latest"
127+
128+
build-alpine-docker:
129+
name: build (alpine-docker, ${{ matrix.platform }})
130+
runs-on: ${{ matrix.runner }}
131+
env:
132+
IMAGE_NAME: alpine-docker
133+
DOCKERFILE: images/Dockerfile.base-image-docker
134+
REPOSITORY: ghcr.io/buildkite/cleanroom-base/alpine-docker
135+
strategy:
136+
fail-fast: false
137+
matrix:
138+
include:
139+
- platform: linux/amd64
140+
platform_key: linux-amd64
141+
runner: ubuntu-24.04
142+
- platform: linux/arm64
143+
platform_key: linux-arm64
144+
runner: ubuntu-24.04-arm
145+
steps:
146+
- uses: actions/checkout@v4
147+
148+
- uses: docker/setup-buildx-action@v3
149+
150+
- uses: docker/login-action@v3
151+
with:
152+
registry: ghcr.io
153+
username: ${{ github.actor }}
154+
password: ${{ secrets.GITHUB_TOKEN }}
155+
156+
- uses: docker/build-push-action@v6
157+
id: build
158+
with:
159+
context: .
160+
file: ${{ env.DOCKERFILE }}
161+
platforms: ${{ matrix.platform }}
162+
outputs: type=image,name=${{ env.REPOSITORY }},push-by-digest=true,name-canonical=true,push=true
163+
164+
- name: Export image digest
165+
run: |
166+
set -euo pipefail
167+
mkdir -p "$RUNNER_TEMP/digests"
168+
digest="${{ steps.build.outputs.digest }}"
169+
if [[ -z "$digest" ]]; then
170+
echo "build digest missing" >&2
171+
exit 1
172+
fi
173+
touch "$RUNNER_TEMP/digests/${digest#sha256:}"
174+
175+
- uses: actions/upload-artifact@v4
176+
with:
177+
name: digests-${{ env.IMAGE_NAME }}-${{ matrix.platform_key }}
178+
path: ${{ runner.temp }}/digests/*
179+
if-no-files-found: error
180+
retention-days: 1
181+
182+
merge-alpine-docker:
183+
name: merge (alpine-docker)
184+
runs-on: ubuntu-24.04
185+
needs: build-alpine-docker
186+
env:
187+
IMAGE_NAME: alpine-docker
188+
DOCKERFILE: images/Dockerfile.base-image-docker
189+
REPOSITORY: ghcr.io/buildkite/cleanroom-base/alpine-docker
34190
steps:
35191
- uses: actions/checkout@v4
36192

37193
- name: Compute base image tag
38194
id: meta
39195
run: |
40-
echo "base_tag=$(scripts/base-image-tag.sh '${{ matrix.image_name }}' '${{ matrix.dockerfile }}')" >> "$GITHUB_OUTPUT"
196+
echo "base_tag=$(scripts/base-image-tag.sh '${{ env.IMAGE_NAME }}' '${{ env.DOCKERFILE }}')" >> "$GITHUB_OUTPUT"
197+
198+
- uses: actions/download-artifact@v4
199+
with:
200+
pattern: digests-${{ env.IMAGE_NAME }}-*
201+
path: ${{ runner.temp }}/digests
202+
merge-multiple: true
203+
204+
- uses: docker/setup-buildx-action@v3
41205

42-
- uses: docker/setup-qemu-action@v3
206+
- uses: docker/login-action@v3
43207
with:
44-
platforms: amd64,arm64
208+
registry: ghcr.io
209+
username: ${{ github.actor }}
210+
password: ${{ secrets.GITHUB_TOKEN }}
211+
212+
- name: Create manifest list
213+
working-directory: ${{ runner.temp }}/digests
214+
env:
215+
BASE_TAG: ${{ steps.meta.outputs.base_tag }}
216+
run: |
217+
set -euo pipefail
218+
shopt -s nullglob
219+
digests=(*)
220+
if [[ ${#digests[@]} -eq 0 ]]; then
221+
echo "no digests downloaded" >&2
222+
exit 1
223+
fi
224+
refs=()
225+
for digest in "${digests[@]}"; do
226+
refs+=("${REPOSITORY}@sha256:${digest}")
227+
done
228+
docker buildx imagetools create \
229+
-t "${REPOSITORY}:latest" \
230+
-t "${REPOSITORY}:${BASE_TAG}" \
231+
-t "${REPOSITORY}:${GITHUB_SHA}" \
232+
"${refs[@]}"
233+
234+
- name: Inspect manifest list
235+
run: docker buildx imagetools inspect "${REPOSITORY}:latest"
236+
237+
build-alpine-agents:
238+
name: build (alpine-agents, ${{ matrix.platform }})
239+
runs-on: ${{ matrix.runner }}
240+
env:
241+
IMAGE_NAME: alpine-agents
242+
DOCKERFILE: images/Dockerfile.base-image-agents
243+
REPOSITORY: ghcr.io/buildkite/cleanroom-base/alpine-agents
244+
strategy:
245+
fail-fast: false
246+
matrix:
247+
include:
248+
- platform: linux/amd64
249+
platform_key: linux-amd64
250+
runner: ubuntu-24.04
251+
- platform: linux/arm64
252+
platform_key: linux-arm64
253+
runner: ubuntu-24.04-arm
254+
steps:
255+
- uses: actions/checkout@v4
45256

46257
- uses: docker/setup-buildx-action@v3
47258

@@ -52,12 +263,82 @@ jobs:
52263
password: ${{ secrets.GITHUB_TOKEN }}
53264

54265
- uses: docker/build-push-action@v6
266+
id: build
55267
with:
56268
context: .
57-
file: ${{ matrix.dockerfile }}
58-
platforms: linux/amd64,linux/arm64
59-
push: true
60-
tags: |
61-
${{ matrix.repository }}:latest
62-
${{ matrix.repository }}:${{ steps.meta.outputs.base_tag }}
63-
${{ matrix.repository }}:${{ github.sha }}
269+
file: ${{ env.DOCKERFILE }}
270+
platforms: ${{ matrix.platform }}
271+
outputs: type=image,name=${{ env.REPOSITORY }},push-by-digest=true,name-canonical=true,push=true
272+
273+
- name: Export image digest
274+
run: |
275+
set -euo pipefail
276+
mkdir -p "$RUNNER_TEMP/digests"
277+
digest="${{ steps.build.outputs.digest }}"
278+
if [[ -z "$digest" ]]; then
279+
echo "build digest missing" >&2
280+
exit 1
281+
fi
282+
touch "$RUNNER_TEMP/digests/${digest#sha256:}"
283+
284+
- uses: actions/upload-artifact@v4
285+
with:
286+
name: digests-${{ env.IMAGE_NAME }}-${{ matrix.platform_key }}
287+
path: ${{ runner.temp }}/digests/*
288+
if-no-files-found: error
289+
retention-days: 1
290+
291+
merge-alpine-agents:
292+
name: merge (alpine-agents)
293+
runs-on: ubuntu-24.04
294+
needs: build-alpine-agents
295+
env:
296+
IMAGE_NAME: alpine-agents
297+
DOCKERFILE: images/Dockerfile.base-image-agents
298+
REPOSITORY: ghcr.io/buildkite/cleanroom-base/alpine-agents
299+
steps:
300+
- uses: actions/checkout@v4
301+
302+
- name: Compute base image tag
303+
id: meta
304+
run: |
305+
echo "base_tag=$(scripts/base-image-tag.sh '${{ env.IMAGE_NAME }}' '${{ env.DOCKERFILE }}')" >> "$GITHUB_OUTPUT"
306+
307+
- uses: actions/download-artifact@v4
308+
with:
309+
pattern: digests-${{ env.IMAGE_NAME }}-*
310+
path: ${{ runner.temp }}/digests
311+
merge-multiple: true
312+
313+
- uses: docker/setup-buildx-action@v3
314+
315+
- uses: docker/login-action@v3
316+
with:
317+
registry: ghcr.io
318+
username: ${{ github.actor }}
319+
password: ${{ secrets.GITHUB_TOKEN }}
320+
321+
- name: Create manifest list
322+
working-directory: ${{ runner.temp }}/digests
323+
env:
324+
BASE_TAG: ${{ steps.meta.outputs.base_tag }}
325+
run: |
326+
set -euo pipefail
327+
shopt -s nullglob
328+
digests=(*)
329+
if [[ ${#digests[@]} -eq 0 ]]; then
330+
echo "no digests downloaded" >&2
331+
exit 1
332+
fi
333+
refs=()
334+
for digest in "${digests[@]}"; do
335+
refs+=("${REPOSITORY}@sha256:${digest}")
336+
done
337+
docker buildx imagetools create \
338+
-t "${REPOSITORY}:latest" \
339+
-t "${REPOSITORY}:${BASE_TAG}" \
340+
-t "${REPOSITORY}:${GITHUB_SHA}" \
341+
"${refs[@]}"
342+
343+
- name: Inspect manifest list
344+
run: docker buildx imagetools inspect "${REPOSITORY}:latest"

0 commit comments

Comments
 (0)