Run #4267 finally got the bind mount through (Merged Binds includes /root/.docker:/root/.docker:ro), but docker build then died: failed to update builder last activity time: open /root/.docker/buildx/activity/.tmp-...: read-only file system The catthehacker job container uses buildx, which writes activity tracking to /root/.docker/buildx/. Mounting the whole host /root/.docker read-only made that path read-only too. Right scope is the file, not the dir: -v /root/.docker/config.json:/root/.docker/config.json:ro That gives the cli the registry auth it needs while leaving the rest of /root/.docker on the container's writable overlay so buildx can populate its own activity dir without colliding with the host's. Also matches the principle of mounting the minimum the secret requires. valid_volumes entry updated to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
silvermetal-builder runner deployment
The Gitea Actions runner that handles runs-on: silvermetal-builder jobs from .gitea/workflows/build-iso-linux.yaml.
Layout
| File | Purpose |
|---|---|
docker-compose.yml |
act_runner service definition, deployed on SLAB docker host. |
Dockerfile.runner |
Adds docker-cli to the upstream gitea/act_runner image. |
config.yaml |
act_runner runtime config — privileged, 4h timeout, host network. |
.env.example |
Template for the registration-token env file (real .env not commit). |
Why privileged
live-build needs loop devices and chroot inside the build container. Without privileged: true, mksquashfs and debootstrap fail. This is the only Gitea runner in the SilverLABS fleet that runs privileged — keep its scope narrow (one repo, one job class).
Deploy
On the SLAB docker host (10.0.0.51):
sudo mkdir -p /opt/silvermetal-builder-runner
cd /opt/silvermetal-builder-runner
# Copy this directory's contents in (e.g. via scp or rsync from a checkout
# of SilverLABS/SilverMetal at linux/build/runner/).
# Then create the .env with a fresh registration token:
GITEA_TOKEN=<admin-token> \
curl -H "Authorization: token $GITEA_TOKEN" \
https://git.silverlabs.uk/api/v1/admin/runners/registration-token
cp .env.example .env
$EDITOR .env # paste the token
# Log in to the registry on the *host* — config.yaml mounts the resulting
# /root/.docker/config.json into both the act_runner container and every
# job container it spawns, so the builder-image job in build-iso-linux.yaml
# can `docker push` without its own login step.
docker login docker-registry.silverlabs.uk
# Pre-pull the builder image so the first job isn't a cold start. (Skip
# this on the very first deploy: the :latest tag won't exist until CI
# runs once. After that it's pushed by the builder-image job.)
docker pull docker-registry.silverlabs.uk/silvermetal-builder:latest || true
docker compose up -d
docker compose logs -f --tail 50 # watch for "Runner registered"
Check the runner shows up under git.silverlabs.uk/-/admin/actions/runners with label silvermetal-builder.
Bump the runner image / config
cd /opt/silvermetal-builder-runner
git pull # if you keep this dir as a checkout
docker compose up -d --build
Tear down
docker compose down -v # -v drops runner-data volume; runner has to re-register
The runner-data volume holds the registered runner identity — keep it across image bumps so we don't pollute the Gitea runners list with dead entries.