Files
Jason Stedwell 1757777a32 ver 0.1
2026-06-29 21:57:51 -05:00

4.0 KiB

Architecture

Design summary

The runner is a Docker image that wraps the official act_runner binary in a controlled, predictable environment. All dependencies are installed at image build time. The running container is long-lived and operator-managed.


Layers

┌─────────────────────────────────────────────┐
│  Gitea instance (git.alwisp.com)            │ ← dispatches jobs via act protocol
└───────────────────┬─────────────────────────┘
                    │ HTTP / WebSocket
┌───────────────────▼─────────────────────────┐
│  custom-gitea-runner container              │
│  ┌──────────────────────────────────────┐  │
│  │  tini (PID 1)                        │  │
│  │  └── docker-entrypoint.sh            │  │
│  │       ├── validate binaries          │  │
│  │       ├── install custom CAs         │  │
│  │       ├── register (first boot only) │  │
│  │       └── act_runner daemon          │  │
│  └──────────────────────────────────────┘  │
│                                             │
│  Bundled tools (installed at build time):   │
│    bash, curl, git, jq, node, npm,          │
│    docker CLI, ca-certificates, tini        │
└───────────────────┬─────────────────────────┘
                    │ /var/run/docker.sock mount
┌───────────────────▼─────────────────────────┐
│  Host Docker daemon                         │ ← runs job containers
└─────────────────────────────────────────────┘

Key design decisions

See docs/decisions/ for ADR-style records of each major choice.

Decision Choice Doc
Base image Ubuntu 22.04 decisions/0001-base-image.md
act_runner strategy Wrap official binary
Docker access Socket mount (/var/run/docker.sock)
PID 1 tini
Node.js source NodeSource (Node 20 LTS)
v1 user model root (Docker socket requires it)

Registration modes

Mode A — Pre-generated config (preferred for stable production)

Operator mounts a pre-generated runner.yaml at RUNNER_CONFIG_PATH. The entrypoint detects the file and skips registration, going straight to daemon start.

Mode B — Bootstrap registration (first boot)

If RUNNER_CONFIG_PATH does not exist, the entrypoint reads GITEA_INSTANCE_URL, GITEA_RUNNER_TOKEN, and GITEA_RUNNER_NAME from the environment, generates a default config, and calls act_runner register. Subsequent starts use the persisted config (Mode A path).

This flow is idempotent — reboots with an existing config will not re-register.


Docker socket model

The runner container mounts the host Docker socket (/var/run/docker.sock). This allows:

  • docker build and docker push in workflow steps
  • docker/login-action against external registries

Trust implication: a workflow running on this runner has full access to the host Docker daemon. This is acceptable for a trusted, self-hosted environment. Future hardening options (DinD, rootless, network isolation) are tracked in ROADMAP.md Phase 6.


Future hardening tracks

  • Rootless container execution
  • Docker-in-Docker (DinD) variant for true isolation
  • Dedicated BuildKit daemon
  • Ephemeral single-job runners
  • Network policy enforcement