Aim the deploy at the runner that exists
The workflow asked for a `self-hosted` label. No runner on the instance offers one, so the run would have sat in "Waiting" forever — no error, no message, nothing to notice. The existing global runner elycon-runner-01 offers `docker` and `ubuntu-latest`, so both workflows now ask for `ubuntu-latest`, the same label ci.yml already used. That correction exposed a second thing the first version glossed over. act_runner starts a container per job; mounting the Docker socket into the *runner* does not put it in the *job*. Whether this job can reach the host's daemon depends on the runner's config.yaml, which is not visible from here — and the runner is global, so changing it affects every repository on the instance, not just this one. Rather than guess, the workflow now measures it in its first step and fails with the fix if it cannot: which config lines to add for the socket, or that SSH is the other way. Without that, the run would have died three steps later on a message nobody could act on. Both branches of the check were exercised: docker absent prints the first message, docker present with no reachable daemon the second. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
39
.github/workflows/deploy.yml
vendored
39
.github/workflows/deploy.yml
vendored
@@ -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
|
||||
|
||||
@@ -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=<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
|
||||
|
||||
Reference in New Issue
Block a user