docs(runner): Livegang-Anleitung (Netz, Compose, Firewall, deploy.sh-Vorschlag)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b7cbe3aa38
commit
126d556bd7
1 file changed
+147
@@ -0,0 +1,147 @@
|
||||
# Preview-Runner: Livegang-Anleitung (R18)
|
||||
|
||||
Stand: Vorschlag aus der Abschluss-Prüfung. Nichts davon ist im Repo umgesetzt, `deploy.sh`
|
||||
(`/home/webklar/apps/kundenbereich.webklar.com/deploy.sh`) liegt außerhalb des Repos und wird hier
|
||||
nur als Vorschlag beschrieben. Reihenfolge laut Spezifikation: L1 (Netz, Geheimnisse, Compose,
|
||||
Schema-Skript) vor L2 (Portal mit `PREVIEW_RUNNER=off`), dann L3 (`PREVIEW_RUNNER=on`).
|
||||
|
||||
## 1. Netzwerk `preview-sandbox` (VOR dem ersten Start anlegen)
|
||||
|
||||
```sh
|
||||
docker network create --subnet 172.30.0.0/24 preview-sandbox
|
||||
```
|
||||
|
||||
Der Runner verweigert den Start, wenn er keine IPv4-Adresse außerhalb dieses Subnetzes hat.
|
||||
`PREVIEW_SANDBOX_SUBNET` muss exakt dem Subnetz entsprechen. Das Subnetz nicht in Compose anders
|
||||
definieren (Netz als `external: true` einbinden).
|
||||
|
||||
Verzeichnisse auf dem Host anlegen (root-eigen genügt, der Runner setzt Besitzer 1000 selbst):
|
||||
|
||||
```sh
|
||||
mkdir -p /srv/webklar-preview-runner/work /srv/webklar-preview-runner/cache /var/www/previews
|
||||
```
|
||||
|
||||
## 2. Compose-Dienst (in `/home/webklar/apps/docker-compose.yml`)
|
||||
|
||||
Der Image-Build-Kontext ist `kundenbereich.webklar.com/build/runner` (Dockerfile im Repo unter
|
||||
`runner/`). Hostpfade stehen im Container unter dem IDENTISCHEN Pfad (R6).
|
||||
|
||||
```yaml
|
||||
preview-runner:
|
||||
build:
|
||||
context: ./kundenbereich.webklar.com/build/runner
|
||||
image: webklar-preview-runner:latest
|
||||
container_name: webklar-preview-runner
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
mem_limit: 256m
|
||||
# keine ports: - erreichbar nur im Docker-Netz webklar-network (Traefik) und vom Portal
|
||||
environment:
|
||||
- PREVIEW_RUNNER_TOKEN=${PREVIEW_RUNNER_TOKEN}
|
||||
- GITEA_URL=https://git.webklar.com
|
||||
- GITEA_TOKEN=${GITEA_SYSTEM_TOKEN} # lesender Token, der die WEBklar-Repos sehen darf
|
||||
- PREVIEW_BASE_HOST=project.webklar.com
|
||||
- PREVIEWS_ROOT=/var/www/previews
|
||||
- RUNNER_WORK_ROOT=/srv/webklar-preview-runner/work
|
||||
- RUNNER_CACHE_ROOT=/srv/webklar-preview-runner/cache
|
||||
- PREVIEW_SANDBOX_SUBNET=172.30.0.0/24
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /var/www/previews:/var/www/previews
|
||||
- /srv/webklar-preview-runner:/srv/webklar-preview-runner
|
||||
networks:
|
||||
- webklar-network
|
||||
- preview-sandbox
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=webklar-network
|
||||
- traefik.http.services.preview-runner.loadbalancer.server.port=8081
|
||||
# nur Dienst, kein Router: die Router erzeugt previewDeploy.syncPreviewTls (preview-runner@docker)
|
||||
|
||||
networks:
|
||||
preview-sandbox:
|
||||
external: true
|
||||
```
|
||||
|
||||
(Den `networks:`-Block in die bestehende Datei einfügen, nicht doppelt anlegen.) Keine Appwrite-,
|
||||
SMTP- oder Stripe-Variablen und kein `PREVIEW_ENV_KEY` im Runner.
|
||||
|
||||
Erster Start: `docker compose build preview-runner && docker compose up -d preview-runner`.
|
||||
|
||||
## 3. Portal-Umgebung (Dienst `kundenbereich-server`, Variablen einzeln auflisten)
|
||||
|
||||
```yaml
|
||||
- PREVIEW_RUNNER=${PREVIEW_RUNNER:-off} # L2: off, L3: on
|
||||
- PREVIEW_RUNNER_URL=http://webklar-preview-runner:8080
|
||||
- PREVIEW_RUNNER_TOKEN=${PREVIEW_RUNNER_TOKEN}
|
||||
- PREVIEW_ENV_KEY=${PREVIEW_ENV_KEY} # 32 Byte, Base64 (openssl rand -base64 32)
|
||||
```
|
||||
|
||||
Das Verzeichnis `upload-data/preview-logs` muss persistent sein (liegt in `./build/`).
|
||||
|
||||
## 4. Firewall für die Sandbox-Bridge (Livegang-Schritt, kein Code)
|
||||
|
||||
Zuerst den Bridge-Namen ermitteln: `BR=br-$(docker network inspect preview-sandbox -f '{{.Id}}' | cut -c1-12)`.
|
||||
|
||||
```sh
|
||||
# Sandbox -> Host (INPUT): alles verwerfen, bereits bestehende Antworten erlauben
|
||||
iptables -I INPUT -i $BR -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
iptables -A INPUT -i $BR -j DROP
|
||||
|
||||
# Sandbox -> andere Ziele (DOCKER-USER, wird vor Docker-Regeln ausgewertet)
|
||||
iptables -I DOCKER-USER -s 172.30.0.0/24 -d 169.254.169.254 -j DROP # Hetzner-Metadaten
|
||||
iptables -I DOCKER-USER -s 172.30.0.0/24 -d 10.0.0.0/8 -j DROP
|
||||
iptables -I DOCKER-USER -s 172.30.0.0/24 -d 192.168.0.0/16 -j DROP
|
||||
# 172.16.0.0/12 (andere Docker-Netze) sperren, ausser dem eigenen /24; Runner-Zugriff wird nicht gebraucht
|
||||
iptables -I DOCKER-USER -s 172.30.0.0/24 -d 172.30.0.0/24 -j ACCEPT # Dev-zu-Dev im eigenen Netz (R13, bekannt)
|
||||
iptables -I DOCKER-USER -s 172.30.0.0/24 ! -d 172.30.0.0/24 -d 172.16.0.0/12 -j DROP
|
||||
```
|
||||
|
||||
Reihenfolge beachten: `-I` setzt vorne ein, die ACCEPT-Regel für das eigene /24 muss vor dem
|
||||
172.16/12-DROP stehen (also zuletzt mit `-I` eingefügt, wie oben die Zeilen in umgekehrter
|
||||
Wirkungsreihenfolge; nach dem Einrichten mit `iptables -S DOCKER-USER` prüfen). DNS läuft über den
|
||||
Docker-Resolver (127.0.0.11) und bleibt erlaubt, Ausgang ins Internet (npm, Registries) ebenfalls.
|
||||
Regeln persistent machen (z. B. `iptables-persistent`), sonst gehen sie beim Neustart verloren.
|
||||
|
||||
## 5. deploy.sh-Erweiterung (Vorschlag, bewusst NICHT eingespielt)
|
||||
|
||||
Voraussetzung: der Build-Container (`kundenbereich-build`) bekommt zusätzlich
|
||||
`/home/webklar/apps/docker-compose.yml:/compose/docker-compose.yml:ro` eingehängt und hat
|
||||
`docker-cli` samt Compose-Plugin. Der Runner wird nur neu gebaut und neu erstellt, wenn sich
|
||||
`runner/` geändert hat UND `GET /status` eine leere Warteschlange meldet (sonst würden laufende
|
||||
Builds/Dev-Server beendet); andernfalls überspringen und protokollieren, der nächste Deploy versucht
|
||||
es erneut. Der Runner wird VOR dem Portal neu gestartet, damit dessen Dev-Registrierung gleich
|
||||
klappt (der Abgleich im Portal holt Verpasstes ohnehin alle 2 Minuten nach).
|
||||
|
||||
Einfügen direkt vor dem Neustart des Portals; vor dem `git reset --hard` den alten Stand merken
|
||||
(`OLD_HEAD=$(git rev-parse HEAD 2>/dev/null || true)`):
|
||||
|
||||
```sh
|
||||
# --- Preview-Runner (nur wenn runner/ geaendert) ---
|
||||
if [ -S /var/run/docker.sock ] && command -v docker >/dev/null 2>&1 && [ -f /compose/docker-compose.yml ]; then
|
||||
NEW_HEAD=$(git rev-parse HEAD)
|
||||
if [ -z "${OLD_HEAD}" ] || ! git diff --quiet "${OLD_HEAD}" "${NEW_HEAD}" -- runner 2>/dev/null; then
|
||||
QUEUE=$(docker exec webklar-preview-runner sh -c \
|
||||
'wget -qO- --header "Authorization: Bearer $PREVIEW_RUNNER_TOKEN" http://127.0.0.1:8080/status' 2>/dev/null \
|
||||
| sed -n 's/.*"queue":\([0-9]*\).*/\1/p')
|
||||
if [ -z "${QUEUE}" ] || [ "${QUEUE}" = "0" ]; then
|
||||
echo "Preview-Runner: Image neu bauen und Container neu erstellen..."
|
||||
docker build -t webklar-preview-runner:latest /app/runner \
|
||||
&& docker compose -f /compose/docker-compose.yml --project-directory /home/webklar/apps \
|
||||
up -d --no-build --no-deps preview-runner \
|
||||
|| echo "Preview-Runner: Aktualisierung fehlgeschlagen (Portal-Deploy laeuft weiter)"
|
||||
else
|
||||
echo "Preview-Runner: Warteschlange nicht leer (${QUEUE}) - Aktualisierung uebersprungen, naechster Deploy versucht es erneut"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
Hinweise: Ist der Runner noch nicht angelegt (`docker exec` schlägt fehl, `QUEUE` leer), wird gebaut
|
||||
und erstellt, das ist beim ersten Mal gewollt. `wget` ist im Alpine-Image enthalten. Die
|
||||
Status-Abfrage bitte vor dem Einspielen einmal von Hand gegenprüfen.
|
||||
|
||||
## 6. Rückfall
|
||||
|
||||
`PREVIEW_RUNNER=off` und Portal neu starten: Der bisherige Weg läuft unverändert. Dokumente behalten
|
||||
`previewMode`/`previewState`, die Dev-Router verschwinden beim nächsten TLS-Sync.
|
||||
Reference in new issue
Block a user