diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index dbac240..0d87362 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -24,8 +24,45 @@ concurrency: jobs: deploy: name: Migrationen und Container - runs-on: self-hosted + # `ubuntu-latest`, weil der vorhandene Runner (elycon-runner-01) genau + # diese Bezeichnung anbietet — neben `docker`. Ein Label, das kein Runner + # führt, lässt den Lauf wortlos in der Warteschlange stehen: kein Fehler, + # keine Meldung, nur „Waiting". + runs-on: ubuntu-latest steps: + # ── Vorprüfung ────────────────────────────────────────────────── + # + # Dieser Job läuft in einem Container, den der Runner startet — nicht + # auf dem Server selbst. Ob er den Docker-Dienst des **Hosts** erreicht, + # hängt davon ab, wie der Runner konfiguriert ist; von aussen ist das + # nicht zu sehen. Statt es zu raten, wird es hier gemessen und im + # Fehlerfall gesagt, was fehlt — sonst scheitert der Lauf erst drei + # Schritte später an einer Meldung, die niemandem weiterhilft. + - name: Erreicht dieser Job den Docker-Dienst des Servers? + run: | + set -u + if ! command -v docker >/dev/null 2>&1; then + echo 'Im Job-Container gibt es kein "docker".' + echo + echo "Zwei Wege:" + echo " a) Im Runner (config.yaml) ein Abbild verwenden, das die Docker-CLI" + echo " mitbringt, und den Socket durchreichen — siehe DEPLOYMENT.md §5." + echo " b) Statt lokal per SSH auf den Server ausrollen." + exit 1 + fi + if ! docker info >/dev/null 2>&1; then + echo "Docker-CLI vorhanden, aber kein Dienst erreichbar." + echo + echo "Dem Job-Container fehlt der Socket des Hosts. In der config.yaml des" + echo "Runners:" + echo " container:" + echo " options: -v /var/run/docker.sock:/var/run/docker.sock" + echo " valid_volumes: [/var/run/docker.sock]" + echo "Danach den Runner neu starten. Alternative: Deploy per SSH." + exit 1 + fi + docker compose version + - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 9dd1f05..7bd2202 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -230,37 +230,44 @@ Zuständig ist [`.github/workflows/deploy.yml`](.github/workflows/deploy.yml). > `ci.yml` stillschweigend abschalten. Solange beide Dateien unter `.github/` > liegen, sieht Gitea beide. -### a) Runner registrieren +### a) Der Runner -Der Runner läuft als Container **auf demselben Server** wie die Anwendung und -bekommt den Docker-Socket des Hosts eingehängt — damit baut und startet er die -Container des Hosts, statt welche in sich selbst zu erzeugen. +Verwendet wird der bestehende, globale Runner **`elycon-runner-01`** (act_runner +v0.2.11, Labels `docker` und `ubuntu-latest`). Ein eigener ist nicht nötig. -Registrierungs-Token holen: Gitea → Repository → *Settings* → *Actions* → -*Runners* → *Create new runner*. +Beide Workflows laufen deshalb auf `ubuntu-latest`. **Ein Label, das kein +Runner führt, lässt den Lauf wortlos in der Warteschlange stehen** — kein +Fehler, keine Meldung, nur „Waiting". Das ist der häufigste Grund, warum +scheinbar nichts passiert. -```bash -mkdir -p /opt/gitea-runner && cd /opt/gitea-runner +#### Der Job läuft im Container, nicht auf dem Server -docker run -d --name gitea-runner --restart unless-stopped \ - -e GITEA_INSTANCE_URL=https://git.elycon.solutions \ - -e GITEA_RUNNER_REGISTRATION_TOKEN= \ - -e GITEA_RUNNER_NAME=alpenwerk-deploy \ - -e GITEA_RUNNER_LABELS=self-hosted,ubuntu-latest \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v /opt/gitea-runner:/data \ - gitea/act_runner:latest +Das ist die Stelle, an der es klemmen kann. act_runner startet je Job einen +eigenen Container; der Docker-Socket des **Hosts** ist darin nur, wenn der +Runner so konfiguriert ist: + +```yaml +# config.yaml des Runners +container: + options: -v /var/run/docker.sock:/var/run/docker.sock + valid_volumes: + - /var/run/docker.sock ``` -Zu den Labels: `self-hosted` verlangt der Deploy-Workflow, `ubuntu-latest` die -bestehende `ci.yml`. Fehlt eines, bleibt der jeweilige Lauf ohne Fehlermeldung -in der Warteschlange — **das ist der häufigste Grund, warum „nichts passiert"**. +Zusätzlich muss das Job-Abbild die Docker-CLI mitbringen (die üblichen +`runner-images`/`catthehacker`-Abbilder tun das). -> Der eingehängte Docker-Socket gibt dem Runner faktisch Wurzelrechte auf dem -> Host. Das ist bei einem Deploy-Runner der Zweck der Übung, aber es heisst -> auch: wer in dieses Repository schreiben darf, darf auf diesem Server alles. -> Bei zwei Personen vertretbar; bei einem grösseren Kreis gehört der Runner auf -> eine eigene Maschine, die sich per SSH verbindet. +Der erste Schritt des Deploy-Workflows prüft genau das und bricht mit einer +Anleitung ab, wenn etwas fehlt — statt drei Schritte später an einer Meldung zu +scheitern, mit der niemand etwas anfangen kann. + +> Der durchgereichte Socket gibt dem Job faktisch Wurzelrechte auf dem Host. +> Bei einem Deploy-Runner ist das der Zweck der Übung, aber es heisst auch: wer +> in dieses Repository schreiben darf, darf auf diesem Server alles. Bei einem +> **globalen** Runner gilt das für jedes Repository der Instanz, das denselben +> Socket benutzt. Ist das zu weit gefasst, ist der Weg über SSH der richtige: +> ein Schlüssel als Repository-Secret, der nur auf den einen Server und nur auf +> das Deploy-Verzeichnis zeigt. ### b) Secrets hinterlegen @@ -370,10 +377,9 @@ Single-Instance-Compose-Konfiguration ist das nicht nötig. - **Push gemacht, aber kein Lauf startet:** meist die Labels. Der Lauf steht dann in Gitea unter *Actions* als „Waiting" — ohne Fehlermeldung, weil kein - Runner das verlangte Label anbietet. `deploy.yml` verlangt `self-hosted`, - `ci.yml` verlangt `ubuntu-latest`. Welche Labels registriert sind, zeigt - Gitea → *Settings* → *Actions* → *Runners*; ändern lassen sie sich durch - erneutes Registrieren. + Runner das verlangte Label anbietet. Beide Workflows verlangen + `ubuntu-latest`; `elycon-runner-01` führt es. Welche Labels registriert sind, + zeigt Gitea → *Site Administration* → *Actions* → *Runners*. - **Deploy läuft, aber es entsteht ein zweiter Stapel:** `COMPOSE_PROJECT_NAME` passt nicht zum bestehenden. Auf dem Server `docker compose ls` — der dort gelistete Name gehört als Variable ins Repository. Bis dahin läuft die alte