Skip to content

Commit 6ac2016

Browse files
committed
Add multi-platforms support with buildx command
1 parent 7922e1f commit 6ac2016

File tree

5 files changed

+196
-16
lines changed

5 files changed

+196
-16
lines changed

.github/workflows/dockerimage.yml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,25 @@ jobs:
99
build:
1010
runs-on: ubuntu-latest
1111
steps:
12-
- uses: actions/checkout@v2
13-
- name: Build the latest Docker image
14-
run: make build
12+
- uses: actions/checkout@v4
13+
14+
- name: Set up QEMU
15+
uses: docker/setup-qemu-action@v3
16+
17+
- name: Set up Docker Buildx
18+
uses: docker/setup-buildx-action@v3
19+
20+
- name: Install Python dependencies
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install invoke requests
24+
25+
- name: Build multi-architecture images
26+
run: |
27+
# For CI testing, build only for the current platform (amd64)
28+
# Use --load to load the image into local Docker daemon for testing
29+
docker buildx build --platform=linux/amd64 --build-arg redis_version=7.2.5 -t grokzen/redis-cluster:7.2.5 --load .
30+
31+
- name: Test the built image
32+
run: |
33+
docker run --rm grokzen/redis-cluster:${LATEST_VERSION:-7.2.5} redis-server --version
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Test Multi-Architecture Build
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'Dockerfile'
7+
- 'tasks.py'
8+
- '.github/workflows/test-multiarch.yml'
9+
workflow_dispatch:
10+
11+
jobs:
12+
test-multiarch-build:
13+
runs-on: ubuntu-latest
14+
strategy:
15+
matrix:
16+
version: ['latest', '7.2.5', '7.0.15']
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Set up QEMU
21+
uses: docker/setup-qemu-action@v3
22+
23+
- name: Set up Docker Buildx
24+
uses: docker/setup-buildx-action@v3
25+
26+
- name: Install Python dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install invoke requests
30+
31+
- name: Test multi-architecture build (without push)
32+
run: |
33+
# Test building for both platforms
34+
# This validates that the build works for ARM64
35+
invoke buildx ${{ matrix.version }} --no-push
36+
37+
- name: Build and test single platform
38+
run: |
39+
# Build for current platform only so we can test it
40+
invoke buildx ${{ matrix.version }} --no-push --platforms="linux/amd64"
41+
42+
# Test the image
43+
docker run --rm grokzen/redis-cluster:${{ matrix.version }} redis-server --version

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.claude/
2+
__pycache__/
3+
*.pyc
4+
*.pyo

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,56 @@ To build a different redis version use the `--build-arg` argument.
222222
docker-compose build --build-arg "redis_version=6.0.11" redis-cluster
223223

224224

225+
## Multi-Architecture Support
226+
227+
This project now supports building images for multiple architectures including `linux/amd64` (x86_64) and `linux/arm64` (ARM64/Apple Silicon).
228+
229+
### Using Pre-built Multi-Arch Images
230+
231+
All images on Docker Hub are now built for both AMD64 and ARM64 architectures. Docker will automatically pull the correct image for your platform:
232+
233+
docker pull grokzen/redis-cluster:latest
234+
docker run grokzen/redis-cluster:latest
235+
236+
### Building Multi-Arch Images Locally
237+
238+
To build multi-architecture images locally, you need Docker Buildx (included in Docker Desktop 19.03+).
239+
240+
#### Using invoke tasks (recommended)
241+
242+
# Build and push to Docker Hub (default behavior)
243+
invoke buildx 7.2.5
244+
245+
# Build without pushing (for validation only - images won't be loaded locally)
246+
invoke buildx 7.2.5 --no-push
247+
248+
# Build for current platform only (will be loaded to local Docker)
249+
invoke buildx 7.2.5 --no-push --platforms="linux/amd64"
250+
251+
# Build all versions for multi-arch
252+
invoke buildx all
253+
254+
# Build and load for local testing (single platform only)
255+
invoke buildx 7.2.5 --no-push --platforms="linux/$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')"
256+
257+
#### Using docker buildx directly
258+
259+
# Create a buildx builder (only needed once)
260+
docker buildx create --use --name redis-cluster-builder
261+
262+
# Build for multiple platforms
263+
docker buildx build --platform="linux/arm64,linux/amd64" \
264+
--build-arg="redis_version=7.2.5" \
265+
--tag="grokzen/redis-cluster:7.2.5" \
266+
--push .
267+
268+
### GitHub Actions
269+
270+
The project includes GitHub Actions workflows that automatically build multi-architecture images:
271+
272+
- **CI Build**: Builds multi-arch images on every push to master (without pushing)
273+
- **Release**: Builds and pushes multi-arch images when creating a release or manually triggered
274+
225275

226276
# Available tags
227277

tasks.py

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@
77

88
latest_version_string = "7.2.5"
99

10+
# Platform mapping for simplified platform arguments
11+
platform_mapping = {
12+
"amd64": "linux/amd64",
13+
"arm64": "linux/arm64",
14+
"both": "linux/amd64,linux/arm64",
15+
"multi": "linux/amd64,linux/arm64"
16+
}
17+
18+
def get_platforms(platform_arg):
19+
"""
20+
Convert simplified platform argument to full platform string
21+
"""
22+
if platform_arg in platform_mapping:
23+
return platform_mapping[platform_arg]
24+
# If it's already a full platform string, return as-is
25+
return platform_arg
26+
1027
# Unpublished versions
1128
version_config_mapping = []
1229
version_config_mapping += [f"3.0.{i}" for i in range(0, 8)]
@@ -72,19 +89,23 @@ def _docker_build(config):
7289
"""
7390
Internal multiprocess method to run docker build command
7491
"""
75-
c, version = config
76-
print(f" -- Starting docker build for version : {version}")
77-
build_command = f"docker build --build-arg redis_version={version} -t grokzen/redis-cluster:{version} ."
92+
c, version, platforms = config
93+
print(f" -- Starting docker build for version : {version} on platforms: {platforms}")
94+
# Create buildx builder if it doesn't exist
95+
c.run("docker buildx create --use --name redis-cluster-builder || docker buildx use redis-cluster-builder", warn=True)
96+
build_command = f"docker buildx build --platform={platforms} --build-arg redis_version={version} -t grokzen/redis-cluster:{version} ."
7897
c.run(build_command)
7998

8099

81100
def _docker_push(config):
82101
"""
83-
Internal multiprocess method to run docker push command
102+
Internal multiprocess method to run docker push command with multi-arch support
84103
"""
85-
c, version = config
86-
print(f" -- Starting docker push for version : {version}")
87-
build_command = f"docker push grokzen/redis-cluster:{version}"
104+
c, version, platforms = config
105+
print(f" -- Starting docker push for version : {version} with platforms: {platforms}")
106+
# Use buildx to build and push multi-arch images
107+
c.run("docker buildx create --use --name redis-cluster-builder || docker buildx use redis-cluster-builder", warn=True)
108+
build_command = f"docker buildx build --platform={platforms} --build-arg redis_version={version} -t grokzen/redis-cluster:{version} --push ."
88109
c.run(build_command)
89110

90111

@@ -103,33 +124,76 @@ def pull(c, version, cpu=None):
103124

104125

105126
@task
106-
def build(c, version, cpu=None):
107-
print(f" -- Docker building version : {version}")
127+
def build(c, version, cpu=None, platforms="both"):
128+
platforms = get_platforms(platforms)
129+
print(f" -- Docker building version : {version} for platforms : {platforms}")
108130

109131
pool = Pool(get_pool_size(cpu))
110132
pool.map(
111133
_docker_build,
112134
[
113-
[c, version]
135+
[c, version, platforms]
114136
for version in version_name_to_version(version)
115137
],
116138
)
117139

118140

119141
@task
120-
def push(c, version, cpu=None):
121-
print(f" -- Docker push version to docker-hub : {version}")
142+
def push(c, version, cpu=None, platforms="both"):
143+
platforms = get_platforms(platforms)
144+
print(f" -- Docker push version to docker-hub : {version} for platforms : {platforms}")
122145

123146
pool = Pool(get_pool_size(cpu))
124147
pool.map(
125148
_docker_push,
126149
[
127-
[c, version]
150+
[c, version, platforms]
128151
for version in version_name_to_version(version)
129152
],
130153
)
131154

132155

156+
@task
157+
def buildx(c, version, cpu=None, platforms="both"):
158+
"""
159+
Build multi-architecture images using docker buildx without pushing.
160+
Use the separate push command to push the images after building.
161+
162+
Usage:
163+
invoke buildx 7.2.5 # Build both platforms (default)
164+
invoke buildx 7.2.5 --platforms=amd64 # Build only AMD64
165+
invoke buildx 7.2.5 --platforms=arm64 # Build only ARM64
166+
"""
167+
platforms = get_platforms(platforms)
168+
print(f" -- Docker buildx for version : {version} on platforms : {platforms}")
169+
170+
# Create buildx builder if it doesn't exist
171+
c.run("docker buildx create --use --name redis-cluster-builder || docker buildx use redis-cluster-builder", warn=True)
172+
173+
pool = Pool(get_pool_size(cpu))
174+
pool.map(
175+
_docker_buildx,
176+
[
177+
[c, version, platforms]
178+
for version in version_name_to_version(version)
179+
],
180+
)
181+
182+
183+
def _docker_buildx(config):
184+
"""
185+
Internal multiprocess method to run docker buildx command
186+
"""
187+
c, version, platforms = config
188+
189+
# Build without loading to local Docker daemon by default
190+
action = ""
191+
192+
print(f" -- Starting docker buildx for version : {version} on platforms: {platforms}")
193+
build_command = f"docker buildx build --platform={platforms} --build-arg redis_version={version} -t grokzen/redis-cluster:{version} ."
194+
c.run(build_command)
195+
196+
133197
@task
134198
def list(c):
135199
from pprint import pprint

0 commit comments

Comments
 (0)