Gitea Runner role
Deployt Gitea-Actions-Runner-Container. Dieser Runner nutzt den basic-Flavour von
gitea/runner (Alpine, kein eingebauter Docker-Daemon, Docker-Socket wird gemountet).
Das bestehende Netz gitea-runner erhält gw_priority: 1 (Compose >= 2.33.1).
Der Runner verbindet sich während eines Jobs zusätzlich mit dessen Netz.
Ohne feste Gateway-Priorität kann Docker dabei seine Standardroute wechseln;
Gitea-Verbindungen brechen ab und Jobs bleiben nach erfolgreichen Schritten
beim Cleanup hängen. Die feste Priorität hält die Standardroute im Runner-Netz.
Stand: Gitea 1.27, Gitea Runner v3.1.0 (Juli 2026)
Wichtige Begriffe
- Runner – Container, der Jobs von der Gitea-Aktions-Engine empfängt und startet.
- Job-Image – das Docker-Image, in dem ein Job läuft.
- Label – Bindet ein
runs-on: xyzan ein Image (oder den Host):xyz:docker://gitea.rwcloud.ch/…oderxyz:host.
⚡ Wichtig:
runs-on:in Workflows wird mit den Labels des Runners gematcht. Wenn der Runner nurubuntu-latest(ohnedocker://…) als Label hat, läuft der Job direkt auf dem Host des Runner-Containers – nicht in einem eigenen Image!
Ein Job bekommt sein runs-on-Image durch die Label-Syntax:
1 2 3 4 5 | |
1 2 3 4 | |
Wenn kein Label zu runs-on passt, fällt der Runner auf
docker.gitea.com/runner-images:ubuntu-latest zurück (extern!).
Runner-Image-Flavour
| Tag | Basis | Docker-Daemon für Jobs | Privilegien |
|---|---|---|---|
gitea/runner:latest (basic) |
alpine | extern (Host-Socket gemountet) | keine, kein --privileged |
gitea/runner:latest-dind |
docker:dind | eingebaut, root | --privileged |
gitea/runner:latest-dind-rootless |
docker:dind-rootless | eingebaut, UID 1000 | rootless-Limits |
Empfehlung: basic (Status Quo). Der Job-Daemon ist der Host-Daemon,
docker image prune greift direkt – ideal für Auto-Patching (siehe unten).
Konfiguration – Beispiel
playbooks/proxmox/group_vars/gitea_runner.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | |
Inventory-Fields (pro Runner)
| Feld | Pflicht | Default | Beschreibung |
|---|---|---|---|
name |
✅ | – | Container-Name (unique) |
token |
✅ | – | Registrierungstoken aus Gitea-UI |
tags |
✅ | – | List of Labels (name oder name:docker://img oder name:host) |
state |
✅ | – | present / absent |
runner_image |
– | gitea/runner:latest |
Image des Runner-Containers (basic/dind/dind-rootless) |
instance_url |
– | https://gitea.rwcloud.ch |
URL der Gitea-Instanz |
capacity |
– | 1 | Parallel-Jobs |
timeout |
– | 36h | Job-Timeout |
envs |
– | – | Dict, läuft in jeden Job als Env-Var |
hooks.job_started |
– | – | Shell-Skript, vor erstem Step, im Job-Context |
hooks.job_completed |
– | – | Shell-Skript, nach letztem Step, im Job-Context |
post_task_script_body |
– | – | Shell-Skript, nach jedem Job, vom Runner ausgeführt. Wird auf den Host geschrieben (/etc/gitea-runner/<name>/post-task.sh), read-only in den Runner-Container gemountet und unter post_task_script: /usr/local/bin/gitea-post-task.sh konfiguriert. Braucht docker-CLI im Runner-Flavour (basic hat keins → -dind oder Custom-Image). |
post_task_script_timeout |
– | 5m | Timeout für das Post-Skript |
cache.dir |
– | – | Pfad für actions/cache |
cache.external_server |
– | – | Gemeinsamer Cache-Server (http://…) |
cache.external_secret |
– | – | Secret für Cache-Server |
cache.v2 |
– | true | Cache-Service v2 |
Hinweis zu
hooks: Hooks laufen im Job-Context – also im Job-Container beidocker://-Labels, auf dem Host beihost-Labels.docker loginbraucht docker-CLI im Job-Image. Alternativ: Runner-envsfür Secrets, die immer gesetzt sein sollen (z. B. Registry-URL).
Workflow-Beispiel
.gitea/workflows/build-vadn.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
Auto-Patch der Job-Images
Ziel: kein manuelles Rebuild, keine manuelle Label-Änderung im Ansible-Inventory.
Bausteine
- Image-Repo (z. B.
docker-builds) – enthält alle Dockerfiles + Build-Workflows - Renovate – PRs für neue
ARG JAVA_VERSION,KOTLIN_VERSION,MAVEN_VERSION - Build-Workflow – Trigger:
pushauf Dockerfile-Änderung + wöchentlich + manuell - Registry –
:latest+ immutable Versionstags (Rollback) post_task_script– pruned Docker-Cache, damit Runner-Hosts nicht voller alt-Image-Schrott werden
Renovate-Konfiguration (ergänzend)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Build-Workflow
.gitea/workflows/runner-java-build.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
Cache-Automatik im Runner
runner.post_task_scriptpruned nach jedem Job (docker image/container prune)pull: alwaysimdocker_compose_v2Task → Runner-latest-Image wird automatisch geupdatet- Job-Images werden vom Runner auf Job-Start gezogen (oder aus Local-Cache)
Achtung: Job-Images bleiben im Local-Daemon-Cache, bis
prunesie entfernt. Wenn ein neuerlatest-Build herauskommt und ein Job läuft, hält der laufende Job das alte Image. Neue Jobs ziehen das neue. Das ist gewolltes Verhalten – aberpost_task_scriptpruned nur unreferenzierte Images, nicht laufende.
Gitea-Instanz: Actions ohne github.com
Damit uses: … nicht von github.com lädt:
app.inider Gitea-Instanz:
1 2 3 | |
- Action-Repositories spiegeln:
1 2 3 4 | |
-
uses:entweder kurz (actions/checkout@v4) – dank Mirror +DEFAULT_ACTIONS_URL=selfvon eigener Gitea – oder absolut (https://gitea.rwcloud.ch/actions/checkout@v4). -
docker loginohnedocker/login-action:
1 2 3 4 | |
Voraussetzung: Job-Label zeigt auf ein Image mit docker-CLI oder du nutzt
runner.envs + hooks.job_started.
Monitoring
1 2 3 | |
Gitea-UI: Repo → Actions → Runners zeigt aktive Runner + Labels.
Security
- Runner-Container läuft root im basic/dind-Flavour (rootless dind → UID 1000).
/var/run/docker.sockist ein Docker-Daemon-Zugang (Root-Äquivalent) – nur auf vertrauenswürdigen Hosts.hooks.job_startedläuft im Job-Context – Secrets hier nutzen ist bewusst.post_task_scriptwird vom Runner in dessen Umgebung ausgeführt und bindet denselben Docker-Socket – hat also Daemon-Rechte.
Troubleshooting
| Problem | Ursache | Fix |
|---|---|---|
| Job läuft nicht im richtigen Image | Label-Syntax falsch (ubuntu-latest statt ubuntu-latest:docker://…) |
Label in Inventory mit docker://-Schema |
java/mvn nicht gefunden |
Job-Image ohne Java | Temurin in Dockerfile installieren |
actions/checkout lädt von github.com |
DEFAULT_ACTIONS_URL nicht gesetzt |
[actions] DEFAULT_ACTIONS_URL=self + Mirror |
docker login schlägt fehl |
Kein docker-CLI im Job-Image | Docker-Image erweitern oder envs verwenden |
| Runner nimmt neue Labels nicht an | .runner-File hat alten Label-State |
runner neu registrieren ODER config set runner.labels … |
| Cache hält altes Image | Local Daemon-Cache | post_task_script → docker image prune, oder pull: always |
job_started-Hook scheitert |
docker-CLI fehlt im Job-Image | docker-CLI installieren ODER Host-Label nutzen |
Playbooks
1 2 3 4 5 6 7 8 9 | |
