Repository navigation
Conversation
Runners - A repo can run N runners (`instances: N` in the private config). Every instance gets its own account, rootless Docker daemon, image store and network namespace; the runner unit joins its daemon's namespace through `actions-runner-exec`, so fixed ports, compose projects and registry logins can no longer collide between concurrent jobs. The runner still runs as an unprivileged user; CAP_SYS_ADMIN is only used to join the namespace. - CI daemons disable RootlessKit port forwarding and detached netns so `--network host` and published ports resolve inside the runner's namespace. - Each daemon re-points /var/run/docker.sock to its own socket so job containers use their own runner's daemon. - Docker restart handler only restarts daemons whose config changed and restarts the runners that must rejoin the new namespace. Cleanup - Replace unconditional `image prune --all`, the 2 GB build cache cap and the "/srv > 25 GB wipes workspaces and caches" rule with dangling-image pruning, a 5 GB per-builder BuildKit budget and 14-day age-based retention, per instance. Existing protections (freeze, active-job skip, flock, thaw, metrics) are unchanged and now cover every instance. Docs and tests updated; the cleanup test covers multiple accounts. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ide the daemon's user namespace Review findings: - The runner unit's `docker info` readiness probe inherited the ambient CAP_SYS_ADMIN, so a CLI plugin planted in the runner home by a previous job could keep it. The probe now runs with ambient/inheritable capabilities cleared; only the namespace-entry step has them. - ci-cleanup removed workspaces and caches as root, so a surviving job container could swap a path for a symlink between `find` and `rm`. Deletion now runs as the runner user inside its daemon's user namespace: it can still remove files owned by container sub-UIDs but cannot touch anything outside that account's data (verified: a symlink to /etc is refused). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ing directory Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…service accounts Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Isolated parallel runners. A repository can run N runners (
instances: Non itsgithub_runner_reposentry, kept in the private vault config; default 1). Each instance gets its own account, rootless Docker daemon, image store and network namespace, and the runner joins that namespace, so fixed ports, compose projects and registry logins cannot collide between concurrent jobs. The runner process stays unprivileged;CAP_SYS_ADMINis only used once to join the namespace and is dropped before the runner starts.--network hostand published ports resolve inside the runner's namespace./var/run/docker.sockto its own socket (job containers mount it; the host compatibility symlink belongs to one account).actions-runner@.servicetemplate is replaced by one unit per instance. Instance 1 keeps the original account and unit name.Bounded CI cleanup. Replaces unconditional
image prune --all, the 2 GB build-cache cap and the "total/srv> 25 GB wipes workspaces and caches" rule with dangling-image pruning, a 5 GB per-builder BuildKit budget and 14-day age-based retention, per instance. Freeze, active-job skip,flock, thaw and metrics are unchanged and now cover every instance.Notes for reviewers / operators
docker_ci_cpu_quota/docker_ci_memory_max(now 6G each). Budget total memory for the number of instances.migrate-rootless.ymlnow loops over instances.Review follow-ups
/so per-userfindcan restore its working directory.Simplification
deployare password-locked (key-only).Testing
tests/test-ci-cleanup.shcovers multiple accounts (per-account Docker calls, busy account skips all, retention per instance).🤖 Generated with Claude Code