Skip to content
This repository was archived by the owner on Apr 4, 2026. It is now read-only.

Commit 6abed23

Browse files
committed
ci: add multi-arch build workflow for ARM64 support
Add a GitHub Actions workflow that builds and publishes multi-arch Docker images (linux/amd64 + linux/arm64) to GHCR using native runners for each platform. The workflow: - Builds both Debian and Alpine variants of 17-3.5 - Uses native ubuntu-24.04 (amd64) and ubuntu-24.04-arm (arm64) runners to avoid QEMU emulation during builds - Pushes per-architecture images by digest - Creates and pushes multi-arch manifests combining both platforms This enables native ARM64/Apple Silicon support for PostGIS Docker images, eliminating the Rosetta/QEMU emulation penalty on Apple Silicon Macs and AWS Graviton instances. Refs: postgis#216, postgis#387
1 parent 3e05db8 commit 6abed23

1 file changed

Lines changed: 179 additions & 0 deletions

File tree

.github/workflows/multi-arch.yml

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
name: Multi-arch Build and Push
2+
3+
on:
4+
push:
5+
branches: [multi-arch-arm64]
6+
workflow_dispatch:
7+
inputs:
8+
version:
9+
description: 'PostgreSQL-PostGIS version (e.g., 17-3.5)'
10+
required: false
11+
default: '17-3.5'
12+
13+
env:
14+
REGISTRY: ghcr.io
15+
IMAGE_NAME: ${{ github.repository }}
16+
17+
jobs:
18+
build:
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
include:
23+
# Debian variant
24+
- runner: ubuntu-24.04
25+
platform: linux/amd64
26+
version: '17-3.5'
27+
variant: default
28+
- runner: ubuntu-24.04-arm
29+
platform: linux/arm64
30+
version: '17-3.5'
31+
variant: default
32+
# Alpine variant
33+
- runner: ubuntu-24.04
34+
platform: linux/amd64
35+
version: '17-3.5'
36+
variant: alpine
37+
- runner: ubuntu-24.04-arm
38+
platform: linux/arm64
39+
version: '17-3.5'
40+
variant: alpine
41+
42+
name: ${{ matrix.version }}-${{ matrix.variant }} (${{ matrix.platform }})
43+
runs-on: ${{ matrix.runner }}
44+
45+
permissions:
46+
contents: read
47+
packages: write
48+
49+
outputs:
50+
# We use artifact exchange for digests instead of outputs
51+
# because matrix jobs can't cleanly merge outputs
52+
image-name: ${{ steps.meta.outputs.image-name }}
53+
54+
steps:
55+
- name: Checkout
56+
uses: actions/checkout@v4
57+
58+
- name: Set up Docker Buildx
59+
uses: docker/setup-buildx-action@v3
60+
61+
- name: Log in to GHCR
62+
uses: docker/login-action@v3
63+
with:
64+
registry: ${{ env.REGISTRY }}
65+
username: ${{ github.actor }}
66+
password: ${{ secrets.GITHUB_TOKEN }}
67+
68+
- name: Determine image metadata
69+
id: meta
70+
run: |
71+
VERSION="${{ matrix.version }}"
72+
VARIANT="${{ matrix.variant }}"
73+
REPO="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
74+
# Lowercase the image name (GHCR requirement)
75+
REPO=$(echo "$REPO" | tr '[:upper:]' '[:lower:]')
76+
77+
if [ "$VARIANT" = "alpine" ]; then
78+
TAG="${VERSION}-alpine"
79+
else
80+
TAG="${VERSION}"
81+
fi
82+
83+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
84+
echo "repo=${REPO}" >> "$GITHUB_OUTPUT"
85+
echo "image-name=${REPO}:${TAG}" >> "$GITHUB_OUTPUT"
86+
echo "dockerfile-dir=${VERSION}$([ "$VARIANT" = "alpine" ] && echo "/alpine" || echo "")" >> "$GITHUB_OUTPUT"
87+
88+
- name: Build and push by digest
89+
id: build
90+
uses: docker/build-push-action@v6
91+
with:
92+
context: ${{ steps.meta.outputs.dockerfile-dir }}
93+
platforms: ${{ matrix.platform }}
94+
push: true
95+
outputs: type=image,name=${{ steps.meta.outputs.repo }},push-by-digest=true,name-canonical=true
96+
cache-from: type=gha,scope=${{ matrix.version }}-${{ matrix.variant }}-${{ matrix.platform }}
97+
cache-to: type=gha,mode=max,scope=${{ matrix.version }}-${{ matrix.variant }}-${{ matrix.platform }}
98+
99+
- name: Export digest
100+
run: |
101+
mkdir -p /tmp/digests/${{ matrix.variant }}
102+
digest="${{ steps.build.outputs.digest }}"
103+
touch "/tmp/digests/${{ matrix.variant }}/${digest#sha256:}"
104+
echo "Exported digest: ${digest}"
105+
106+
- name: Upload digest
107+
uses: actions/upload-artifact@v4
108+
with:
109+
name: digests-${{ matrix.version }}-${{ matrix.variant }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
110+
path: /tmp/digests/${{ matrix.variant }}/
111+
if-no-files-found: error
112+
retention-days: 1
113+
114+
# Create and push multi-arch manifests
115+
manifest:
116+
needs: build
117+
runs-on: ubuntu-24.04
118+
permissions:
119+
contents: read
120+
packages: write
121+
122+
strategy:
123+
matrix:
124+
include:
125+
- version: '17-3.5'
126+
variant: default
127+
tag: '17-3.5'
128+
- version: '17-3.5'
129+
variant: alpine
130+
tag: '17-3.5-alpine'
131+
132+
name: Manifest ${{ matrix.tag }}
133+
steps:
134+
- name: Log in to GHCR
135+
uses: docker/login-action@v3
136+
with:
137+
registry: ${{ env.REGISTRY }}
138+
username: ${{ github.actor }}
139+
password: ${{ secrets.GITHUB_TOKEN }}
140+
141+
- name: Download amd64 digest
142+
uses: actions/download-artifact@v4
143+
with:
144+
name: digests-${{ matrix.version }}-${{ matrix.variant }}-amd64
145+
path: /tmp/digests/
146+
147+
- name: Download arm64 digest
148+
uses: actions/download-artifact@v4
149+
with:
150+
name: digests-${{ matrix.version }}-${{ matrix.variant }}-arm64
151+
path: /tmp/digests/
152+
153+
- name: Set up Docker Buildx
154+
uses: docker/setup-buildx-action@v3
155+
156+
- name: Create and push manifest
157+
run: |
158+
REPO="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
159+
REPO=$(echo "$REPO" | tr '[:upper:]' '[:lower:]')
160+
TAG="${{ matrix.tag }}"
161+
162+
# Collect all digests
163+
DIGESTS=""
164+
for digest_file in /tmp/digests/*; do
165+
digest="sha256:$(basename $digest_file)"
166+
DIGESTS="${DIGESTS} ${REPO}@${digest}"
167+
done
168+
169+
echo "Creating manifest for ${REPO}:${TAG} from digests:${DIGESTS}"
170+
171+
docker buildx imagetools create \
172+
--tag "${REPO}:${TAG}" \
173+
${DIGESTS}
174+
175+
- name: Inspect manifest
176+
run: |
177+
REPO="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
178+
REPO=$(echo "$REPO" | tr '[:upper:]' '[:lower:]')
179+
docker buildx imagetools inspect "${REPO}:${{ matrix.tag }}"

0 commit comments

Comments
 (0)