Skip to content

Commit 44df5f2

Browse files
committed
Docker: distribute build across multiple runners
1 parent e35f6c0 commit 44df5f2

File tree

2 files changed

+198
-32
lines changed

2 files changed

+198
-32
lines changed
Lines changed: 195 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,234 @@
1+
#
2+
# Based on:
3+
#
4+
# Docker docs: Distribute build across multiple runners
5+
# https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
6+
#
7+
18
name: Upload Docker images to GitHub Container Registry (ghcr.io)
29

310
on:
11+
release:
12+
types:
13+
- released
14+
415
push:
5-
branches: [ master, main ]
6-
tags: [ 'v*' ]
16+
branches:
17+
- master
18+
- main
19+
720
pull_request:
8-
branches: [ master, main ]
21+
branches:
22+
- master
23+
- main
24+
25+
workflow_dispatch:
26+
inputs:
27+
ref:
28+
description: Git tag to push the image
29+
required: true
30+
type: string
931

1032
jobs:
11-
docker:
12-
name: Build images
33+
prepare:
34+
name: Prepare
35+
runs-on: ubuntu-latest
36+
outputs:
37+
github_repository: ${{ steps.vars.outputs.github_repository }}
38+
publish_image: ${{ steps.vars.outputs.publish_image }}
39+
semver_value: ${{ steps.vars.outputs.semver_value }}
40+
steps:
41+
- id: vars
42+
name: Prepare outputs
43+
run: |
44+
function prepend() { while read line; do echo "${1}${line}"; done; }
45+
readonly NOTICE_VAR='::notice title=Setting variable::'
46+
47+
github_repository=${{ github.repository }}
48+
echo "github_repository=${github_repository,,}" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"
49+
50+
if [ "${{ github.event_name }}" = "release" ]; then
51+
echo "publish_image=true" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"
52+
elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
53+
echo "publish_image=true" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"
54+
echo "semver_value=,value=${{ inputs.ref }}" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"
55+
fi
56+
57+
build:
58+
name: Build image
59+
if: github.event_name == 'pull_request'
1360
runs-on: ubuntu-latest
61+
needs:
62+
- prepare
1463
steps:
1564
- name: Check out code
1665
uses: actions/checkout@v4
17-
- name: Set up QEMU
18-
if: github.event_name != 'pull_request'
19-
uses: docker/setup-qemu-action@v3
2066
with:
21-
platforms: arm,arm64
22-
cache-image: false
67+
fetch-tags: true
68+
69+
- name: Docker meta
70+
id: meta
71+
uses: docker/metadata-action@v5
72+
with:
73+
images: ghcr.io/${{ github.repository }}
74+
2375
- name: Set up Docker Buildx
2476
uses: docker/setup-buildx-action@v3
77+
78+
- name: Build
79+
uses: docker/build-push-action@v6
80+
with:
81+
context: .
82+
platforms: linux/amd64
83+
push: false
84+
tags: ${{ steps.meta.outputs.tags }}
85+
labels: ${{ steps.meta.outputs.labels }}
86+
annotations: ${{ steps.meta.outputs.annotations }}
87+
88+
mbuild:
89+
name: Build image
90+
needs:
91+
- prepare
92+
if: github.event_name != 'pull_request'
93+
runs-on: ubuntu-latest
94+
strategy:
95+
fail-fast: false
96+
matrix:
97+
platform:
98+
- platform: linux/amd64
99+
- platform: linux/arm64
100+
qemu: arm64
101+
- platform: linux/arm/v7
102+
qemu: arm
103+
- platform: linux/arm/v6
104+
qemu: arm
105+
steps:
106+
- name: Prepare
107+
id: prepare
108+
run: |
109+
platform=${{ matrix.platform.platform }}
110+
echo "platform_pair=${platform//\//-}" | tee -a $GITHUB_OUTPUT
111+
112+
- name: Check out code
113+
if: github.event_name == 'workflow_dispatch'
114+
uses: actions/checkout@v4
115+
with:
116+
ref: ${{ inputs.ref }}
117+
fetch-tags: true
118+
119+
- name: Check out code
120+
if: github.event_name != 'workflow_dispatch'
121+
uses: actions/checkout@v4
122+
with:
123+
fetch-tags: true
124+
25125
- name: Docker meta
26126
id: meta
27127
uses: docker/metadata-action@v5
28128
with:
29129
images: ghcr.io/${{ github.repository }}
30-
# create latest tag for branch events
31-
flavor: |
32-
latest=${{ github.event_name == 'push' && github.ref_type == 'branch' }}
33-
tags: |
34-
type=ref,event=branch
35-
type=ref,event=pr
36-
type=semver,pattern={{version}}
37-
type=semver,pattern={{major}}.{{minor}}
38-
type=semver,pattern={{major}}.{{minor}}.{{patch}}
39-
env:
40-
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
130+
131+
- name: Set up QEMU
132+
uses: docker/setup-qemu-action@v3
133+
if: ${{ matrix.platform.qemu }}
134+
with:
135+
platforms: ${{ matrix.platform.qemu }}
136+
cache-image: false
137+
138+
- name: Set up Docker Buildx
139+
uses: docker/setup-buildx-action@v3
140+
41141
- name: Login to GitHub Container Registry
42-
if: github.event_name != 'pull_request'
142+
if: needs.prepare.outputs.publish_image
43143
uses: docker/login-action@v3
44144
with:
45145
registry: ghcr.io
46146
username: ${{ github.actor }}
47147
password: ${{ secrets.GITHUB_TOKEN }}
148+
48149
- name: Build
49-
if: github.event_name == 'pull_request'
150+
if: ${{ ! needs.prepare.outputs.publish_image }}
50151
uses: docker/build-push-action@v6
51152
with:
52153
context: .
53-
platforms: linux/amd64
154+
platforms: ${{ matrix.platform.platform }}
54155
push: false
55156
tags: ${{ steps.meta.outputs.tags }}
56157
labels: ${{ steps.meta.outputs.labels }}
57158
annotations: ${{ steps.meta.outputs.annotations }}
159+
58160
- name: Build and push
59-
if: github.event_name != 'pull_request'
161+
if: needs.prepare.outputs.publish_image
60162
uses: docker/build-push-action@v6
163+
id: build
61164
with:
62165
context: .
63-
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
64-
push: true
65-
tags: ${{ steps.meta.outputs.tags }}
166+
platforms: ${{ matrix.platform.platform }}
66167
labels: ${{ steps.meta.outputs.labels }}
67168
annotations: ${{ steps.meta.outputs.annotations }}
68-
cache-from: type=gha
69-
cache-to: type=gha,mode=max
169+
outputs: type=image,"name=ghcr.io/${{ needs.prepare.outputs.github_repository }}",push-by-digest=true,name-canonical=true,push=true
170+
171+
- name: Export digest
172+
if: needs.prepare.outputs.publish_image
173+
run: |
174+
mkdir -p ${{ runner.temp }}/digests
175+
digest='${{ steps.build.outputs.digest }}'
176+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
177+
178+
- name: Upload digest
179+
if: needs.prepare.outputs.publish_image
180+
uses: actions/upload-artifact@v4
181+
with:
182+
name: digests-${{ steps.prepare.outputs.platform_pair }}
183+
path: ${{ runner.temp }}/digests/*
184+
if-no-files-found: error
185+
retention-days: 1
186+
compression-level: 0
187+
188+
merge:
189+
name: Merge images
190+
runs-on: ubuntu-latest
191+
needs:
192+
- prepare
193+
- mbuild
194+
if: needs.prepare.outputs.publish_image
195+
steps:
196+
- name: Download digests
197+
uses: actions/download-artifact@v4
198+
with:
199+
path: ${{ runner.temp }}/digests
200+
pattern: digests-*
201+
merge-multiple: true
202+
203+
- name: Login to GHCR
204+
uses: docker/login-action@v3
205+
with:
206+
registry: ghcr.io
207+
username: ${{ github.actor }}
208+
password: ${{ secrets.GITHUB_TOKEN }}
209+
210+
- name: Set up Docker Buildx
211+
uses: docker/setup-buildx-action@v3
212+
213+
- name: Docker meta
214+
id: meta
215+
uses: docker/metadata-action@v5
216+
with:
217+
images: ghcr.io/${{ github.repository }}
218+
flavor: |
219+
latest=${{ github.event_name == 'workflow_dispatch' && 'false' || 'auto' }}
220+
tags: |
221+
type=semver,pattern={{version}}${{ needs.prepare.outputs.semver_value }}
222+
type=semver,pattern={{major}}.{{minor}}${{ needs.prepare.outputs.semver_value }}
223+
type=semver,pattern={{major}}.{{minor}}.{{patch}}${{ needs.prepare.outputs.semver_value }}
224+
225+
- name: Create manifest list and push
226+
working-directory: ${{ runner.temp }}/digests
227+
run: |
228+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
229+
$(printf 'ghcr.io/${{ needs.prepare.outputs.github_repository }}@sha256:%s ' *)
230+
231+
- name: Inspect image
232+
run: docker buildx imagetools inspect ghcr.io/${{ needs.prepare.outputs.github_repository }}:${{ steps.meta.outputs.version }}
233+
234+

Dockerfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
FROM golang:alpine AS build
22
ARG TARGETARCH
3+
ARG GOCACHE=/tmp
34

45
RUN apk add --update git make bash gcc musl-dev
56

67
USER nobody:nogroup
78
WORKDIR /usr/local/src/go-carbon
89
COPY --chown=nobody:nogroup . .
910
RUN --network=none make clean
10-
RUN --mount=type=cache,id=go-cache,target=/.cache,sharing=locked,uid=65534,gid=65534 make go-carbon
11-
RUN --mount=type=cache,id=go-cache,target=/.cache,sharing=locked,uid=65534,gid=65534 <<EOT
11+
RUN make go-carbon
12+
RUN <<EOT
1213
if [ "${TARGETARCH:-unknown}" = "amd64" ]; then
1314
make run-test COMMAND="test -race"
1415
else

0 commit comments

Comments
 (0)