This guide explains how to build Docker containers for the Colonies server, including multi-platform builds for different architectures.
- Docker 20.10 or later
- Docker buildx plugin (for multi-platform builds)
- Git (for version information)
Build a container image for your current platform (fastest option):
make containerThis creates an image tagged as colonyos/colonies for your local architecture (typically linux/amd64).
Build for both AMD64 and ARM64 architectures:
make container-multiplatformThis builds images for linux/amd64 and linux/arm64 using Docker buildx.
Build multi-platform images and push to Docker Hub or your registry:
make container-multiplatform-pushThis builds for both architectures and pushes with tags:
colonyos/colonies(latest)colonyos/colonies:<version>(thePUSH_IMAGEtag from the Makefile)
To push an already-built local image without rebuilding, run make push, which
tags BUILD_IMAGE as PUSH_IMAGE and pushes both.
Multi-platform builds require Docker buildx with QEMU support. If buildx is not available, follow these setup steps:
Method 1: Using Package Manager (if available)
# On Ubuntu/Debian
sudo apt-get install docker-buildx-pluginMethod 2: Manual Installation
# Create plugin directory
mkdir -p ~/.docker/cli-plugins
# Download buildx (replace version as needed)
curl -SL https://github.com/docker/buildx/releases/download/v0.18.0/buildx-v0.18.0.linux-amd64 \
-o ~/.docker/cli-plugins/docker-buildx
# Make executable
chmod +x ~/.docker/cli-plugins/docker-buildx
# Verify installation
docker buildx versionEnable building for ARM64 and other architectures on x86 machines:
docker run --privileged --rm tonistiigi/binfmt --install allThis installs QEMU emulators for multiple architectures including:
- linux/arm64
- linux/arm/v7
- linux/riscv64
- linux/ppc64le
- linux/s390x
Create a dedicated builder instance with multi-platform support:
# Create and bootstrap the builder
docker buildx create --name multiplatform-builder --driver docker-container --bootstrap --use
# Verify available platforms
docker buildx inspect multiplatform-builderYou should see output showing support for multiple platforms:
Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, ...
The default Colonies container (top-level Dockerfile) uses a multi-stage
build:
-
Builder Stage - Builds the Go binary
- Based on
golang:1.25-alpine - Copies
go.mod/go.sumand runsgo mod download, but since the repository vendors its dependencies (vendor/), the compile resolves packages from the vendor tree rather than fetching modules - Compiles with build version and timestamp
- Produces a statically-linked binary (CGO_ENABLED=0)
- Based on
-
Runtime Stage - Minimal runtime image
- Based on
alpine:latest - Contains only the compiled binary
- Optimized for small image size
- Based on
docker/allinone/Dockerfile builds a self-contained image with the Colonies
server plus an embedded PostgreSQL, so docker run yields a working server
with no external dependencies:
- Builder stage compiles two binaries: the server (
./cmd/main.go) and the PID-1 supervisor (./cmd/standalone) - Runtime stage is based on
postgres:17-alpine, which providesinitdb,postgres,pg_isready, andsu-execfor the supervisor to drive ENTRYPOINTiscolonies-standalone; only the API port50080is exposed (PostgreSQL stays internal)- Mount a volume at
/var/lib/postgresql/datato persist the database across restarts
Build it with:
make container-allinoneThis produces colonyos/colonies-allinone:latest.
The build process accepts two arguments for versioning:
VERSION- Git commit hash (fromgit rev-parse --short HEAD)BUILDTIME- ISO 8601 timestamp (fromdate -u '+%Y-%m-%dT%H:%M:%SZ')
These are embedded into the binary via -ldflags during compilation.
Native builds (e.g. linux/amd64 on an x86 host) are fast; emulated builds (e.g. linux/arm64 under QEMU on x86) are substantially slower. Subsequent builds are faster due to Docker layer caching.
Override the default image name and tags:
# Custom build image name
BUILD_IMAGE=myregistry/colonies make container
# Custom push tags
BUILD_IMAGE=myregistry/colonies PUSH_IMAGE=myregistry/colonies:v2.0.0 make container-multiplatform-pushBuild for a single non-native platform:
docker buildx build \
--platform linux/arm64 \
--build-arg VERSION=$(git rev-parse --short HEAD) \
--build-arg BUILDTIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ') \
-t colonyos/colonies:arm64 \
--load \
.Note: --load loads the image into your local Docker daemon (only works with single platform).
Build for more architectures beyond amd64/arm64:
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 \
--build-arg VERSION=$(git rev-parse --short HEAD) \
--build-arg BUILDTIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ') \
-t colonyos/colonies \
--push \
.View information about multi-platform images in the build cache:
# List builders and their platforms
docker buildx ls
# Inspect a specific builder
docker buildx inspect multiplatform-builder
# View build cache
docker buildx duExport multi-platform images to OCI format:
# Export to tar archive
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t colonyos/colonies \
-o type=oci,dest=colonies-multi.tar \
.
# Extract to directory
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t colonyos/colonies \
-o type=oci,dest=colonies-oci/ \
.Docker buildx is not installed. Follow the Docker Buildx Setup section.
QEMU emulation is not installed. Run:
docker run --privileged --rm tonistiigi/binfmt --install allCreate a buildx builder:
docker buildx create --name multiplatform-builder --driver docker-container --bootstrap --useClear the build cache if experiencing issues:
# Prune build cache
docker buildx prune -a -f
# Remove and recreate builder
docker buildx rm multiplatform-builder
docker buildx create --name multiplatform-builder --driver docker-container --bootstrap --useThis is expected when building ARM64 images on x86 hardware due to QEMU emulation. Consider:
- Using a native ARM64 builder (e.g., AWS Graviton, Apple Silicon)
- Setting up a remote buildx builder on ARM64 hardware
- Using cloud build services like Docker Hub automated builds
The following workflow is illustrative. The repository's real workflow
(.github/workflows/docker_master.yaml) pushes images to ghcr.io using
docker/build-push-action.
name: Build Multi-Platform Container
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
run: make container-multiplatform-pushbuild-multiplatform:
image: docker:latest
services:
- docker:dind
before_script:
- apk add --no-cache git make curl
- docker run --privileged --rm tonistiigi/binfmt --install all
- docker buildx create --name mybuilder --use
script:
- make container-multiplatform-push
only:
- tags- Use Multi-Stage Builds - Keep final images small by separating build and runtime stages
- Cache Dependencies - Copy
go.modandgo.sumbefore source code for better layer caching (in this repository the dependencies are vendored, so the build does not fetch modules and this matters less) - Statically Link Binaries - Use
CGO_ENABLED=0for portable binaries - Version Everything - Embed version information in binaries
- Tag Consistently - Use semantic versioning for image tags
- Test All Platforms - Run basic tests on each architecture after building
- Automate Builds - Set up CI/CD for automatic multi-platform builds on releases
- Installation Guide - Installing Colonies server
- Configuration - Configuring the server
- Deployment - Deploying with the repository's Docker Compose profiles
- HADeployment - High-availability clustering with embedded etcd
- Makefile - Complete build targets reference;
make buildalso produceslib/libcryptolib.so,lib/libcfslib.so, andlib/libcryptolib.wasm