Compare commits

...
4 Commits
Author SHA1 Message Date
DragonSlayer_14andClaude Sonnet 5 e055999f0c Feat: Runner-Capacity über RUNNER_CAPACITY in .env konfigurierbar
Das offizielle gitea/runner-Image kennt keine Umgebungsvariable für
runner.capacity, dieser Wert lässt sich nur über die config.yaml setzen.
entrypoint.sh kopiert config/runner.yaml beim Containerstart daher nach
/data/config.runtime.yaml und überschreibt dort per `gitea-runner config
set` die capacity, falls RUNNER_CAPACITY gesetzt ist, bevor das
eigentliche run.sh des Images gestartet wird.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 18:50:13 +02:00
DragonSlayer_14andClaude Sonnet 5 863688c180 Fix: Nachbesserungen aus Code-Review am Cache-Setup
- Healthcheck für den Cache-Server, damit der Runner (depends_on:
  condition: service_healthy) wirklich wartet, bis der Cache-Server auf
  Port 8088 Verbindungen annimmt, statt nur den Container-Start abzuwarten
- Veralteten Kommentarverweis auf "cache-config.yaml" korrigiert zu
  "config/cache.yaml"
- README: Hinweis ergänzt, dass Port 8088 zwingend auf allen
  Host-Interfaces lauschen muss (sonst für Job-Container unerreichbar) und
  daher per Host-Firewall gegen Zugriff von außen abgesichert werden sollte

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kFWpJ4p1jQ2pJf3S13FWE
2026-09-10 00:07:57 +02:00
DragonSlayer_14andClaude Sonnet 5 e26481d8df Feat: Isolierter externer Cache-Service + 5 parallele Jobs
Der Cache läuft jetzt als eigener, per Secret authentifizierter Service
(config/cache.yaml, Service "cache") statt eingebettet im Runner. Dadurch
behält jeder Job weiterhin sein eigenes isoliertes Docker-Netzwerk (auch bei
runner.capacity: 5), statt sich wie zuvor ein gemeinsames Netzwerk mit dem
Runner und allen anderen Jobs zu teilen - das hätte parallelen/späteren Jobs
erlaubt, sich gegenseitig zu erreichen und den unauthentifizierten Cache zu
vergiften.

Job-Container erreichen den Cache-Server über den Docker-Host-Gateway
(container.options: --add-host=cachehost:host-gateway) statt über ein
gemeinsames Netzwerk.

- runner.capacity: 5
- Cache-Server-Prozess authentifiziert per external_secret_file (cache-secret,
  wird auf dem Host erzeugt, nicht committet)
- Konfigurationen nach config/runner.yaml und config/cache.yaml verschoben
- Datenverzeichnisse aufgeteilt in data/runner und data/cache
- README: Setup-Anleitung fürs Secret + Migrationsanleitung für bestehende
  Deployments (alter data/-Inhalt -> data/runner)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kFWpJ4p1jQ2pJf3S13FWE
2026-09-10 00:02:10 +02:00
DragonSlayer_14andClaude Sonnet 5 8cf02112d5 Fix: Repariert den Cache-Service des Runners
Der Runner erstellte für jeden Job ein isoliertes Docker-Netzwerk, wodurch
Job-Container den automatisch erkannten Cache-Host nicht erreichen konnten.
Zusätzlich wäre der Cache mangels explizitem cache.dir in der
Container-Schreibschicht statt im persistenten /data-Volume gelandet.

- Gemeinsames Docker-Netzwerk (gitea_runner_net) für Runner und Job-Container
- cache.host/port explizit auf den Runner-Container gesetzt
- cache.dir unter /data, damit der Cache Neuerstellungen übersteht
- restart: unless-stopped, damit der Runner nach Absturz/Reboot wieder anläuft

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kFWpJ4p1jQ2pJf3S13FWE
2026-09-09 23:34:28 +02:00
8 changed files with 159 additions and 3 deletions
+3
View File
@@ -2,3 +2,6 @@ INSTANCE_URL=https://gitea.creative-dragonslayer.de
REGISTRATION_TOKEN=ABC REGISTRATION_TOKEN=ABC
RUNNER_NAME=gitea_main RUNNER_NAME=gitea_main
RUNNER_LABELS= RUNNER_LABELS=
# Optional: überschreibt runner.capacity aus config/runner.yaml zur Laufzeit.
# Leer lassen, um den Wert aus config/runner.yaml zu verwenden.
RUNNER_CAPACITY=
+1
View File
@@ -1,4 +1,5 @@
data/ data/
cache-secret
.vscode .vscode
.env .env
+80 -1
View File
@@ -1,3 +1,82 @@
# gitea_runner # gitea_runner
Enthält eine einfache docker-compose, um einen gitea_runner zu starten. Enthält eine einfache docker-compose, um einen gitea_runner zu starten.
## Verzeichnisstruktur
- `config/runner.yaml` — Konfiguration des Runners
- `config/cache.yaml` — Konfiguration des Cache-Servers
- `entrypoint.sh` — Wrapper-Entrypoint des Runner-Containers (siehe „Capacity über .env“ unten)
- `data/runner` — persistenter Zustand des Runners (u. a. `.runner`-Registrierungsdatei)
- `data/cache` — persistente Cache-Daten
- `cache-secret` — gemeinsames Secret für Runner ↔ Cache-Server (siehe unten, **nicht** in Git)
## Einrichtung
Vor dem ersten Start muss auf dem Host ein Secret für die Authentifizierung zwischen
Runner und Cache-Server erzeugt werden:
```sh
openssl rand -hex 32 > cache-secret
chmod 600 cache-secret
```
Diese Datei darf **nicht committet werden** (sie ist über `.gitignore` ausgeschlossen)
und muss auf jedem Host, auf dem dieses Setup läuft, individuell erzeugt werden.
## Migration von einer älteren Version dieses Compose-Setups
Frühere Versionen legten die Runner-Daten direkt unter `./data` ab und hatten kein
`config/`-Verzeichnis. Beim Umstieg auf diese Version muss der bestehende Datenordner
verschoben werden, sonst registriert sich der Runner erneut (verwaiste Registrierung
auf der Gitea-Instanz) und der bisherige Cache geht verloren:
```sh
# Runner vorher stoppen
docker compose down
# Repository pullen
git pull
# Vorhandene Daten (u. a. die .runner-Datei) nach data/runner verschieben
mv data data_old
mkdir -p data
mv data_old data/runner
# Danach ganz normal wieder starten
docker compose up -d
```
Falls vorher schon ein eigenständiger Cache-Ordner existierte (z. B. unter
`data/runner/cache` oder `cache-data/` aus einer Zwischenversion), diesen entsprechend
nach `data/cache` verschieben.
## Capacity über .env
Das offizielle `gitea/runner`-Image kennt keine Umgebungsvariable für `runner.capacity`
dieser Wert lässt sich nur über die `config.yaml` setzen. `entrypoint.sh` schließt diese
Lücke: beim Containerstart wird `config/runner.yaml` nach `/data/config.runtime.yaml`
kopiert und dort, falls `RUNNER_CAPACITY` in der `.env` gesetzt ist, per
`gitea-runner config set` überschrieben, bevor das eigentliche `run.sh` des Images
gestartet wird. Ist `RUNNER_CAPACITY` leer, bleibt der Wert aus `config/runner.yaml`
unverändert.
## Cache-Service
Der Cache läuft als eigener Service (`cache` in `docker-compose.yaml`), getrennt vom
Runner, damit die bis zu 5 parallel laufenden Jobs weiterhin jeweils ihr eigenes,
isoliertes Docker-Netzwerk bekommen und sich nicht gegenseitig erreichen können.
Job-Container erreichen den Cache-Server trotzdem über den Docker-Host (`cachehost`
wird per `--add-host=cachehost:host-gateway` auf das Host-Gateway gemappt, siehe
`config/runner.yaml` -> `container.options`), der Port `8088` des Cache-Servers ist
dafür auf dem Host veröffentlicht.
**Achtung:** Da Job-Container den Cache-Server nur über den Host erreichen können,
muss Port `8088` auf allen Host-Interfaces lauschen (`0.0.0.0`) — eine engere Bindung
(z. B. nur `127.0.0.1`) würde den Cache für Jobs unerreichbar machen. Der Zugriff ist
zwar durch das Secret in `cache-secret` geschützt, trotzdem sollte Port `8088` per
Host-Firewall von außen (Internet/fremdes LAN) blockiert werden, z. B.:
```sh
ufw deny 8088/tcp
```
View File
+5
View File
@@ -0,0 +1,5 @@
cache:
dir: /data
host: "0.0.0.0"
port: 8088
external_secret_file: "/run/cache-secret"
+20
View File
@@ -0,0 +1,20 @@
runner:
# Bis zu 5 Jobs gleichzeitig. container.network bleibt leer, damit jeder Job weiterhin
# sein eigenes isoliertes Docker-Netzwerk bekommt (kein gegenseitiger Zugriff der Jobs).
# Standardwert, falls RUNNER_CAPACITY in der .env nicht gesetzt ist (siehe entrypoint.sh).
capacity: 5
cache:
enabled: true
# Dedizierter, separater Cache-Server (siehe config/cache.yaml + docker-compose.yaml,
# Service "cache"), erreichbar über den Docker-Host-Gateway (siehe container.options
# unten), unabhängig vom isolierten Netzwerk des jeweiligen Jobs.
external_server: "http://cachehost:8088/"
external_secret_file: "/run/cache-secret"
container:
# Jeder Job bekommt ein eigenes, frisches Docker-Netzwerk (network bewusst leer gelassen),
# damit parallele Jobs sich nicht gegenseitig erreichen können. Damit die Job-Container
# trotzdem den externen Cache-Server erreichen, wird "cachehost" auf das Docker-Host-Gateway
# gemappt; der Cache-Server veröffentlicht seinen Port auf dem Host (siehe docker-compose.yaml).
options: "--add-host=cachehost:host-gateway"
+32 -2
View File
@@ -1,13 +1,43 @@
services: services:
runner: runner:
image: docker.io/gitea/runner:latest image: docker.io/gitea/runner:latest
container_name: gitea_runner
restart: unless-stopped
depends_on:
cache:
condition: service_healthy
entrypoint: ["/sbin/tini", "--", "bash", "/entrypoint.sh"]
environment: environment:
CONFIG_FILE: /config.yaml CONFIG_FILE: /config.yaml
RUNNER_CAPACITY: "${RUNNER_CAPACITY:-}"
GITEA_INSTANCE_URL: "${INSTANCE_URL}" GITEA_INSTANCE_URL: "${INSTANCE_URL}"
GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}" GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}"
GITEA_RUNNER_NAME: "${RUNNER_NAME}" GITEA_RUNNER_NAME: "${RUNNER_NAME}"
GITEA_RUNNER_LABELS: "${RUNNER_LABELS}" GITEA_RUNNER_LABELS: "${RUNNER_LABELS}"
volumes: volumes:
- ./config.yaml:/config.yaml - ./entrypoint.sh:/entrypoint.sh:ro
- ./data:/data - ./config/runner.yaml:/config.yaml:ro
- ./data/runner:/data
- ./cache-secret:/run/cache-secret:ro
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
extra_hosts:
- "cachehost:host-gateway"
cache:
image: docker.io/gitea/runner:latest
container_name: gitea_runner_cache
restart: unless-stopped
entrypoint: ["/sbin/tini", "--", "/usr/local/bin/gitea-runner"]
command: ["-c", "/config.yaml", "cache-server"]
volumes:
- ./config/cache.yaml:/config.yaml
- ./data/cache:/data
- ./cache-secret:/run/cache-secret:ro
ports:
- "8088:8088"
healthcheck:
test: ["CMD", "bash", "-c", "echo > /dev/tcp/127.0.0.1/8088"]
interval: 5s
timeout: 3s
retries: 10
start_period: 5s
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Kopiert die (read-only gemountete) config/runner.yaml in einen beschreibbaren
# Pfad in /data und wendet dort optional RUNNER_CAPACITY aus der .env an, bevor
# das eigentliche Runner-Entrypoint-Skript des Images gestartet wird.
set -euo pipefail
SOURCE_CONFIG="${CONFIG_FILE:-/config.yaml}"
RUNTIME_CONFIG="/data/config.runtime.yaml"
mkdir -p /data
cp "$SOURCE_CONFIG" "$RUNTIME_CONFIG"
if [[ -n "${RUNNER_CAPACITY:-}" ]]; then
gitea-runner config set -c "$RUNTIME_CONFIG" runner.capacity "$RUNNER_CAPACITY"
fi
export CONFIG_FILE="$RUNTIME_CONFIG"
exec /usr/local/bin/run.sh