Reorganised deployment scripts and added rollback functionality. Updated documentation and workflow for container image builds.
Test and publish container images / test (push) Successful in 2m50s
Test and publish container images / publish (push) Failing after 54s

This commit is contained in:
BuTzZ
2026-07-25 12:36:35 +02:00
parent 12eee8d211
commit c9a20aacd7
17 changed files with 642 additions and 73 deletions
+78 -13
View File
@@ -12,11 +12,11 @@ cp deploy/.env.production.example deploy/.env.production
editor deploy/.env.production
```
Mindestens `WATERMAPS_ACME_EMAIL` muss angepasst werden. Der Hetzner-API-Token
gehört **nicht** in diese Datei. Er bleibt lokal in der ignorierten Datei
`infra/opentofu/terraform.tfvars` (alternativ kann der Provider
`TF_VAR_hcloud_token` lesen). Der Upload schließt Terraform-Variablen, Pläne,
State, lokale Env-Dateien und `.terraform` in jeder Verzeichnistiefe aus.
Mindestens `WATERMAPS_ACME_EMAIL` muss angepasst werden. Außerdem müssen
`WATERMAPS_REGISTRY` und `WATERMAPS_REGISTRY_OWNER` auf die Gitea Container
Registry zeigen. Der Hetzner-API-Token gehört **nicht** in diese Datei. Er
bleibt lokal in der ignorierten Datei `infra/opentofu/terraform.tfvars`
(alternativ kann der Provider `TF_VAR_hcloud_token` lesen).
Die private SSH-Keydatei wird ebenfalls nicht gespeichert. Sie kann beim
Deployment mit `--identity` oder über `WATERMAPS_SSH_KEY` angegeben werden.
@@ -26,24 +26,64 @@ Angaben erforderlich. Der vorbereitete SSH-Benutzer heißt standardmäßig
`deploy`; die privilegierten Installationsschritte laufen über dessen
passwortloses `sudo`.
## Gitea Actions und Container Registry
Der Workflow `.gitea/workflows/container-images.yml` führt Typechecks und Tests
aus. Nach einem erfolgreichen Push auf `main` baut und veröffentlicht er zwei
OCI-Images unter der vollständigen Git-Commit-SHA:
```text
gitea.incoso.eu/kevin_janssen/watermaps:<commit-sha>
gitea.incoso.eu/kevin_janssen/watermaps-route-data:<commit-sha>
```
In Gitea müssen Repository Actions aktiviert und ein Docker-fähiger
`ubuntu-latest`-Runner registriert sein. Unter
`Repository → Settings → Actions → Secrets` werden benötigt:
- `REGISTRY_USERNAME`: Gitea-Benutzer, dem die Packages gehören
- `REGISTRY_TOKEN`: Personal Access Token mit `package: Read and Write`
Der separate PAT ist derzeit nötig, weil Giteas eingebauter Job-Token
OCI-Pakete noch nicht zuverlässig veröffentlichen kann. Für Pull Requests
werden nur Tests ausgeführt; Registry-Secrets werden dabei nicht verwendet.
## Deployment
Nach `tofu apply` liest dieses Skript standardmäßig den Output `server_ipv4`,
überträgt das Projekt ohne State, lokale Daten oder Node-Module und startet den
Serverbootstrap sowie den Docker-Stack:
Nach einem erfolgreichen Image-Build liest das Skript standardmäßig den
OpenTofu-Output `server_ipv4`. Es erlaubt ausschließlich einen sauberen,
vollständig committeten Git-Stand und überträgt nur den kleinen Ordner
`deploy/`, nicht den Anwendungsquellcode. Die Image-Tags entsprechen exakt
`git rev-parse HEAD`.
Ist die Registry privat, werden einmalig beziehungsweise nach Tokenwechsel
lokale Pull-Zugangsdaten mitgegeben:
```bash
./deploy/scripts/upload-and-deploy.sh --identity ~/.ssh/watermaps_hetzner_ed25519
WATERMAPS_REGISTRY_USERNAME=kevin_janssen \
WATERMAPS_REGISTRY_TOKEN='<package-read-token>' \
./deploy/scripts/upload-and-deploy.sh \
--identity ~/.ssh/watermaps_hetzner_ed25519
```
Alternativ:
Der Token benötigt auf dem Produktionsserver nur `package: Read`. Er wird per
SSH an `docker login --password-stdin` übergeben, nicht in
`.env.production`, einem Container oder dem Image gespeichert. Docker legt die
Anmeldung root-lesbar in seiner lokalen Client-Konfiguration ab. Bei späteren
Deployments muss der Token nicht erneut angegeben werden, solange die
Anmeldung gültig ist:
```bash
WATERMAPS_SERVER_IPV4=203.0.113.10 \
WATERMAPS_SSH_KEY=~/.ssh/watermaps_hetzner_ed25519 \
./deploy/scripts/upload-and-deploy.sh
./deploy/scripts/upload-and-deploy.sh \
--identity ~/.ssh/watermaps_hetzner_ed25519
```
Das Serverskript lädt App, Routingdaten-Builder, Nginx und Certbot mit
`docker compose pull`. Die beiden commitgenauen Gitea-Tags werden anschließend
in ihre unveränderlichen Registry-Digests aufgelöst. Erst danach werden die
Container mit `--no-build` gestartet. Der Produktionsserver benötigt deshalb
weder Git noch Node/npm oder den Quellcode.
Der erste Datenaufbau lädt die Geofabrik-Extrakte für Deutschland und die
Niederlande herunter und kann entsprechend der Serverleistung längere Zeit
dauern. Der produktive Index liegt auf dem Server unter:
@@ -63,6 +103,30 @@ persistente Swap-Reserve ein.
Vor dem Livegang antwortet Nginx nur für ACME-Challenges. Alle anderen
HTTP-Anfragen erhalten 404.
## Rollback
Jedes erfolgreiche Release wird mit Commit-SHA und den aufgelösten
Image-Digests unter `/srv/watermaps-runtime/deployments/` gespeichert. Scheitert
ein Deployment nach dem Containerwechsel, startet `deploy.sh` automatisch das
vorherige Release und führt die Health- und Routentests erneut aus.
Das unmittelbar vorherige Release lässt sich auch manuell aktivieren:
```bash
./deploy/scripts/remote-rollback.sh \
--identity ~/.ssh/watermaps_hetzner_ed25519
```
Oder ein bestimmter, bereits erfolgreich deployter Commit:
```bash
./deploy/scripts/remote-rollback.sh \
--revision 0123456789abcdef0123456789abcdef01234567 \
--identity ~/.ssh/watermaps_hetzner_ed25519
```
Der Rollback verwendet gespeicherte Digests, nicht einen beweglichen Tag.
## DNS und SSL-Livegang
Sobald der OpenTofu-Output bekannt ist, kann folgender DNS-Eintrag gesetzt
@@ -103,5 +167,6 @@ journalctl -u watermaps-certbot-renew.service
docker compose \
--project-directory /opt/watermaps \
--env-file /opt/watermaps/deploy/.env.production \
--env-file /opt/watermaps/deploy/.env.images \
-f /opt/watermaps/deploy/compose.production.yml ps
```