Files

85 lines
4.0 KiB
Markdown
Raw Permalink Normal View History

2026-06-29 21:56:12 -05:00
# 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