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 buildanddocker pushin workflow stepsdocker/login-actionagainst 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