Files

3.8 KiB

Auto-Deploy-Pipeline

Ziel: git push = neue Version automatisch live, ohne manuellen Eingriff.

Überblick

Code ändern → git push (Gitea) → ┬─ Webhook → Hermes-Receiver → SSH → Dokploy → Build + Deploy
                                 └─ Cron-Polling (alle 2 Min) → Dokploy → Build + Deploy

Es gibt zwei unabhängige Trigger, weil der Gitea-Webhook unzuverlässig ist (siehe „Warum zwei Trigger?"):

Mechanismus Latenz Zuverlässigkeit
Gitea-Webhook → Receiver ~5 s ⚠️ sporadisch
Cron-Polling ≤ 2 min ✅ garantiert

Komponenten

1. Gitea-Webhook

Per Gitea-API erstellt:

curl -X POST "https://git.kgessner.de/api/v1/repos/LuiiCode/techno-todo/hooks" \
  -H "Authorization: token $GITEA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "gitea",
    "config": {"url": "http://192.168.0.80:8002/hook", "content_type": "json"},
    "events": ["push"],
    "active": true
  }'

Zeigt auf den Webhook-Receiver auf dem Hermes-Server (192.168.0.80:8002).

2. Webhook-Receiver (Hermes)

Datei: /home/hermes/webhook-receiver.py

  • Python-Stdlib-http.server (keine Dependencies)
  • Lauscht auf 0.0.0.0:8002
  • Bei X-Gitea-Event: push auf refs/heads/main des Ziel-Repos:
    • startet asynchron (Thread) ssh root@192.168.0.184 /opt/deploy-techno-todo.sh
    • antwortet sofort mit 200 (Gitea wartet nicht auf den Deploy)
  • Loggt in /home/hermes/webhook-receiver.log

3. Deploy-Skript (Dokploy-Host)

Datei: /opt/deploy-techno-todo.sh

Idempotent — deployt nur, wenn es neue Commits gibt:

#!/bin/bash
set -euo pipefail
REPO_DIR="/opt/repos/techno-todo"
SERVICE_NAME="techno-todo-v2-mzs9mj"
cd "$REPO_DIR"

git fetch --all --prune >/dev/null 2>&1
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse origin/main)
[ "$LOCAL" = "$REMOTE" ] && { echo "UP-TO-DATE: $LOCAL"; exit 0; }

git reset --hard origin/main
COMMIT=$(git rev-parse --short HEAD)
docker build -t "techno-todo:${COMMIT}" .
docker tag "techno-todo:${COMMIT}" techno-todo:latest
docker service update --force --image "techno-todo:${COMMIT}" "$SERVICE_NAME"
echo "DONE: deployed ${COMMIT}"

Das Repo liegt persistent unter /opt/repos/techno-todo auf dem Dokploy-Host.

4. Cron-Polling (Fallback)

Auf dem Dokploy-Host:

*/2 * * * * /opt/deploy-techno-todo.sh >> /var/log/techno-todo-deploy.log 2>&1

Da das Skript idempotent ist, passiert bei „keine neuen Commits" nichts (exit 0).


Warum zwei Trigger?

Der Gitea-Webhook erwies sich beim POC als unzuverlässig: Von mehreren Pushes wurden nur einige ausgelöst, andere gingen verloren.

Root-Cause: Gitea läuft in einem Kubernetes-Cluster (Talos) auf Proxmox — also in einem anderen Netzwerk-Kontext als der Dokploy-Docker-Swarm-Host (192.168.0.184) und der Hermes-Server (192.168.0.80). Ausgehende Verbindungen aus dem K8s-Cluster zu internen 192.168.0.x-Adressen sind nicht zuverlässig möglich (CNI/NAT-Isolation).

Der Cron-Polling-Fallback umgeht das komplett: Er läuft direkt auf dem Dokploy-Host und holt sich den Git-Stand aktiv ab, statt auf einen eingehenden Webhook zu warten.


Setup-Reihenfolge (für eine neue App)

  1. Repo persistent auf Dokploy klonen: /opt/repos/<app>
  2. Deploy-Skript anpassen (Repo-Dir + Service-Name) → /opt/deploy-<app>.sh
  3. Cron-Job auf Dokploy einrichten (alle 2 Min)
  4. (Optional) Webhook-Receiver auf Hermes starten + Gitea-Webhook einrichten

Verifikation

# 1. Push machen
git push

# 2. Nach ~2 Min prüfen:
ssh root@192.168.0.184 "docker service ls --format '{{.Name}} {{.Image}}' | grep techno"
# → techno-todo-v2-mzs9mj  techno-todo:<neuer-commit>

# 3. Live testen:
curl -H "Host: techno-todo.192.168.0.184.sslip.io" http://192.168.0.184/