Files
kadence/docker-compose.ci.yml
T
timka123andClaude Opus 5 8415c8995b ci: the runner is docker-mode, and a guide for setting one up
`runs-on: ubuntu-latest` stays what it is everywhere else — a disposable
container — and `docker-compose.ci.yml` is now what makes that true: the label
maps to `catthehacker/ubuntu:act-24.04`, job containers share the runner's
network so the cache server is reachable at all, and the host's docker socket is
passed through (`docker_host: automount`) so the image workflow can build.

The failure this is replacing is worth naming, because the symptom does not
point at it: with a **host**-mode runner answering the same label, every job runs
directly on the server as the runner's own user, so the workflows' `apt-get
install` steps fail on permissions — and had they succeeded, CI would have been
installing packages on a host. A workflow cannot tell which kind of runner it
got; only the label map can say.

`docs/gitea-runner.md` is the separate guide: why docker mode, the prerequisites
including Gitea's two `app.ini` settings, the install, how to remove a host-mode
runner (and what to check before you do, since a runner is shared), how to
verify a job really is in a container, why labels cannot be changed without
re-registering, and a table of the failures with their causes.

Also `workflow_dispatch` on the test workflow, so a fresh runner can be proved
from the UI without inventing a commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-22 18:35:20 +03:00

73 lines
3.4 KiB
YAML

# The Gitea Actions runner, in Docker.
#
# This is the runner that executes everything in `.gitea/workflows`. It claims
# the label **`ubuntu-latest`** and maps it to a container image, which is what
# the workflows expect: GitHub's own name, GitHub's own semantics — the job runs
# in a disposable container, not on the machine.
#
# It replaced a *host*-mode runner on the same box (`ubuntu-latest:host`), where
# every job ran directly on the server as the `act_runner` user. That is why the
# workflows' `apt-get install` steps failed: nothing could be installed, and had
# it succeeded it would have been installing packages on the host.
#
# Setting it up, and what each piece is for, is in
# [`docs/gitea-runner.md`](docs/gitea-runner.md). The short version:
#
# mkdir -p /opt/gitea-runner && cd /opt/gitea-runner
# # copy this file as docker-compose.yml and deploy/act-runner.yaml as config.yaml
# printf 'GITEA_RUNNER_REGISTRATION_TOKEN=%s\n' "<token from Gitea>" > .env
# chmod 600 .env
# docker compose up -d
#
# The registration token is needed **once**: after the first start the runner has
# its own permanent token in `./data/.runner` and the one in `.env` is dead.
services:
runner:
image: gitea/act_runner:0.3.1
container_name: gitea-runner
restart: unless-stopped
environment:
GITEA_INSTANCE_URL: ${GITEA_INSTANCE_URL:-https://git.timka.su}
# Only read at first registration; harmless (and ignored) afterwards.
GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN:-}
GITEA_RUNNER_NAME: ${GITEA_RUNNER_NAME:-dockerized}
# The label map: what `runs-on` may ask for, and what it gets.
#
# `act-24.04` and not something slimmer because the jobs need two things
# from the image: a **node**, since Gitea's javascript actions (checkout,
# cache, upload-artifact) run *inside* the job container, and **Python
# 3.12**, which the backend's `requires-python` insists on and Ubuntu
# 24.04 ships. A plain `ubuntu:24.04` has neither and every job would
# fail at the first `uses:`.
#
# Labels are baked into `./data/.runner` at registration — changing this
# line later does nothing on its own. See the guide.
GITEA_RUNNER_LABELS: >-
ubuntu-latest:docker://catthehacker/ubuntu:act-24.04,
ubuntu-24.04:docker://catthehacker/ubuntu:act-24.04,
ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04
CONFIG_FILE: /config/config.yaml
volumes:
- ./config.yaml:/config/config.yaml:ro
# The registration lives here. Delete `./data/.runner` and the runner
# re-registers as a *new* one, leaving a stale entry in Gitea.
- ./data:/data
# The host's docker daemon, so a job can build and push an image. This is
# a real privilege — root on the host, effectively — and the reason the
# runner should not be registered at instance level on a box you do not
# want CI to own. `config.yaml` passes it through to job containers.
- /var/run/docker.sock:/var/run/docker.sock
networks:
- runner
networks:
# Job containers join this same network (`container.network` in config.yaml),
# which is what makes the runner's built-in cache server reachable from them:
# it advertises its own address, and on a separate network that address would
# route nowhere. It is also why nothing here needs a published port.
runner:
name: gitea-runner