Probe the runner's Docker and buildx capabilities #3

Closed
opened 2026-09-30 13:14:52 +00:00 by piscis · 1 comment
Owner

What to build

A manually dispatchable Forgejo Actions workflow on the docker runner label (other labels available: ubuntu-latest, ubuntu-22.04, ubuntu-24.04) that reports what the runner can do for building the Image. It checks:

  • whether the job container can reach a Docker daemon (host socket or docker-in-docker)
  • whether docker buildx is available and which builders and platforms it lists
  • the host CPU architecture
  • whether arm64 emulation (QEMU/binfmt) is registered or can be set up in the job

Post the findings as a comment on this issue. If Docker access is missing, recommend the smallest fix: either the runner-admin change (container.docker_host: automount or a privileged dind service, with the security trade-off stated) or a daemonless builder. Hand that decision back to the human instead of making it.

Acceptance criteria

  • The workflow runs to completion via manual dispatch on the docker label
  • The comment on this issue states: daemon reachable (yes/no, and how), buildx version and platforms, host arch, arm64 emulation availability
  • If anything needed for a multi-arch buildx build is missing, the comment recommends a fix and the issue is relabelled ready-for-human

Blocked by

  • None (can start immediately)

Context: see GLOSSARY.md (Upstream, Upstream Version, Image, Rebuild, Consumer, Pin) and docs/adr/ (0001 build from Upstream source for multi-arch, 0002 canonical Upstream not the Codeberg mirror, 0003 tag scheme and immutable Rebuild tags).

## What to build A manually dispatchable Forgejo Actions workflow on the `docker` runner label (other labels available: `ubuntu-latest`, `ubuntu-22.04`, `ubuntu-24.04`) that reports what the runner can do for building the Image. It checks: - whether the job container can reach a Docker daemon (host socket or docker-in-docker) - whether `docker buildx` is available and which builders and platforms it lists - the host CPU architecture - whether arm64 emulation (QEMU/binfmt) is registered or can be set up in the job Post the findings as a comment on this issue. If Docker access is missing, recommend the smallest fix: either the runner-admin change (`container.docker_host: automount` or a privileged dind service, with the security trade-off stated) or a daemonless builder. Hand that decision back to the human instead of making it. ## Acceptance criteria - [ ] The workflow runs to completion via manual dispatch on the `docker` label - [ ] The comment on this issue states: daemon reachable (yes/no, and how), buildx version and platforms, host arch, arm64 emulation availability - [ ] If anything needed for a multi-arch buildx build is missing, the comment recommends a fix and the issue is relabelled `ready-for-human` ## Blocked by - None (can start immediately) Context: see `GLOSSARY.md` (Upstream, Upstream Version, Image, Rebuild, Consumer, Pin) and `docs/adr/` (0001 build from Upstream source for multi-arch, 0002 canonical Upstream not the Codeberg mirror, 0003 tag scheme and immutable Rebuild tags).
Author
Owner

Runner probe results

I added .forgejo/workflows/probe-runner.yml and dispatched it manually on the docker label. It ran twice (runs #1 and #2 on branch piscis/forgejo-runner-implement) and both finished successfully. The job uses container: image: docker:cli (Alpine 3.24), which ships the docker CLI and the buildx plugin, because the runner's default job image may have neither.

Daemon reachable: yes, through the runner's docker-in-docker daemon, not a host socket.

  • DOCKER_HOST=tcp://docker_dind:2376 (TLS) is set in the job container, and /var/run/docker.sock is absent.
  • docker info works: Docker Engine 29.8.1, daemon name docker_dind, OS "Alpine Linux v3.24 (containerized)".
  • The job container is visible to that daemon, so it is the same dind daemon the runner starts jobs on (sibling containers), not a per-job dind service.
  • The containerd image store is on (driver-type: io.containerd.snapshotter.v1), so the default docker driver can build and push multi-platform images without creating a docker-container builder.

buildx: v0.37.1, BuildKit v0.33.0, one builder: default (driver docker).

  • Platforms (buildx inspect, run #2): linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64. Run #1 only had buildx ls, which truncates the list to linux/amd64 (+3), so which platforms existed before the first binfmt install isn't known.

Host arch: x86_64 (uname -m and docker info agree). 4 CPUs, 7.75 GiB RAM, kernel 6.8.0-142-generic.

arm64 emulation: available.

  • Before run #1, qemu-aarch64 was not registered. Note that binfmt_misc isn't mounted in the job container, so /proc/sys/fs/binfmt_misc can't be read from inside the job.
  • docker run --privileged tonistiigi/binfmt --install arm64 works in-job (reported installing: arm64 OK).
  • docker run --platform linux/arm64 alpine uname -m printed aarch64.
  • In run #2 binfmt reported qemu-aarch64 already registered. The registration is kernel-wide on the runner host and lasts until reboot. The build workflow should still run the binfmt install step every time rather than rely on it.

Conclusion

Everything a multi-arch (amd64 + arm64) buildx build needs is present: a reachable daemon, buildx with the containerd image store, and arm64 emulation that the job can set up itself. The runner needs no admin changes and no daemonless builder. Per ADR 0001, Go cross-compiles natively, so QEMU is only needed for any RUN steps in the arm64 final stage.

Side note: this Forgejo instance doesn't support job summaries (::warning::This Forgejo instance does not support job summaries), so the probe also prints a full report as its last log step.

## Runner probe results I added `.forgejo/workflows/probe-runner.yml` and dispatched it manually on the `docker` label. It ran twice (runs #1 and #2 on branch `piscis/forgejo-runner-implement`) and both finished successfully. The job uses `container: image: docker:cli` (Alpine 3.24), which ships the docker CLI and the buildx plugin, because the runner's default job image may have neither. **Daemon reachable: yes, through the runner's docker-in-docker daemon, not a host socket.** - `DOCKER_HOST=tcp://docker_dind:2376` (TLS) is set in the job container, and `/var/run/docker.sock` is absent. - `docker info` works: Docker Engine 29.8.1, daemon name `docker_dind`, OS "Alpine Linux v3.24 (containerized)". - The job container is visible to that daemon, so it is the same dind daemon the runner starts jobs on (sibling containers), not a per-job dind service. - The containerd image store is on (`driver-type: io.containerd.snapshotter.v1`), so the default `docker` driver can build and push multi-platform images without creating a `docker-container` builder. **buildx: v0.37.1**, BuildKit v0.33.0, one builder: `default` (driver `docker`). - Platforms (`buildx inspect`, run #2): `linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64`. Run #1 only had `buildx ls`, which truncates the list to `linux/amd64 (+3)`, so which platforms existed before the first binfmt install isn't known. **Host arch: x86_64** (`uname -m` and `docker info` agree). 4 CPUs, 7.75 GiB RAM, kernel 6.8.0-142-generic. **arm64 emulation: available.** - Before run #1, `qemu-aarch64` was not registered. Note that binfmt_misc isn't mounted in the job container, so `/proc/sys/fs/binfmt_misc` can't be read from inside the job. - `docker run --privileged tonistiigi/binfmt --install arm64` works in-job (reported `installing: arm64 OK`). - `docker run --platform linux/arm64 alpine uname -m` printed `aarch64`. - In run #2 binfmt reported `qemu-aarch64 already registered`. The registration is kernel-wide on the runner host and lasts until reboot. The build workflow should still run the binfmt install step every time rather than rely on it. ### Conclusion Everything a multi-arch (amd64 + arm64) buildx build needs is present: a reachable daemon, buildx with the containerd image store, and arm64 emulation that the job can set up itself. The runner needs no admin changes and no daemonless builder. Per ADR 0001, Go cross-compiles natively, so QEMU is only needed for any `RUN` steps in the arm64 final stage. Side note: this Forgejo instance doesn't support job summaries (`::warning::This Forgejo instance does not support job summaries`), so the probe also prints a full report as its last log step.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
Reference
vicoli-oss/docker-forgejo-mcp#3
No description provided.