feat: coolify-deployable forgejo runner with dind #1
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/runner"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds a Forgejo Actions runner that Coolify deploys from this repository as a Docker Compose resource: one runner with configurable parallelism and a Docker-in-Docker sidecar, every value set through Coolify environment variables.
Design:
docs/superpowers/specs/2026-09-26-forgejo-runner-design.md. Plan:docs/superpowers/plans/2026-09-26-forgejo-runner.md.What's in it
compose.yaml:dind(privilegeddocker:28-dind, pinned by digest, TCP 2375 inside its own network namespace, never published) andrunner(sharesdind's namespace, no host Docker socket, waits fordindto be healthy).Dockerfile: builds oncode.forgejo.org/forgejo/runner:${RUNNER_VERSION}and adds two scripts.entrypoint.sh: validates the variables, derives the runner UUID fromFORGEJO_RUNNER_SECRET(theforgejo-cli actions registerscheme), writes/data/config.ymlwith mode 600 on every start, then runsforgejo-runner daemon.entrypoint.sh renderprints the config with the token redacted.healthcheck.sh: checks the daemon process, the cache port, the DinD port and$FORGEJO_URL/api/healthz, and names the check that failed..env.exampleandREADME.md: the variables, Coolify setup, registering a secret, troubleshooting.Only
FORGEJO_RUNNER_SECRETis required. The compose file uses${FORGEJO_RUNNER_SECRET:?…}, so a deploy without it fails immediately.Verification
sh tests/entrypoint.test.sh: 30/30. It builds the image and checks the rendered config (defaults, overrides, escaping), every validation error, that the secret never appears in any output, and that the healthcheck reports a missing daemon. It also starts the real daemon, which loads the config and fails pinging the configured DinD address. A malformed config fails this check instead. Containers run with--network noneonly.sh tests/compose.test.sh: 12/12. The secret is required, and the defaults, overrides anddind/runnerwiring come out right.shellcheckandhadolint: clean.compose.yamland.env.exampleagree on all 10 variables.Not covered by the tests
Job containers reaching DinD for Docker and the cache at
dind.docker.internalonly get exercised by the first real workflow run after deployment. Testing that locally would mean starting privileged containers on the production host.Coolify 4.3.23 skips injecting
networks:for a service withnetwork_mode: itsserviceParserchecks for it. Sonetwork_mode: service:dindshould deploy, but that is confirmed only by the first deploy.Cutover (after merge)
Task 4 of the plan: reuse runner 1's registered secret, stop the old
forgejo-runnerservice before deploying this one, then delete the runner-2 and runner-3 registrations and the old volumes once a job has run.