245 lines
10 KiB
Markdown
245 lines
10 KiB
Markdown
# Deployment mit einem Image aus der Container Registry
|
|
|
|
Proxmox AIS wird auf dem Zielserver aus einem bereits veröffentlichten
|
|
Containerimage gestartet. Der [Gitea-Actions-Workflow](gitea-actions.md) erstellt dieses Image; auf dem
|
|
Zielserver werden nur Docker Compose und die Betriebskonfiguration benötigt.
|
|
Diese Anleitung setzt einen erfolgreichen `container-publish`-Job und ein
|
|
weiterhin abrufbares Image voraus.
|
|
|
|
## Voraussetzungen und Dateien
|
|
|
|
Der Zielserver benötigt Linux auf amd64, Docker Engine, das Docker-Compose-Plugin
|
|
und einen HTTPS-Reverse-Proxy. Die Docker-Befehle unter einem Deploymentkonto
|
|
mit Docker-Zugriff ausführen. Dasselbe Konto für `docker login` und
|
|
`docker compose` verwenden, damit die Registry-Anmeldung verfügbar ist.
|
|
Die [Docker-Installationsanleitung](https://docs.docker.com/engine/install/debian/)
|
|
beschreibt beispielsweise die Installation auf Debian.
|
|
|
|
Python, Node.js, ein CI-Runner und Build-Werkzeuge gehören zur Build-Umgebung;
|
|
die Anwendung samt Laufzeit ist im veröffentlichten Image enthalten. Ein
|
|
Checkout des Anwendungsquellcodes ist auf dem Zielserver nicht erforderlich.
|
|
|
|
Ein beschreibbares Deploymentverzeichnis bereitstellen, beispielsweise
|
|
`/opt/proxmox-ais`, und diese beiden Dateien aus dem gewünschten Projektstand
|
|
herunterladen beziehungsweise dorthin kopieren:
|
|
|
|
| Datei aus dem Repository | Dateiname auf dem Zielserver |
|
|
| --- | --- |
|
|
| [compose.yaml](../compose.yaml) | `/opt/proxmox-ais/compose.yaml` |
|
|
| [config/deployment.env.example](../config/deployment.env.example) | `/opt/proxmox-ais/.env` |
|
|
|
|
Im weiteren Verlauf alle Compose-Befehle in diesem Verzeichnis ausführen:
|
|
|
|
```bash
|
|
cd /opt/proxmox-ais
|
|
chmod 600 .env
|
|
docker version
|
|
docker compose version
|
|
```
|
|
|
|
Die Compose-Datei verwendet das Image aus `PROVISIONER_IMAGE`. Ein fehlender
|
|
Wert führt bereits bei der Konfigurationsprüfung zu einem Fehler.
|
|
|
|
## Image und öffentliche Adresse festlegen
|
|
|
|
In Gitea unter **Actions** den erfolgreichen Workflow-Lauf mit
|
|
`container-publish` öffnen, unter **Artifacts** das Archiv `container-deploy`
|
|
herunterladen und entpacken. Es enthält `build.env` und `deploy.env`.
|
|
Die vollständige Zeile `PROVISIONER_IMAGE=…@sha256:…` aus `deploy.env` in die
|
|
`.env` auf dem Zielserver übernehmen. Der Digest legt genau das veröffentlichte
|
|
Image fest. Compose liest `deploy.env` nicht automatisch ein.
|
|
|
|
Alternativ in Gitea beim Benutzer `BartelLuis` das zugehörige **Packages**-Paket
|
|
öffnen und den vollständigen
|
|
Imagepfad mit einem tatsächlich vorhandenen Versions-Tag kopieren. Der aktuelle
|
|
Imagepfad der Beispieldatei sieht so aus:
|
|
|
|
```dotenv
|
|
PROVISIONER_IMAGE=gitlab.bartelluis.de/bartelluis/proxmox-ais-server:0.9.1
|
|
PUBLIC_URL=https://provision.example.net
|
|
MAINTENANCE=false
|
|
```
|
|
|
|
`PROVISIONER_IMAGE` und `PUBLIC_URL` für die Installation festlegen. Der
|
|
Imagepfad entspricht dem aktuellen Wert der Vorlage; die Verfügbarkeit des
|
|
Tags `0.9.1` wird damit nicht vorausgesetzt. Maßgeblich sind das
|
|
Pipeline-Artefakt oder die Registry-Anzeige deines Projekts.
|
|
Der Registry-Endpunkt der Vorlage ist `gitlab.bartelluis.de`. Bei einer abweichenden
|
|
CI-Registry den Host aus `deploy.env` auch für `docker login` verwenden.
|
|
Für reproduzierbare Deployments den Digest
|
|
bevorzugen und die bisher verwendeten Digests für spätere Updates aufbewahren.
|
|
|
|
`PUBLIC_URL` ist die vollständige HTTPS-Basisadresse ohne zusätzlichen Pfad,
|
|
unter der Browser, Installer und installierte Hosts den Dienst erreichen.
|
|
DNS und Zertifikatskette müssen für diese Systeme gültig sein. Der
|
|
Reverse-Proxy auf dem Zielserver leitet diese Adresse an
|
|
`http://127.0.0.1:8080` weiter. Der Compose-Port ist nur auf Loopback gebunden.
|
|
Bei einem Proxy auf einem anderen Host oder in einem anderen Container dessen
|
|
Verbindung gezielt nach der [Betriebsanleitung](operations.md#tls-und-reverse-proxy)
|
|
einrichten; `127.0.0.1` bezeichnet dort jeweils das eigene System.
|
|
|
|
## An der Registry anmelden und Image laden
|
|
|
|
Öffentliche Gitea-Pakete lassen sich ohne Anmeldung herunterladen. Für ein
|
|
privates Paket einen Gitea Personal Access Token mit dem Scope
|
|
`read:package` verwenden. Das zugehörige Gitea-Konto benötigt Lesezugriff auf
|
|
das Paket. Der Token wird
|
|
bei der Anmeldung als Passwort verdeckt eingegeben und gehört nicht in `.env`.
|
|
Das kurzlebige `GITEA_TOKEN` des CI-Jobs ist kein Deployment-Zugang.
|
|
[Gitea-Container-Registry](https://docs.gitea.com/usage/packages/container/),
|
|
[Paketberechtigungen](https://docs.gitea.com/usage/packages/overview/#access-restrictions).
|
|
|
|
Nur für private Pakete anmelden und `GITEA_USERNAME` durch den Gitea-Namen
|
|
des Token-Inhabers ersetzen:
|
|
|
|
```bash
|
|
docker login gitlab.bartelluis.de --username GITEA_USERNAME
|
|
```
|
|
|
|
Konfiguration prüfen und das gewählte Image herunterladen:
|
|
|
|
```bash
|
|
docker compose config --quiet
|
|
docker compose pull provisioner
|
|
```
|
|
|
|
Erst nach erfolgreichem Pull fortfahren. `unauthorized` oder `denied` weist
|
|
auf Anmeldung beziehungsweise Zugriffsrechte hin; bei `manifest unknown` den
|
|
Imagepfad und den verfügbaren Tag/Digest prüfen. Bei internen Zertifikaten
|
|
den CA-Vertrauensanker im Docker-Dienst des Zielservers einrichten.
|
|
|
|
## Einmalige Initialisierung und Start
|
|
|
|
Nur bei der ersten Inbetriebnahme mit neuen Daten- und Schlüsselvolumes den
|
|
Administrator und den Master-Key anlegen:
|
|
|
|
```bash
|
|
docker compose run --rm --no-deps \
|
|
--volume proxmox-ais-keys:/run/secrets:rw provisioner init --username admin
|
|
```
|
|
|
|
Das Passwort wird zweimal interaktiv abgefragt. Es gibt kein Standardpasswort.
|
|
Das Schlüsselvolume ist für diesen einen Aufruf beschreibbar. Im Regelbetrieb
|
|
wird es schreibgeschützt eingebunden. Bei einer bestehenden Installation oder
|
|
einem Update diesen Initialisierungsbefehl nicht erneut ausführen.
|
|
|
|
Anschließend den Dienst starten:
|
|
|
|
```bash
|
|
docker compose up -d --no-build --wait
|
|
docker compose ps
|
|
docker compose logs --tail=100 provisioner
|
|
```
|
|
|
|
`--wait` wartet auf einen laufenden, gesunden Dienst gemäß dem Healthcheck im
|
|
Image. Der Proxyzugriff wird separat geprüft.
|
|
[Compose-Startoptionen](https://docs.docker.com/reference/cli/docker/compose/up/).
|
|
Mit `curl`, sofern auf dem Zielserver verfügbar, den lokalen Dienst und die
|
|
öffentliche HTTPS-Adresse prüfen; die Beispieladresse ersetzen:
|
|
|
|
```bash
|
|
curl --fail http://127.0.0.1:8080/health/ready
|
|
curl --fail https://provision.example.net/health/ready
|
|
```
|
|
|
|
Beide Aufrufe sollen `"status":"ready"` liefern. Danach die öffentliche
|
|
Adresse im Browser öffnen und mit dem angelegten Administrator anmelden.
|
|
|
|
## Daten und Schlüssel
|
|
|
|
Die Anwendung läuft im Container als UID/GID `10001:10001`. Die Compose-Datei
|
|
verwendet diese dauerhaften, von Docker verwalteten Volumes:
|
|
|
|
| Volume | Inhalt | Containerpfad |
|
|
| --- | --- | --- |
|
|
| `proxmox-ais-data` | SQLite-Datenbank und Artefakte | `/var/lib/proxmox-ais` |
|
|
| `proxmox-ais-keys` | Master-Key für verschlüsselte Geheimnisse | `/run/secrets` |
|
|
|
|
Für neue Volumes übernimmt Docker die vorbereiteten Verzeichnisse aus dem
|
|
Image; sie sind für den Dienstbenutzer angelegt. Beim Wiederverwenden oder
|
|
Wiederherstellen bestehender Volumes müssen Eigentümer und Rechte weiterhin
|
|
zu UID/GID 10001 passen. Lokale Bind-Mount-Verzeichnisse benötigen dieselben
|
|
passenden Rechte, falls die Compose-Datei später entsprechend angepasst wird.
|
|
[Docker-Volumes](https://docs.docker.com/engine/storage/volumes/).
|
|
|
|
Containerneustarts und Updates erhalten diese Volumes.
|
|
`docker compose down --volumes` würde sie löschen. Für mehrere getrennte Instanzen auf demselben
|
|
Host die Volume-Namen in Compose und beim Initialisierungsaufruf je Instanz
|
|
anpassen. Daten und Master-Key nach der
|
|
[Backup-Anleitung](operations.md#backup) getrennt sichern.
|
|
|
|
## Updates
|
|
|
|
Ein Wartungsfenster vorsehen. Vor dem ersten Neustart den Digest des
|
|
tatsächlich laufenden Images ermitteln, insbesondere bei Verwendung eines
|
|
beweglichen Tags:
|
|
|
|
```bash
|
|
AIS_RUNNING_IMAGE_ID=$(docker inspect --format '{{.Image}}' "$(docker compose ps -q provisioner)")
|
|
docker image inspect --format '{{range .RepoDigests}}{{println .}}{{end}}' "$AIS_RUNNING_IMAGE_ID"
|
|
```
|
|
|
|
Den zum Projekt passenden Registry-Digest zusammen mit dem Backup aufbewahren
|
|
und in `.env` als `PROVISIONER_IMAGE` eintragen. Damit verwendet auch der
|
|
Wartungsneustart genau die bisherige Version. Falls kein Registry-Digest
|
|
angezeigt wird, die bisherige Version vor dem Update eindeutig zuordnen.
|
|
|
|
Jetzt in `.env` `MAINTENANCE=true` setzen und die Einstellung mit der
|
|
bisherigen Version übernehmen:
|
|
|
|
```bash
|
|
docker compose up -d --no-build --wait
|
|
```
|
|
|
|
Der Wartungsmodus sperrt neue Installationsfreigaben. Bereits gestartete
|
|
Installer und Host-Runner werden dadurch nicht beendet. Ihre laufenden
|
|
Phasen vor dem eigentlichen Versionswechsel prüfen und einen geeigneten
|
|
Zeitpunkt für den Dienststopp abwarten.
|
|
|
|
Jetzt die Daten mit der bisher eingesetzten Anwendungsversion sichern und
|
|
den Master-Key separat verwahren. Die [Backup-Anleitung](operations.md#backup)
|
|
enthält dafür die Containerbefehle. Zusätzlich die aktuelle `.env`, den
|
|
bisherigen Image-Digest und die Proxykonfiguration sichern.
|
|
|
|
Danach die neue `PROVISIONER_IMAGE`-Zeile aus dem erfolgreichen
|
|
`container-publish`-Job in `.env` übernehmen. `PUBLIC_URL` und die
|
|
Volume-Namen beibehalten, `MAINTENANCE=true` gesetzt lassen. Folgender Ablauf
|
|
prüft und lädt das neue Image, bevor er den bisherigen Dienst stoppt:
|
|
|
|
```bash
|
|
(
|
|
set -eu
|
|
docker compose config --quiet
|
|
docker compose pull provisioner
|
|
docker compose stop provisioner
|
|
docker compose up -d --no-build --wait
|
|
docker compose ps
|
|
)
|
|
```
|
|
|
|
Bei einem fehlgeschlagenen Pull läuft der bisherige Dienst weiter. Nach dem
|
|
Update Readiness über HTTPS, Anmeldung und Inventar prüfen. Erst nach
|
|
erfolgreicher Prüfung in `.env` `MAINTENANCE=false` setzen und übernehmen:
|
|
|
|
```bash
|
|
docker compose up -d --no-build --wait
|
|
```
|
|
|
|
Der Initialisierungsbefehl gehört ausschließlich zur ersten Inbetriebnahme.
|
|
|
|
## Rückkehr zum vorherigen Stand
|
|
|
|
Falls der neue Dienst nicht gesund startet, zunächst
|
|
`docker compose logs --tail=100 provisioner` prüfen. Das vorherige Image darf
|
|
nur auf eine damit kompatible Datenbank zugreifen. Bei bestätigter
|
|
Kompatibilität die gesicherte `.env` beziehungsweise den bisherigen exakten
|
|
Image-Digest wiederherstellen und den Updateablauf erneut ausführen; den
|
|
Wartungsmodus erst nach erfolgreicher Prüfung beenden.
|
|
|
|
Hat die neue Version das Schema bereits verändert, den Dienst stoppen und
|
|
mit der zum Backup passenden Anwendungsversion nach der
|
|
[Restore-Anleitung](operations.md#restore) in ein neues leeres Datenvolume
|
|
wiederherstellen. Die vorhandenen Daten erhalten, bis die Wiederherstellung
|
|
geprüft ist. Der Restore setzt Maschinenberechtigungen zurück und erfordert
|
|
den dort beschriebenen Abgleich laufender Installationen.
|