Website Deployment mit Codeberg Pages und CI

Wer mit dem Static-Site-Generator Hugo seine Webauftritt erstellt, will die generierten Webseiten auf einem Server bereitstellen: Irgendwo einen Webspace besitzen, Markdown-Dateien bearbeiten, hugo ausführen und im Anschluss per scp die Dateien im Hugo-Projekt aus dem Unter-Verzeichnis public hochladen. Das ist kein Hexenwerk, aber von der Bearbeitung des Inhaltes bis zur Bereitstellung auf dem Webspace sind einige Schritte notwendig. Insbesondere bei kleinen Änderungen kann das nervig sein.

Da ich für meinen Teil sehr gerne mit git arbeite und meine Quellen in der Regel auf irgendwelchen gitea-/forgejo-Instanzen verteile, habe ich mich bei dieser Website dafür entschieden, Codeberg Pages für das Hosting zu verwenden. Darüber hinaus automatisiere ich den Build- und Deploy-Prozess mit Hilfe von Codeberg CI. Wie das im Detail geht, beschreibe ich im Folgenden.

Inhalt:

Die Idee

Es gibt zwei Repos auf Codeberg:

  • toheine_sources enthält das Hugo-Projekt. (Quellen-Repo)
  • toheine enthält die durch Hugo generierten Dateien für den Webserver. (Pages-Repo)

Das Hugo-Projekt ist wie folgt aufgebaut:

. -> Quellen-Repo
├── archetypes
├── assets
├── content
├── data
├── layouts
├── public -> Pages-Repo
├── resources
├── static
└── themes

Damit liegt ein Repo in einem Repo. Das ist kein Problem, da git hierfür eine Lösung gleich liefert: git submodule

Jedes Mal, wenn Änderungen im Hugo-Projekt (im Quellen-Repo) durchgeführt werden, wird im Anschluss ein Commit erzeugt und in mein Codeberg-Repo gepusht toheine_sources. Dieses Event wird von der Codeberg CI registriert, der dort verwendete Woodpecker beginnt die Hugo-Files zu bauen und hinterlegt die so erzeugten Dateien im Pages-Repo toheine. Letzteres nutzt Codeberg Pages, der die Dateien unter einer Domain als Webseite bereitstellt.

Repos vorbereiten und Pages-Server nutzen

In einem ersten Schritt habe ich auf Codeberg die beiden öffentlichen, leeren Repos erstellt. Wichtig: Damit die Webseite von Codeberg Pages später korrekt dargestellt wird, lautet der Name des einzigen Branches im Webseiten-Repo “pages”.

Branch-Name im Pages-Repo lautet "pages"
Branch-Name im Pages-Repo lautet "pages"

Beim Quellen-Repo ist der Name des/der verwendeten Branches egal. Auf dem Rechner habe ich dann das Quellen-Repo heruntergeladen und mein (bereits vorhandenes) Hugoprojekt dort hinein kopiert:

git clone git@codeberg.org:toheine/toheine_sources.git
cd toheine_sources
cp -r /Quelle/meines/Hugo-Projektes/* .

Im Anschluss hab ich das Public-Verzeichnis entfernt und das Submodul hinzugefügt:

rm -rf public
git submodule add git@codeberg.org:toheine/toheine.git public

Die Struktur meiner Git-Repos ist somit fertig und die Webseite kann via https://toheine.codeberg.page/toheine/ aufgerufen werden (Aufbau: https://<user>.codeberg.page/repo). Ich will allerdings meine eigene Domain verwenden. Das ist hier auch gut dokumentiert. Ich habe mich für Option 2 (via ALIAS record) entschieden und folgende DNS-Einträge vorgenommen:

Domain 	         Type 	Data
toheine.net      ALIAS	codeberg.page
toheine.net      TXT    toheine.toheine.codeberg.page
www.toheine.net	 CNAME	toheine.net

Im letzten Schritt brauche ich in meinem pages-Repo noch eine Datei .domains, die pro Zeile einen Eintrag mit allen Adressen enthält, über die ich meine Seite aufrufen will. Diese hat in meinem Fall folgenden Aufbau:

toheine.net
www.toheine.net

Der Pages-Server von Codeberg sorgt jetzt dafür, dass die Seiten korrekt angezeigt werden und hinterlegt ein passendes Lets-Encrypt-Zertifikat:

LetsEncrypt schon implementiert
LetsEncrypt schon implementiert

Ab jetzt kann ich manuell (ohne CI) neue Seiten veröffentlichen, in dem ich nach einer Änderung an meinem Hugo-Projekt lokal hugo ausführe, dann in das Verzeichnis public navigiere und die dortigen Änderungen in mein Pages-Repo auf Codeberg pushe:

hugo
cd public
git add *
git commit -m "Manuelle Änderung meiner Hugo-Seite"
git push

Codeberg CI einrichten

Es fehlt noch der Schritt zur Automatisierung via Codeberg CI. Dieses System kann allerdings nicht ohne Anmeldung benutzt werden. Es muss vorab ein Request gestellt werden. Das Verfahren ist unter folgender Adresse beschrieben: https://codeberg.org/Codeberg-e.V./requests.

Nachdem ich das Issue erstellt hatte (siehe hier), erfolgte wenige Stunden später eine Freigabe und damit Zugriff auf Codeberg CI via https://ci.codeberg.org/. Der Login erfolgt via SSO: Wer auf Codeberg angemeldet ist, klickt auf “Anmelden” und kann loslegen:

Woodpecker mit Repo verbinden
Woodpecker mit Repo verbinden

Über den Button “Repository hinzufügen” wählt man das Quellen-Repo aus und klickt auf “Aktivieren”. Wenn das hinterlegt ist, brauchen wir noch eine Pipeline im Quellen-Repo, dass den Namen .woodpecker.yml trägt. Letztendlich ist das die Abfolge an Befehlen, die von der Codeberg CI (Woodpecker) ausgeführt wird, sobald eine Änderung auf Codeberg erfolgt. Freundlicherweise, liegen für viele erdenkliche Szenarien schon Beispiele bereit (siehe hier).

Ich hab die Datei für meine Verwendung leicht angepasst, aber im Wesentlichen so beibehalten (siehe hier). Wichtig ist allerdings, dass bei Verwendung die Codeberg CI die beiden Variablen mail und codeberg_token gesetzt werden. Den Token müssen wir vorab im Codeberg-Konto generieren:

Hierzu muss in den Profil-Einstellungen, unter Anwendungen, ein Zugriffstoken hinzugefügt werden. Dieser bekommt einen eindeutigen Namen und entsprechende Berechtigungen:

Zugriffstoken auf Codeberg erstellen
Zugriffstoken auf Codeberg erstellen

Soblad man auf “Token generieren” klickt, erscheint der Token mit einem Hinweis, diesen jetzt zu kopieren, da er später nicht mehr angezeigt wird.

Im letzten Schritt der Einrichtung hinterlegen wir die beiden oben erwähnten Secrets noch in Woodpecker. Dazu im Repo (also auf https://ci.codeberg.org/), in den Einstellungen …

Woodpecker-Einstellungen öffnen
Woodpecker-Einstellungen öffnen

… unter dem Reiter “Geheimnisse” die beiden gewünschten Werte hinterlegen:

Secrets in Woodpecker verwalten
Secrets in Woodpecker verwalten

Damit ist Woodpecker (Codeberg CI) fertig eingerichtet.

Abschließende Anpassung und Nutzung

So … da in Zukunft eigentlich nur noch im Quellen-Repo gearbeitet wird und die Erzeugung nicht mehr lokal erfolgt, ist der lokale Ordner public im Hugo-Projekt für die Versionierung nicht mehr relevant. Daher hab ich diesen auf die Ignore-Liste gesetzt:

echo public >> .gitignore

Wenn Änderungen im Hugo-Projekt durchgeführt und versioniert werden, bekommt das Woodpecker mit. Codeberg CI erstellt die Seiten und veröfffentlicht diese auf Codeberg Pages. Wenn man nach einem commit, das Projekt in das Quellen-Repo auf Codeberg pusht, kann man den Prozess in der Woodpecker-Webui verfolgen:

Sobald der Specht anfängt zu klopfen …

Woodpecker läuft
Woodpecker läuft

… kann der Prozess im Detail eingesehen werden, in dem man auf die Commit-Botschaft klickt. Die einzelnen Schritte werden abgearbeitet und können in den “Step Logs” nachvollzogen werden:

Woodpecker-Änderungen nachvollziehen
Woodpecker-Änderungen nachvollziehen

Sofern alles korrekt gelaufen ist, erscheint ein grüner Haken pro einzelnem Schritt und nach Fertigstellung für den ganzen Commit:

Rückmeldung mit grünem Haken in Woodpecker
Rückmeldung mit grünem Haken in Woodpecker

Fazit

Es ist ein wenig Aufwand, diese hier erwähnte Automatisierung mit Woodpecker zu realisieren. Aber … wenn das System eingerichtet ist, ist die Veröffentlichung in Sekunden realisiert und auch kleinere Änderungen an der Webseite sind schnell erledigt. Daher war das IMHO eine sinnvolle Investition.

Darüber hinaus hat man als Lehrkraft oder in der Fortbildung gleich ein Beispiel für einen sinnvollen Einsatz von CI/CD.

Codeberg e. V. bietet neben den reinen git-Repos mit Codeberg Pages und Codeberg CI ein überragendes Angebot. Die Doku und die erwähnten Beispiele für die.woodpecker.yml lassen keine Wünsche übrig. Ich finde das der absolute Hammer und Codeberg ist ein toller Verein!!!

Quellen