Skip to content

Commit 41a814f

Browse files
committed
fix: Move docker builds to native platforms
The current Docker builds are taking an excessively long time to complete, currently over 6 hours causing GitHub Actions to time out. We believe it's because internally it's using virtualization to build the arm64 version of the container. To attempt to alleviate this, this PR uses a GitHub Actions matrix to separate the builds into runners on their own native platforms. The hope is that the lack of needing to virtualize will speed up the overall time.
1 parent 90f2e0c commit 41a814f

File tree

1 file changed

+97
-11
lines changed

1 file changed

+97
-11
lines changed

.github/workflows/docker-publish.yml

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,122 @@ env:
1111

1212
jobs:
1313
build:
14-
runs-on: ubuntu-latest
14+
# We use a matrix to run each docker container build for a specific platform on it's own native runner.
15+
# This avoids using virtualization and massively speeds up builds.
16+
strategy:
17+
matrix:
18+
platform: [linux/amd64, linux/arm64]
19+
include:
20+
- platform: linux/amd64
21+
runner: ubuntu-latest
22+
- platform: linux/arm64
23+
runner: ubuntu-24.04-arm
24+
25+
26+
name: Build ${{ matrix.platform }}
27+
runs-on: ${{ matrix.runner }}
1528
steps:
16-
- name: Checkout
29+
- name: Code checkout
1730
uses: actions/checkout@v4
31+
1832
- name: Set up Docker Buildx
1933
uses: docker/setup-buildx-action@v3
34+
2035
- name: Get source version
21-
run: echo "SOURCE_VERSION=$(grep VERSION compose.yaml | awk {'print $2'})" >> "$GITHUB_ENV"
36+
run: echo "SOURCE_VERSION=$(grep VERSION compose.yaml | awk '{print $2}')" >> "$GITHUB_ENV"
37+
2238
- name: Docker meta
2339
id: meta
2440
uses: docker/metadata-action@v5
2541
with:
2642
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
43+
flavor: |
44+
latest=false
2745
tags: |
28-
type=ref,event=branch
29-
type=semver,pattern={{version}}
30-
- name: Login to registry ${{ env.REGISTRY }}
46+
type=ref,event=branch,pattern={{branch}}
47+
type=semver,pattern={{version}},value=${{ env.SOURCE_VERSION }}
48+
49+
- name: Derive arch-suffixed tags as output
50+
id: archtags
51+
run: |
52+
set -euo pipefail
53+
ARCH="$(echo '${{ matrix.platform }}' | cut -d/ -f2)"
54+
T="$(printf '%s\n' "${{ steps.meta.outputs.tags }}" | sed "s/$/-${ARCH}/")"
55+
{
56+
echo 'tags<<EOF'
57+
echo "$T"
58+
echo 'EOF'
59+
echo "arch=$ARCH"
60+
} >> "$GITHUB_OUTPUT"
61+
62+
- name: Login to ${{ env.REGISTRY }}
3163
if: github.event_name != 'pull_request'
3264
uses: docker/login-action@v3
3365
with:
3466
registry: ${{ env.REGISTRY }}
3567
username: ${{ secrets.DOCKER_USERNAME }}
3668
password: ${{ secrets.DOCKER_PASSWORD }}
37-
- name: Build and push
38-
uses: docker/build-push-action@v5
69+
70+
- name: Build & push ${{ matrix.platform }}
71+
uses: docker/build-push-action@v6
3972
with:
4073
context: .
74+
platforms: ${{ matrix.platform }}
75+
push: ${{ github.event_name != 'pull_request' }}
4176
build-args: |
4277
VERSION=${{ env.SOURCE_VERSION }}
43-
platforms: linux/amd64,linux/arm64
44-
push: ${{ github.event_name != 'pull_request' }}
45-
tags: ${{ steps.meta.outputs.tags }}
78+
tags: ${{ steps.archtags.outputs.tags }}
4679
labels: ${{ steps.meta.outputs.labels }}
80+
81+
# In order to have a single tag that covers both archtectures we run one more job to create a multi-arch manifest
82+
# under a single tag.
83+
manifest:
84+
name: Create multi-arch manifest
85+
runs-on: ubuntu-latest
86+
needs: build
87+
steps:
88+
- name: Code checkout
89+
uses: actions/checkout@v4
90+
91+
- name: Get source version
92+
run: echo "SOURCE_VERSION=$(grep VERSION compose.yaml | awk '{print $2}')" >> "$GITHUB_ENV"
93+
94+
- name: Docker meta (same base tags)
95+
id: meta
96+
uses: docker/metadata-action@v5
97+
with:
98+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
99+
flavor: |
100+
latest=false
101+
tags: |
102+
type=ref,event=branch,pattern={{branch}}
103+
type=semver,pattern={{version}},value=${{ env.SOURCE_VERSION }}
104+
105+
- name: Login
106+
uses: docker/login-action@v3
107+
with:
108+
registry: ${{ env.REGISTRY }}
109+
username: ${{ secrets.DOCKER_USERNAME }}
110+
password: ${{ secrets.DOCKER_PASSWORD }}
111+
112+
- name: Create manifest for each base tag
113+
if: github.event_name != 'pull_request'
114+
run: |
115+
set -euo pipefail
116+
while IFS= read -r BASE; do
117+
echo "Preparing manifest for $BASE"
118+
AMD="${BASE}-amd64"
119+
ARM="${BASE}-arm64"
120+
# Skip if one arch is missing
121+
docker buildx imagetools inspect "$AMD"
122+
docker buildx imagetools inspect "$ARM"
123+
124+
docker buildx imagetools create \
125+
--tag "$BASE" \
126+
"$AMD" \
127+
"$ARM"
128+
129+
echo "OK: $BASE now points to $AMD + $ARM"
130+
done <<'EOF'
131+
${{ steps.meta.outputs.tags }}
132+
EOF

0 commit comments

Comments
 (0)