diff --git a/.gitea/workflows/image.yml b/.gitea/workflows/image.yml new file mode 100644 index 0000000..051c755 --- /dev/null +++ b/.gitea/workflows/image.yml @@ -0,0 +1,75 @@ +# Baut das Flaro-Image und legt es in die Registry dieses Gitea. +# +# **Warum hier und nicht auf dem Arbeitsrechner.** Ein Bau von Hand heisst: +# jemand muss daran denken, muss die richtige Architektur angeben und muss +# angemeldet sein. Hier passiert es bei jedem Push von selbst, immer für +# beide Architekturen, und die Anmeldung besorgt Gitea. +# +# **Voraussetzung ist ein Runner.** Ohne einen registrierten Act-Runner +# läuft diese Datei nie an — dann bleibt der Weg von Hand aus +# `Tools/image-veroeffentlichen.sh`. + +name: Image bauen und veröffentlichen + +on: + push: + branches: [main] + tags: ['v*'] + workflow_dispatch: + +jobs: + image: + runs-on: ubuntu-latest + + steps: + - name: Quelltext holen + uses: actions/checkout@v4 + + # **buildx, nicht das eingebaute `docker build`.** Nur damit lassen + # sich zwei Architekturen in einem Manifest ablegen; ohne das bekommt + # ein Intel-NAS ein arm64-Image und meldet „exec format error". + - name: buildx vorbereiten + uses: docker/setup-buildx-action@v3 + + - name: QEMU für die fremde Architektur + uses: docker/setup-qemu-action@v3 + + - name: An der Registry anmelden + uses: docker/login-action@v3 + with: + registry: ${{ vars.REGISTRY || 'git.scarriffle.com' }} + username: ${{ gitea.actor }} + password: ${{ secrets.GITEA_TOKEN }} + + - name: Marken bestimmen + id: marken + run: | + REGISTRY="${{ vars.REGISTRY || 'git.scarriffle.com' }}" + # Gitea verlangt Kleinbuchstaben im Pfad; der Besitzername kann + # gross geschrieben sein. + PFAD=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]') + BILD="$REGISTRY/$PFAD" + + MARKEN="$BILD:latest,$BILD:${GITHUB_SHA::7}" + # Auf einem Git-Tag zusätzlich dessen Namen — damit sich eine + # Fassung festnageln lässt, statt immer „latest" zu ziehen. + if [ "${GITHUB_REF_TYPE}" = "tag" ]; then + MARKEN="$MARKEN,$BILD:${GITHUB_REF_NAME#v}" + fi + echo "marken=$MARKEN" >> "$GITHUB_OUTPUT" + echo "Gebaut wird: $MARKEN" + + - name: Bauen und hochladen + uses: docker/build-push-action@v5 + with: + context: . + file: server/Dockerfile + # **Beide Architekturen.** amd64 für die Intel-NAS, arm64 für + # ARM-Geräte und für den Apple-Rechner. + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.marken.outputs.marken }} + # Zwischenergebnisse behalten: ohne das lädt jeder Lauf alle + # Pakete neu, und ein Bau dauert statt zwei Minuten zwölf. + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Tools/image-veroeffentlichen.sh b/Tools/image-veroeffentlichen.sh new file mode 100755 index 0000000..5cf7555 --- /dev/null +++ b/Tools/image-veroeffentlichen.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Baut das Flaro-Image für beide Architekturen und legt es in die Registry. +# +# **Der Weg von Hand** — für den Fall, dass kein Gitea-Runner läuft. Sonst +# macht das `.gitea/workflows/image.yml` bei jedem Push von selbst. +# +# Tools/image-veroeffentlichen.sh → :latest +# Tools/image-veroeffentlichen.sh 0.2.0 → :latest und :0.2.0 +# +# Vorher einmalig anmelden — das Passwort tippst du selbst ein: +# +# docker login git.scarriffle.com + +set -euo pipefail + +REGISTRY="${FLARO_REGISTRY:-git.scarriffle.com}" +PFAD="${FLARO_IMAGE_PATH:-scarriffle/flaro}" +BILD="$REGISTRY/$PFAD" +FASSUNG="${1:-}" + +cd "$(dirname "$0")/.." + +command -v docker >/dev/null || { echo "docker fehlt."; exit 1; } + +# **Ohne Anmeldung bricht der Push erst nach dem ganzen Bau ab.** Zwei +# Minuten Arbeit für eine Fehlermeldung, die am Anfang gestanden hätte. +# Kein `docker info | grep -q`: `grep -q` beendet die Pipe beim ersten +# Treffer, Docker bekommt SIGPIPE, und mit `set -o pipefail` gilt das als +# Fehlschlag. Die Prüfung meldete dann „Docker läuft nicht", während es lief. +if ! docker info >/dev/null 2>&1; then + echo "Docker läuft nicht."; exit 1 +fi +if ! grep -q "$REGISTRY" ~/.docker/config.json 2>/dev/null; then + echo "Nicht an $REGISTRY angemeldet. Erst:" + echo + echo " docker login $REGISTRY" + exit 1 +fi + +MARKEN=(-t "$BILD:latest") +[ -n "$FASSUNG" ] && MARKEN+=(-t "$BILD:$FASSUNG") + +# **Ein eigener Builder.** Der Vorgabe-Builder von Docker Desktop kann kein +# Manifest mit zwei Architekturen bauen; `docker buildx create` schon. +docker buildx inspect flaro-bauer >/dev/null 2>&1 \ + || docker buildx create --name flaro-bauer --use >/dev/null + +echo "Baue $BILD für amd64 und arm64 — das dauert, arm64 läuft unter Emulation." +docker buildx build \ + --builder flaro-bauer \ + --platform linux/amd64,linux/arm64 \ + -f server/Dockerfile \ + "${MARKEN[@]}" \ + --push . + +echo +echo "Fertig. Auf dem NAS:" +echo " image: $BILD:${FASSUNG:-latest}" diff --git a/docs/NAS-EINRICHTEN.md b/docs/NAS-EINRICHTEN.md index df15e2d..bdb3b06 100644 --- a/docs/NAS-EINRICHTEN.md +++ b/docs/NAS-EINRICHTEN.md @@ -49,38 +49,75 @@ Drei Wege. Der erste ist der bequemste, der zweite braucht keine Registry. Dein Gitea unter `git.scarriffle.com` bringt eine Container-Registry mit. Einmal einrichten, danach ist jedes Update ein `docker compose pull`. -Auf dem Arbeitsrechner: +#### A1 · Gitea baut selbst + +`.gitea/workflows/image.yml` liegt im Projekt. Bei jedem Push auf `main` +baut Gitea das Image für **beide** Architekturen und legt es ab — ohne dass +jemand daran denken muss, und ohne Anmeldung am Arbeitsrechner. + +**Voraussetzung ist ein registrierter Act-Runner.** Hat dein Gitea keinen, +passiert nichts; dann gilt A2. Nachsehen unter +*Einstellungen → Actions → Runner*. Ein Runner lässt sich als Container +neben Gitea betreiben: + +```bash +docker run -d --restart unless-stopped --name gitea-runner \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e GITEA_INSTANCE_URL=https://git.scarriffle.com \ + -e GITEA_RUNNER_REGISTRATION_TOKEN= \ + gitea/act_runner:latest +``` + +#### A2 · Von Hand vom Arbeitsrechner + +Einmalig anmelden — das Passwort tippst du selbst ein: ```bash docker login git.scarriffle.com ``` +Danach genügt ein Befehl; er baut amd64 **und** arm64 und lädt hoch: + ```bash -cd ~/Projects_Coding/Flixy -docker buildx build --platform linux/amd64 \ - -f server/Dockerfile \ - -t git.scarriffle.com/scarriffle/flaro:latest \ - --push . +Tools/image-veroeffentlichen.sh ``` -`--push` lädt direkt hoch; ein getrenntes `docker push` entfällt. +Mit einer Fassungsnummer, wenn du sie festnageln willst: -Auf dem NAS dann in der Compose-Datei: +```bash +Tools/image-veroeffentlichen.sh 0.2.0 +``` + +#### A3 · Das Paket öffentlich stellen + +Sonst muss sich auch das NAS anmelden. In Gitea unter +*dein Profil → Pakete → flaro → Einstellungen* auf öffentlich stellen. Der +Quelltext ist ohnehin offen; das Image enthält nichts, was er nicht auch +enthält. + +#### A4 · Die Registry im NAS eintragen + +In der Docker-App des UGREEN: **Repository → Zahnrad → Quellname des +Images → Hinzufügen**. Dort stehen schon DockerHub und `ghcr.io`; daneben +kommt: + +| Feld | Wert | +|---|---| +| Alias | `gitea` | +| Link | `https://git.scarriffle.com/` | + +**Bestätigen** — danach findet die Suche in der Docker-App auch +`scarriffle/flaro`. Ist das Paket privat, trägst du unter +*Registierungseinstellungen* Benutzername und ein Gitea-Zugriffstoken ein +(nicht dein Kontopasswort: ein Token lässt sich einzeln widerrufen, unter +*Einstellungen → Anwendungen → Zugriffstoken*, Berechtigung `read:package`). + +In der Compose-Datei steht dann: ```yaml image: git.scarriffle.com/scarriffle/flaro:latest ``` -Ist das Paket in Gitea **privat**, muss sich auch das NAS anmelden: - -```bash -docker login git.scarriffle.com -``` - -Einfacher ist, das Paket in Gitea auf öffentlich zu stellen — unter -*Pakete → flaro → Einstellungen*. Der Quelltext ist ohnehin offen; das Image -enthält nichts, was es nicht auch tut. - ### Weg B — als Datei hochladen Ohne Registry, dafür bei jedem Update von Hand. diff --git a/server/docker-compose.example.yml b/server/docker-compose.example.yml index 24c0d36..c68e1b3 100644 --- a/server/docker-compose.example.yml +++ b/server/docker-compose.example.yml @@ -5,7 +5,9 @@ services: flaro: - image: ghcr.io/scarriffle/flaro:latest + # Die Registry des eigenen Gitea. Wer woanders veröffentlicht, trägt + # hier etwas anderes ein — siehe docs/NAS-EINRICHTEN.md. + image: git.scarriffle.com/scarriffle/flaro:latest container_name: flaro restart: unless-stopped