commit 24773657633d4b3e608dfc2cd96136fbf3b98e2c Author: Lucas Orth Date: Thu Aug 20 19:17:55 2026 +0200 Runner-Setup fuer Gitea Actions act_runner auf dem VPS, steuert den Docker-Daemon des Hosts ueber den Socket. Registrierung ueber die interne Adresse http://gitea:3000 im Netz gitea-ci - die oeffentliche Domain ist aus Containern heraus nicht erreichbar (NAT-Hairpin, host-gateway zusaetzlich von der Firewall geblockt). Bewusst nicht im Netz nginx-proxy-manager_default: der Runner spricht mit Gitea, nicht mit dem Proxy. .env und data/ bleiben aussen vor, beide enthalten Runner-Credentials. Co-Authored-By: Claude Opus 5 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..3b5d37f --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# Name des Gitea-Containers, pruefen mit: docker ps --format '{{.Names}}' +GITEA_CONTAINER=gitea +# Interner Port von Gitea (nicht der veroeffentlichte). Im Nginx Proxy +# Manager beim Host gitea.lucas-orth.de als "Forward Port" sichtbar. +GITEA_PORT=3000 + +GITEA_RUNNER_REGISTRATION_TOKEN=hier-den-token-aus-gitea-einfuegen diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e6ec30d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Registration-Token +.env + +# Enthaelt .runner mit der Runner-UUID und ihrem Token - das ist ein +# Credential, kein Zustand. Gehoert nicht ins Repo. +data/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..f85fae0 --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +# gitea-runner + +Der CI-Runner fuer Gitea Actions auf dem VPS. Baut und deployt die Apps, +sobald in einem Repo ein Tag `v*` gepusht wird. + +Die Konventionen fuer die Apps selbst stehen nicht hier, sondern in +[deploy-kit](https://gitea.lucas-orth.de/lucas.orth/deploy-kit). + +## Aufbau + +``` +Tag-Push -> Gitea -> gitea-runner -> Job-Container -> Docker-Daemon des Hosts +``` + +Der Runner steuert den Docker-Daemon ueber `/var/run/docker.sock`. Er baut +also nicht in sich selbst, sondern auf dem Host - deshalb laufen die +gebauten Container ganz normal neben ihm. + +Zwei getrennte Netze: + +| Netz | Wer haengt drin | +|---|---| +| `gitea-ci` | Gitea, Runner, Job-Container | +| `nginx-proxy-manager_default` | Proxy, alle App-Container | + +Der Runner hat im Proxy-Netz nichts verloren - er spricht mit Gitea, nicht +mit dem Proxy. + +## Einrichtung + +### 1. Actions in Gitea aktivieren + +In der `app.ini`: + +```ini +[actions] +ENABLED = true +``` + +Ab Gitea 1.21 Default. Danach Gitea neu starten. + +### 2. Netz anlegen und Gitea daran haengen + +```bash +docker network create gitea-ci +``` + +In **Gitea's** `docker-compose.yml` ergaenzen - beim Service und im +`networks`-Block: + +```yaml +services: + server: + networks: + - nginx-proxy-manager_default + - gitea-ci + +networks: + nginx-proxy-manager_default: + external: true + gitea-ci: + external: true +``` + +Das ist der Teil, der es dauerhaft macht. `docker network connect` von Hand +waere beim naechsten Recreate von Gitea wieder weg. + +Dann in Gitea's Verzeichnis `docker compose up -d` und pruefen: + +```bash +docker inspect -f '{{range $n,$v := .NetworkSettings.Networks}}{{$n}} {{end}}' gitea +``` + +Beide Netze muessen erscheinen. + +### 3. Runner registrieren + +Token holen: Gitea -> Site Administration -> Actions -> Runner -> +"Create new Runner". + +```bash +cp .env.example .env && nano .env +docker compose up -d +docker compose logs --tail 30 runner +``` + +`runner registered successfully` muss erscheinen, in Gitea steht der Runner +danach als **Idle**. + +## Warum die interne Adresse + +`GITEA_INSTANCE_URL` zeigt auf `http://gitea:3000`, nicht auf die +oeffentliche Domain. Gitea laeuft auf demselben Host: ein Container, der die +oeffentliche IP anspricht, bekommt keine Antwort zurueck (NAT-Hairpin). Der +Umweg ueber `host-gateway` scheitert zusaetzlich an der Firewall. + +Aus demselben Grund setzen die Workflows in `actions/checkout` den Input +`github-server-url: http://gitea:3000` - sonst klont der Job-Container ueber +die oeffentliche Domain und laeuft in denselben Timeout. + +## Nicht im Repo + +`.env` (Registration-Token) und `data/` (enthaelt `.runner` mit dem +dauerhaften Runner-Token). Beides steht in `.gitignore`. diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..322aaaf --- /dev/null +++ b/config.yaml @@ -0,0 +1,15 @@ +runner: + # Wie viele Jobs gleichzeitig. 1 reicht fuer einen VPS. + capacity: 1 + timeout: 30m + +container: + # Job-Container in dasselbe Netz wie Gitea, damit actions/checkout + # den Server erreicht. + network: gitea-ci + privileged: false + # Leer = act_runner reicht den Docker-Socket in den Job-Container. + # Ohne das kann der Workflow kein "docker build" ausfuehren. + docker_host: "" + valid_volumes: + - '**' diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a63873a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +services: + runner: + image: gitea/act_runner:latest + container_name: gitea-runner + restart: unless-stopped + environment: + # Interne Adresse ueber das gemeinsame Netz gitea-ci. + # NICHT die oeffentliche Domain: Gitea laeuft auf demselben Host, der + # Weg ueber die oeffentliche IP findet nicht zurueck (NAT-Hairpin) + # und die Registrierung haengt still. + GITEA_INSTANCE_URL: http://${GITEA_CONTAINER}:${GITEA_PORT} + GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN} + GITEA_RUNNER_NAME: vps-runner + # Ohne das wird die gemountete config.yaml ignoriert. + CONFIG_FILE: /config.yaml + GITEA_RUNNER_LABELS: ubuntu-latest:docker://catthehacker/ubuntu:act-latest + volumes: + - ./data:/data + - ./config.yaml:/config.yaml:ro + # Der Runner steuert den Docker-Daemon des Hosts. + # ACHTUNG: das entspricht Root-Rechten auf dem VPS. + - /var/run/docker.sock:/var/run/docker.sock + networks: + - gitea-ci + +# Bewusst NICHT nginx-proxy-manager_default: der Runner spricht mit Gitea, +# nicht mit dem Proxy. Das Netz wird einmalig angelegt mit +# docker network create gitea-ci +# und muss auch in Gitea's Compose-File stehen, sonst faellt Gitea beim +# naechsten Recreate wieder heraus. +networks: + gitea-ci: + external: true