243 lines
14 KiB
Markdown
243 lines
14 KiB
Markdown
# Gitea Actions und Container Registry
|
|
|
|
Das Projekt liegt auf
|
|
[Gitea](https://gitlab.bartelluis.de/BartelLuis/Proxmox-AIS-Server).
|
|
Der [Workflow](../.gitea/workflows/ci.yml) prüft Python und JavaScript, baut
|
|
das Image und führt den Container-Smoke-Test aus. Bei aktivierter
|
|
Veröffentlichung lädt er dasselbe getestete Image in die Gitea Container
|
|
Registry. Der Workflow endet beim Image-Push; die Schritte auf dem Zielserver
|
|
stehen in der [Deployment-Anleitung](deployment.md).
|
|
|
|
## Gitea und Runner einrichten
|
|
|
|
In den Repository-Einstellungen **Actions** aktivieren und unter
|
|
**Settings → Actions → Runners** einen registrierten Runner prüfen oder
|
|
einrichten. Gitea benötigt einen eigenen Runner-Dienst; ein GitHub-Runner-Label
|
|
stellt keine Rechenkapazität bereit.
|
|
[Gitea Actions einrichten](https://docs.gitea.com/usage/actions/quickstart/).
|
|
|
|
Alle Jobs verwenden `vars.AIS_RUNNER_LABEL` oder, wenn die Variable nicht gesetzt
|
|
ist, `ubuntu-latest`. Das ausgewählte Label muss einem für dieses Repository
|
|
verfügbaren, erreichbaren Linux-amd64-Runner entsprechen. Die Angabe
|
|
`ubuntu-latest` wählt ein Runner-Label; sie installiert kein Ubuntu-Image.
|
|
Für ein anderes Label in **Settings → Actions → Variables** beispielsweise
|
|
`AIS_RUNNER_LABEL=ais-ci` setzen und genau dieses Label am Runner konfigurieren.
|
|
|
|
Die tatsächliche Job-Umgebung benötigt Git, Bash, OpenSSL, `ssh-keygen`, Python
|
|
3.13 mit `venv`, Node.js 24 sowie Docker CLI und Buildx mit Zugriff auf einen
|
|
laufenden Docker-Daemon. Die Setup-Actions richten Python 3.13 und Node.js 24
|
|
für ihre jeweiligen Jobs ein. Die Umgebung muss außerdem bereits die
|
|
JavaScript-Laufzeit zum Ausführen der Actions unterstützen. Bei einem
|
|
Container-Runner müssen Werkzeuge und Docker-Zugriff im Job-Container verfügbar
|
|
sein, nicht nur auf dem Host. Ein Standard-Node-Image allein enthält nicht die
|
|
gesamte Build-Umgebung. Runner-Konfiguration und Label-Zuordnung sind in der
|
|
[Runner-Anleitung](https://docs.gitea.com/1.26/usage/actions/act-runner/#labels)
|
|
beschrieben.
|
|
|
|
Der Runner muss Gitea, die Registry, die absoluten Action-URLs im Workflow und
|
|
die Downloadquellen für Python, Node.js, Python-Pakete und das Docker-Basisimage
|
|
erreichen. Die Actions sind auf vollständige Commit-SHAs festgelegt.
|
|
Der Artefakt-Upload verwendet die Gitea-kompatible Action
|
|
`https://gitea.com/actions/gitea-upload-artifact`.
|
|
|
|
Diese Build-Umgebung ist unabhängig vom AIS-Host-Runner für die
|
|
Postinstallation auf Proxmox-Hosts. CI-Code mit Docker-Zugriff auf einer dafür
|
|
vorgesehenen Build-Maschine ausführen; Änderungen an Workflow und CI-Skripten
|
|
vor der Übernahme prüfen.
|
|
|
|
## Registry und Veröffentlichung einrichten
|
|
|
|
Ohne `PUBLISH_IMAGES=true` führen alle Refs ausschließlich Prüfungen durch.
|
|
In **Settings → Actions → Variables** folgende Repository-Variablen setzen:
|
|
|
|
| Variable | Wert und Bedeutung |
|
|
| --- | --- |
|
|
| `AIS_RUNNER_LABEL` | Optional: Label eines verfügbaren Runners; Standard `ubuntu-latest` |
|
|
| `ARTIFACT_SERVER_URL` | Optional: aus dem Job-Container erreichbare Basis-URL derselben Gitea-Instanz, etwa `https://gitlab.bartelluis.de`; Standard ist `gitea.server_url` wie beim Checkout |
|
|
| `REGISTRY_HOST` | Optional: Registry-Host ohne Schema oder Pfad; Standard `gitlab.bartelluis.de` |
|
|
| `REGISTRY_USERNAME` | Gitea-Benutzername des Token-Inhabers; für Veröffentlichung erforderlich |
|
|
| `PUBLISH_IMAGES` | Genau `true`, nachdem Registry-Zugang und Schutzregeln eingerichtet sind |
|
|
|
|
Im Gitea-Benutzerkonto einen Personal Access Token mit Paket-Schreibrecht
|
|
(`write:package`, in der Oberfläche **package: Read & Write**) erstellen.
|
|
Den Wert unter **Settings → Actions → Secrets** als `REGISTRY_TOKEN` speichern.
|
|
Das zugehörige Konto muss beim Paketinhaber `BartelLuis` Schreibzugriff besitzen.
|
|
Das kurzlebige `GITEA_TOKEN` des Jobs unterstützt die Paketveröffentlichung
|
|
nicht; es ersetzt dieses Secret nicht.
|
|
[Gitea-Secrets](https://docs.gitea.com/usage/actions/secrets/),
|
|
[Paketberechtigungen](https://docs.gitea.com/usage/packages/overview/#access-restrictions),
|
|
[Gitea-Paketautorisierung](https://docs.gitea.com/usage/actions/comparison/#package-repository-authorization).
|
|
|
|
Der Imagepfad ist `<REGISTRY_HOST>/<kleingeschriebener Repositoryname>`, hier
|
|
`gitlab.bartelluis.de/bartelluis/proxmox-ais-server`. Bei einem Fork oder einer
|
|
Umbenennung ändert sich der Pfad. Pakete gehören in Gitea einem Benutzer oder
|
|
einer Organisation. Nach dem ersten Push kann das Paket in seinen Einstellungen
|
|
mit dem Repository verknüpft werden, damit es auch in dessen Paketliste erscheint.
|
|
[Gitea Container Registry](https://docs.gitea.com/usage/packages/container/).
|
|
|
|
## Standardbranch und Release-Tags schützen
|
|
|
|
Vor `PUBLISH_IMAGES=true` in den Gitea-Repository-Einstellungen den
|
|
Standardbranch `main` und die Release-Tags schützen. Für `main` direkte Pushes
|
|
deaktivieren, Reviews und erfolgreiche Statuschecks verlangen sowie Force-Push
|
|
und Löschen einschränken.
|
|
Für `v*` die Erstellung, Änderung und Löschung auf Release-Verantwortliche
|
|
begrenzen. Release-Tags auf einen geprüften Commit mit passender Projektversion
|
|
setzen. Die Schutzregeln werden durch den Workflow-Commit nicht angelegt.
|
|
[Geschützte Branches](https://docs.gitea.com/usage/access-control/protected-branches/),
|
|
[Geschützte Tags](https://docs.gitea.com/usage/access-control/protected-tags/).
|
|
|
|
Nach dem ersten Pull-Request-Lauf die tatsächlich gemeldeten Statuskontexte
|
|
für `python-tests`, `javascript-check`, `container-policy` und `container-verify`
|
|
als verpflichtend auswählen. `container-publish` wird bei Pull Requests übersprungen und ist
|
|
deshalb keine Pflichtprüfung.
|
|
|
|
Die CI entscheidet anhand von `PUBLISH_IMAGES`, Ereignis und Ref. Sie fragt
|
|
keinen Schutzstatus ab: Giteas kompatibler `ref_protected`-Wert ist dafür nicht
|
|
verwendbar. Die Gitea-Schutzregeln und restriktive Schreibrechte bleiben daher
|
|
ein eigener Einrichtungsschritt.
|
|
|
|
## Auslöser und Image-Tags
|
|
|
|
Der Workflow läuft bei Branch- und Tag-Pushes, bei Pull Requests sowie bei
|
|
manuellem Start über `workflow_dispatch`.
|
|
|
|
| Ref und Ereignis | Container-Job | Veröffentlichung |
|
|
| --- | --- | --- |
|
|
| `PUBLISH_IMAGES` fehlt oder ist nicht `true` | `container-verify` | Keine |
|
|
| Pull Request, Feature-Branch oder sonstiger Tag | `container-verify` | Keine |
|
|
| Standardbranch, Push oder manueller Start, Veröffentlichung aktiviert | `container-publish` | `sha-<vollständiger Commit-SHA>` und `edge` |
|
|
| Tag `vX.Y.Z`, Push oder manueller Start, Veröffentlichung aktiviert | `container-publish` | `sha-<vollständiger Commit-SHA>` und `X.Y.Z` |
|
|
|
|
Release-Tags müssen vollständig dem Muster
|
|
`v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)` entsprechen. Führende
|
|
Nullen, Vorabversionen und Build-Zusätze veröffentlichen kein Image.
|
|
Bei einem zur Veröffentlichung ausgewählten Release muss die Version außerdem
|
|
exakt `[project].version` in [pyproject.toml](../pyproject.toml) entsprechen;
|
|
eine Abweichung bricht den Publish-Job ab.
|
|
|
|
`edge` ist ein beweglicher Tag. Ein erneuter Lauf eines älteren Commits kann
|
|
ihn zurücksetzen. SHA-Tags enthalten alle 40 Zeichen des Commits; externe
|
|
Build-Abhängigkeiten können bei erneuten Builds zu einem anderen Digest führen.
|
|
Es gibt keinen `latest`-Tag. Im Betrieb den Digest aus `deploy.env` verwenden
|
|
und bisherige Registry-Versionen für Updates und Rollback aufbewahren.
|
|
|
|
## Jobs und Artefakte
|
|
|
|
`python-tests` führt über [ci/python-tests.sh](../ci/python-tests.sh) Pytest in
|
|
einer temporären virtuellen Umgebung aus. `javascript-check` prüft mit
|
|
`node --check provisioner/static/app.js` die JavaScript-Syntax.
|
|
`container-policy` wählt den Container-Job aus. Nach erfolgreichen
|
|
Quellcodeprüfungen läuft genau einer der Jobs `container-verify` und
|
|
`container-publish`. Beide verwenden [ci/container.sh](../ci/container.sh);
|
|
das Skript prüft vor einer Veröffentlichung erneut Ereignis, Ref und Opt-in.
|
|
|
|
Der [Container-Smoke-Test](../tests/container_smoke.py) prüft das gebaute
|
|
`linux/amd64`-Image auf TLS, Anmeldung, CSRF, Webdateien und Datenerhalt über
|
|
einen Dienstneustart. Er läuft als UID 10001 mit schreibgeschütztem Dateisystem,
|
|
entfernten Linux-Capabilities und temporären Testdaten. Eine Proxmox-Installation
|
|
ist kein Bestandteil dieses Tests. Der Publish-Job lädt das getestete Image
|
|
ohne zweiten Build hoch. OCI-Labels enthalten Quellrepository, Commit und
|
|
Anwendungsversion; Provenance- und SBOM-Attestierungen werden nicht erzeugt.
|
|
|
|
| Artefakt im Gitea-Lauf | Inhalt | Angefragte Aufbewahrung |
|
|
| --- | --- | --- |
|
|
| `python-test-results` | `reports/pytest.xml`, auch bei fehlgeschlagenen Tests, sofern erzeugt | 7 Tage |
|
|
| `container-build` | `build.env` nach erfolgreicher Verifikation | 7 Tage |
|
|
| `container-deploy` | `build.env` und `deploy.env` nach erfolgreicher Veröffentlichung | 30 Tage |
|
|
|
|
Die tatsächliche Aufbewahrung unterliegt der Gitea-Instanzkonfiguration.
|
|
Unter **Actions** den erfolgreichen Lauf öffnen und das gewünschte Artefakt
|
|
herunterladen. `build.env` enthält den temporären lokalen Image-Tag, Commit
|
|
und Anwendungsversion. Der lokale `ci-…`-Tag wird nicht veröffentlicht und am
|
|
Jobende entfernt. `deploy.env` enthält ausschließlich
|
|
`PROVISIONER_IMAGE=gitlab.bartelluis.de/bartelluis/proxmox-ais-server@sha256:…`
|
|
beziehungsweise die konfigurierte Registry-Adresse. Beide Dateien enthalten
|
|
keine Zugangsdaten. Die Image-Zeile in `.env` auf dem Zielserver übernehmen.
|
|
|
|
## Erster Lauf und Release
|
|
|
|
Nach dem Push unter **Actions** prüfen, dass der Lauf einen Runner erhält und
|
|
Python-, JavaScript- und Containerprüfungen erfolgreich sind. Nach aktivierter
|
|
Veröffentlichung muss ein Standardbranch-Lauf außerdem die Image-Tags
|
|
`sha-<Commit>` und `edge` sowie `container-deploy` mit `deploy.env` liefern.
|
|
Lokale Tests ersetzen diesen Lauf mit Registry-Anmeldung und Push nicht.
|
|
|
|
Für ein Release zuerst `[project].version` ändern und den geprüften Commit
|
|
übernehmen. Anschließend mit einem berechtigten Konto den passenden Tag
|
|
erstellen und an den Gitea-Remote pushen. Im vorhandenen Checkout heißt er
|
|
`origin`; vor dem Push mit `git remote -v` prüfen. Für Projektversion `0.9.1`,
|
|
sofern der Tag noch nicht existiert:
|
|
|
|
```bash
|
|
git tag -a v0.9.1 -m "Release 0.9.1"
|
|
git push origin v0.9.1
|
|
```
|
|
|
|
Der Release-Lauf muss den Image-Tag `0.9.1` erzeugen. Für einen manuellen Lauf
|
|
unter **Actions** den Workflow und den gewünschten Ref auswählen. Auch dabei
|
|
gelten Opt-in, Standardbranch- beziehungsweise Tag-Regel und Versionsabgleich.
|
|
Branch-Push und Pull Request können für denselben Quellstand getrennte Läufe
|
|
erzeugen. Pull Requests veröffentlichen keine Images.
|
|
|
|
## Fehlersuche und Deployment
|
|
|
|
Bei **Waiting** beziehungsweise **no matching online runner** das angeforderte
|
|
Label mit den erreichbaren Runnern unter **Settings → Actions → Runners**
|
|
vergleichen. Der bisherige Workflow verlangte `ubuntu-24.04`; dafür war kein
|
|
passender Online-Runner verfügbar. `AIS_RUNNER_LABEL` auf ein tatsächlich
|
|
vorhandenes Label setzen oder einen geeigneten Runner registrieren und starten.
|
|
Ein Label-Wechsel allein ersetzt keine fehlende Runner-Installation.
|
|
|
|
Bei fehlendem Docker-Zugriff `docker info` und `docker buildx version` in der
|
|
Job-Umgebung prüfen. Bei DNS-, Checkout- oder Artefaktfehlern müssen Giteas
|
|
öffentliche `ROOT_URL`, die Checkout-Adresse und die vom Runner erreichbare
|
|
Adresse zusammenpassen. Das Projekt verwendet `gitlab.bartelluis.de`; eine
|
|
von der Instanz zurückgegebene abweichende Adresse wie `git.bartelluis.de` muss
|
|
ebenfalls auflösbar und erreichbar sein oder in der Gitea-Konfiguration
|
|
korrigiert werden.
|
|
|
|
Bei einem Timeout von `ArtifactService/CreateArtifact` den Wert von
|
|
`ACTIONS_RESULTS_URL` im Upload-Schritt prüfen. Der Runner setzt ihn zunächst
|
|
aus seiner Registrierungsadresse; Runner 3.4.2 kann ihn für die
|
|
Artefaktweiterleitung durch die Adresse seines Cache-Servers ersetzen.
|
|
Ein interner Docker-Hostname oder eine nur im Runner-Container erreichbare
|
|
Adresse kann im getrennten Job-Netz unerreichbar sein. Der gemountete
|
|
Docker-Socket verbindet diese Netze nicht miteinander.
|
|
Der Workflow setzt deshalb für alle drei Uploads `ACTIONS_RESULTS_URL` auf
|
|
`gitea.server_url`, also dieselbe Gitea-Adresse wie beim Checkout. Falls nötig,
|
|
`ARTIFACT_SERVER_URL=https://gitlab.bartelluis.de` als Repository-Variable setzen.
|
|
Die Basis-URL enthält Schema und Host, gegebenenfalls einen Port, aber keinen
|
|
`/api/actions_pipeline`-Pfad. Sie muss dieselbe Gitea-Instanz erreichen.
|
|
Die Überschreibung muss direkt im Upload-Schritt stehen, da der Runner
|
|
Umgebungsvariablen auf Workflow- oder Job-Ebene überschreiben kann.
|
|
[Runner-Artefaktweiterleitung](https://gitea.com/gitea/runner/src/tag/v3.4.2/internal/app/run/runner.go#L598),
|
|
[Gitea-Laufzeitvariablen](https://docs.gitea.com/usage/actions/actions-variables/#internal-environment-variables).
|
|
|
|
Die Erreichbarkeit innerhalb eines Job-Containers prüfen:
|
|
|
|
```bash
|
|
curl --connect-timeout 5 --max-time 10 --silent --show-error --output /dev/null \
|
|
--write-out 'HTTP %{http_code}\n' \
|
|
https://gitlab.bartelluis.de/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact
|
|
```
|
|
|
|
Ein `405` auf diese GET-Anfrage bestätigt, dass der POST-Endpunkt erreichbar
|
|
ist; der eigentliche Upload benötigt weiterhin das vom Runner bereitgestellte
|
|
Job-Token. Bei einem Timeout DNS, Routing und Proxy-Zugriff aus dem Job-Netz
|
|
prüfen oder Runner und Jobs an ein gemeinsames erreichbares Docker-Netz
|
|
anbinden. Eine längere Wiederholungszeit behebt eine unerreichbare Adresse nicht.
|
|
|
|
Bei übersprungenem Publish-Job `PUBLISH_IMAGES`, Ereignis, Standardbranch und
|
|
Tagformat prüfen. Bei `denied` oder `unauthorized` Registry-Host, Benutzername,
|
|
`REGISTRY_TOKEN`, dessen `write:package`-Scope und die Rechte am Paketinhaber
|
|
kontrollieren. Bei Versionsfehlern Git-Tag und `pyproject.toml` abgleichen.
|
|
Fehlt `container-deploy`, die Build-, Smoke-, Push- und Upload-Logs prüfen.
|
|
|
|
Zum Deployment [compose.yaml](../compose.yaml) und
|
|
[config/deployment.env.example](../config/deployment.env.example) auf den
|
|
Zielserver kopieren. Die [Deployment-Anleitung](deployment.md) beschreibt
|
|
Registry-Anmeldung, Erstinitialisierung, HTTPS-Prüfung, Updates und Rollback.
|
|
Für private Pakete benötigt das Deploymentkonto einen eigenen Token mit
|
|
`read:package`; öffentliche Pakete lassen sich anonym laden.
|