Running Docker Engine (Moby) on riscv64 is a challenge: upstream Moby doesn’t support riscv64 or Debian trixie out of the box, and many base images are missing. This post documents our journey to make it work, with all the technical details, code snippets, and troubleshooting we encountered.
We started by forking the Moby repository and creating a new integration repo. To keep things maintainable, we decided:
-
All riscv64-specific logic, scripts, and patches would live outside the moby submodule.
-
Moby is added as a git submodule:
git submodule add https://github.com/moby/moby.git moby
-
All work is done on a feature branch:
git checkout -b feature/add-riscv64-support
We created a tasks.md file with atomic, testable steps, including:
-
Auditing for existing riscv64 support
-
Writing failing unit tests
-
Creating riscv64 Dockerfiles and build scripts
-
Moving all riscv64 logic out-of-tree
-
Patch-based integration for upstream files
We searched for "bookworm" in all Dockerfiles and scripts:
+
grep -ri bookworm .We created riscv64-specific Dockerfiles and scripts, but quickly realized this duplicated too much logic and would be hard to maintain.
We switched to patching the upstream Moby Dockerfile and build system. Example patch for docker-bake.hcl:
+
--- docker-bake.hcl
+++ docker-bake.hcl
@@ -218,6 +218,11 @@
no-cache-filter = ["run"]
output = ["${DESTDIR}"]
}
+group "riscv64" {
+ targets = ["docker-image"]
+ platforms = ["linux/riscv64"]
+}We automated patch application with a script:
+
./apply-riscv64-patches.shMoby’s Dockerfile expects a golang:1.24.4-trixie image, which doesn’t exist on Docker Hub. BuildKit won’t use local images for cross-arch builds unless they’re in a registry.
We wrote a script to build and push the image to a local registry:
+
#!/bin/bash
GO_VERSION=1.24.4
BASE_DISTRO=trixie
TAG="golang:${GO_VERSION}-${BASE_DISTRO}"
LOCAL_REGISTRY="host.docker.internal:5000"
LOCAL_TAG="$LOCAL_REGISTRY/golang:1.24.4-trixie"
# Start local registry if not running
if ! docker ps | grep -q "registry:2"; then
if docker ps -a | grep -q "registry"; then
docker rm registry
fi
docker run -d -p 5000:5000 --name registry registry:2
fi
# Wait for registry
for i in {1..10}; do
if curl -fsSL http://127.0.0.1:5000/v2/ > /dev/null; then break; fi
sleep 1
done
# Build and push
docker buildx build --platform linux/riscv64 --load -f Dockerfile.golang-trixie -t $TAG .
docker tag $TAG $LOCAL_TAG
docker push $LOCAL_TAGWe patched moby/Dockerfile to use the local registry image:
+
-ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
+ARG GOLANG_IMAGE="host.docker.internal:5000/golang:1.24.4-trixie"-
BuildKit containers can’t access 127.0.0.1:5000, but can access host.docker.internal:5000 on Docker Desktop.
-
You must configure Docker to allow insecure registries:
"insecure-registries": ["host.docker.internal:5000"]
-
Restart Docker after changing the config.
-
build-local-golang-trixie.shbuilds and pushes the custom image to the local registry. -
apply-riscv64-patches.shapplies all necessary patches to the moby submodule. -
build-docker-riscv64.shruns the full riscv64 build using trixie as the base.
-
"unexpected end of file in patch": Add a trailing newline to the patch file.
-
"malformed patch": Ensure the context matches the target file exactly (line endings, whitespace).
-
"connection refused": The registry container may not be running, or BuildKit can’t access it.
-
Use
host.docker.internal:5000instead oflocalhost:5000for cross-container access.
-
BuildKit only pulls from registries for cross-arch builds.
-
Always push your custom image to a registry and reference it by registry address.
-
Out-of-tree patching is maintainable, but patch context and line endings must match exactly.
-
BuildKit’s image resolution logic is registry-first for cross-arch builds.
-
Local registry and host.docker.internal are essential for local development with custom base images.
-
Automating every step (patching, image build, registry setup) is key for reproducibility.
-
Upstream the riscv64 and trixie support if possible.
-
Explore CI/CD integration for riscv64 builds.
-
Document and share scripts for the community.
Let me know if you want to add more code snippets, screenshots, or specific troubleshooting stories!