85 lines
4.0 KiB
Markdown
85 lines
4.0 KiB
Markdown
# 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
|