Skip to content

images: start dockerd at boot for docker toolsets (fix container-job race) - #1

Merged
linyiru merged 2 commits into
mainfrom
fix/golden-docker-at-boot-for-container-jobs
Aug 23, 2026
Merged

images: start dockerd at boot for docker toolsets (fix container-job race)#1
linyiru merged 2 commits into
mainfrom
fix/golden-docker-at-boot-for-container-jobs

Conversation

@linyiru

@linyiru linyiru commented Aug 23, 2026

Copy link
Copy Markdown
Member

Problem

Container jobs (a workflow job with container: and/or services:) fail intermittently at job setup on the base/full golden, before any step runs:

failed to connect to the docker API at unix:///var/run/docker.sock ... : no such file or directory
##[error]Exit code 1 returned from process: '/usr/bin/docker version --format {{.Server.APIVersion}}'
##[error]Value cannot be null. (Parameter 'ContainerId')

The GitHub runner runs docker version at job pickup (before any step) to create the job container and service containers. So dockerd must be ready the instant the runner accepts the job.

The golden currently leaves docker.service disabled and relies on docker.socket socket-activation ("start dockerd on first docker call"). Under a concurrent matrix this races: some legs accept a job before docker.socket has finished initializing, so /var/run/docker.sock doesn't exist yet and setup fails. Single/sequential Docker jobs usually win the race, which is why this hides until you run a real matrix.

Observed on a real rails-ci migration (container jobs + Postgres/Redis service containers): with a 4-shard matrix, lint + 2 shards + system-test passed while 2 shards failed at 0.1 min with the error above. Reproducible: single jobs pass, concurrent matrix flakes a subset.

Fix

For the toolsets that ship docker (base/full): start dockerd at boot and order the runner after it.

  • systemctl enable docker.service
  • drop-in firerunner-runner.service.d/10-docker.conf: After=docker.service + Wants=docker.service

docker.service is Type=notify, so After=docker.service makes the runner wait until dockerd has signalled ready — the runner can never accept a container job before Docker is up. The minimal toolset has no docker and keeps docker.service disabled (unchanged).

Boot cost is a couple of seconds of dockerd startup on a cold VM, and it's fully hidden by a warm pool (--min-runners). Non-docker tiers are unaffected.

Verification

Generated Dockerfile RUN line for each toolset:

# full: enable docker + gate the runner
&& systemctl enable docker.service \
   && mkdir -p /etc/systemd/system/firerunner-runner.service.d \
   && printf "[Unit]\nAfter=docker.service\nWants=docker.service\n" > .../10-docker.conf \
   && for u in postgresql.service mysql.service apache2.service nginx.service; do systemctl disable "$u"; done

# minimal: unchanged (docker.service stays disabled)
&& for u in docker.service containerd.service postgresql.service ...; do systemctl disable "$u"; done

Applied the equivalent patch to a full-docker golden and re-ran the same rails-ci matrix (lint + 4 shards + system-test, all container jobs with pg/redis services + headless Chromium): all green, no Docker-socket setup failures.

…race)

Container jobs run `docker version` at job pickup (before any step) to create
the job/service containers, so dockerd must be ready the moment the runner
accepts a job. The golden previously left docker.service disabled and relied on
docker.socket socket-activation, which races under a concurrent matrix: some
legs accept a job before docker.socket is up and fail setup with
"dial unix /var/run/docker.sock: no such file".

For the base/full toolsets (which ship docker) enable docker.service at boot and
order firerunner-runner.service After=docker.service via a drop-in. docker.service
is Type=notify, so the runner waits until dockerd is READY before accepting a
job. The minimal toolset has no docker and keeps docker.service disabled.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Starts Docker during boot for Docker-capable Ubuntu images, preventing container-job setup races.

Changes:

  • Enables docker.service for base/full toolsets.
  • Orders the runner after Docker startup.
  • Keeps Docker disabled for minimal images.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread images/build-ubuntu-rootfs.sh Outdated
Comment on lines +301 to +304
# base/full start dockerd at boot (runner ordered after it, see DOCKER_BOOT
# above) so container jobs never race an un-started daemon; minimal keeps docker
# disabled. The DBs/web servers stay disabled everywhere. Snap, apt timers,
# networkd-wait-online and other noise are masked outright.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted in e0ce8ec — rewrote the boot-policy comment into one consistent paragraph (runner always starts; DBs/web disabled; docker per-toolset: base/full start dockerd at boot and gate the runner behind it, minimal keeps docker disabled).

Comment thread images/build-ubuntu-rootfs.sh Outdated
…cy comment

Use Requires= (not Wants=) together with After= so the runner is not started
unless docker.service reaches active — otherwise a docker.service failure would
still let the runner accept a container job with no daemon, defeating the
readiness guarantee. Rewrite the boot-policy comment so it no longer contradicts
itself about docker being disabled at boot.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@linyiru
linyiru merged commit 6f22d8d into main Aug 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants