Hugo als richtiges „CMS“ – dank GitLab und automatischem Deployment

Ein Blog mit statischen HTML-Seiten ist was feines. Noch feiner ist es, wenn man Hugo und GitLab zusammenbringt, um Seiten einfacher ändern und automatisch generieren zu können.

Lesezeit: 5 Min., von Titus Gast gepostet am Sun, 21.10.2018
Tags: hugo, html, cms, git, docker, blog

Als ich von Wordpress auf Hugo umstieg, haderte ich etwas mit der fehlenden Möglichkeit, mal schnell von unterwegs oder einem anderen Computer was an meinen Seiten zu ändern. Da ich mich wegen eines anderen Projektes ohnehin in Git einarbeiten wollte und endlich auch mal einen GitLab-Account angelegt hatte, bin ich dann der Idee genauer nachgegangen, den Publikationsprozess via GitLab zu automatisieren. Nach einiger Bastelei, vielen Suchmaschinenanfragen und viel Trial and Error habe ich jetzt eine schöne Continous-Integration-Pipeline mit Versionsverwaltung aufgebaut. Für mein Blog. Warum ich das auch konzeptionell ganz toll finde, erkläre ich ganz unten.

Automatische Publikation mit Versionskontrolle

Basis meines Vorgehens waren diese beiden Anleitungen von Graham Stevens und Dino Fizzotti.

Wenn alles klappt, ist es das Ganze sehr einfach: Man braucht natürlich zunächst einen GitLab-Account (ich habe mir direkt bei GitLab einen angelegt) und startet dort ein Projekt, in das man sein Hugo-Dateien legt. Für das automatische Bauen und Deployen der Seite legt man dann eine Datei namens .gitlab-ci.yml an, in der die Anweisungen für GitLab stehen, was zu tun ist. Das Ganze funktioniert wie Docker Compose (und arbeitet im Hintergrund auch damit), will heißen:

  • Wenn sich am Git-Repository was ändert, wird die CI/CD-Pipeline gestartet.
  • Es werden dann – je nach Anweisung in der .gitlab-ci.yml– Docker-Container gestartet, die Dinge machen.
  • Zunächst wird ein Docker-Container mit Hugo gestartet, der die Seiten baut.
  • Dann startet ein Docker-Container, der die fertigen HTML-Dateien mit Rsync auf meinen Webserver lädt.

Letztendlich verwende ich derzeit eine Kombination der beiden .gitlab-ci.yml-Dateien von Dino Fizzotti und Graham Stevens. Das müsste sicher nicht sein. Ich hatte anfangs mit der von Graham Stevens Probleme, weswegen ich für den zweiten Job des Skripts teilweise auf den Ansatz von Dino Fizzotti ausgewichen bin.

Die richtigen Variablen bei GitLab eintragen

Die Probleme, die ich hatte, hatten allerdings eine andere Ursache als die Unterschiede in den Skripten: Ein kritischer Punkt war bei mir, die ganzen Variablen richtig einzutragen. Das geschieht bei GitLab unter > Einstellungen > CI/CD > Variables. Hier kann man Variablen für die Zugangsdaten hinterlegen, die dann nicht in der Datei .gitlab-ci.yml hinterlegt werden müssen. Diese wären:

  • {SSH_PRIVATE_KEY}: Das ist ein SSH-Schlüssel, den man lokal generiert und dann bei GitLab abspeichert, damit .gitlab-ci.yml ihn aufrufen kann, damit der Container sich auf dem Zielsystem ohne Login via SSH/Rsync anmeldet.
  • ${SSH_USER_HOST_LOCATION}: Das ist im Wesentlichen die Rsync-Anmeldung samt Pfad zum finalen Ablageort der HTML-Dateien, also benutzername@server:/pfad/zum/html/ordner(in meinem Falle also der Ordner, aus dem mein Nginx die HTML-Dateien holt.
  • ${SSH_HOST_KEY}: Diese Variable hat mir die größten Probleme bereitet, denn es gelang mir zunächst nicht, hier den korrekten Wert zu ermitteln. Geholfen hat mir nach viel Googelei am Ende, auf dem Ziel-System (mit dem User, den auch $SSH_USER_HOST_LOCATION benutzt), den Befehl ssh-keyscan [optional: -p PORT] [SERVER-URL] auszuführen. Das Ergebnis enthält ein paar rsa-, ecdsa- und ed25519-Keys; den ganzen Block kopiert man dann in das entsprechende Feld bei GitLab. Erst dadurch kann sich der bei GitLab gestartetet Docker-Container mit Rsync gegenüber dem Zielserver korrekt „ausweisen“.

Die Datei .gitlab-ci.yml sieht aktuell bei mir so aus und funktioniert:

stages:
  - build
  - deploy
build:
  stage: build
  image: jojomi/hugo
  script:
  - hugo version
  - git submodule update --init --recursive
  - hugo -d public_html
  artifacts:
    paths:
    - public_html
  only:
  - master

deploy:
  stage: deploy
  image: dinofizz/rsync-ssh
  script:
  - echo "${SSH_PRIVATE_KEY}" > id_rsa
  - chmod 700 id_rsa
  - mkdir "${HOME}/.ssh"
  - echo "${SSH_HOST_KEY}" > "${HOME}/.ssh/known_hosts"
  - rsync -hrvz --delete --exclude=_ -e 'ssh -i id_rsa -p 55122' public_html/ "${SSH_USER_HOST_LOCATION}"
  only:
  - master

Wenn dann alles klappt, kann man bei GitLab zugucken, wie die Seiten erstellt und publiziert werden. Das sieht dann so aus:

Screenshot GitLab: CI/CD > Jobs

Und wenige Sekunden bis Minuten später (je nachdem, was man geändert hat), sind die Seiten online.

Die Vorteile dieser Lösung sind:

  • Ich muss die statischen HTML-Seiten nicht mehr lokal auf dem Rechner generieren. Das passiert jetzt bei GitLab.
  • Der gesamte manuelle Upload entfällt (auch wenn man das wie ich über Shell-Script automatisiert, dauert das ja trotzdem seine Zeit).
  • Auch Hugo selbst braucht man nur noch für die Vorschau über hugo server und http://localhost:1313

Anstattdessen pusht man neue Seiten via Git zu GitLab und dann geht alles seinen Gang.

Der Nachteil dieser Lösung ist: Git ;-)

Will heißen: Man braucht ein paar Grundkenntnisse über Git. ABER: Das kann und will ich nicht als Nachteil sehen, denn Sinn dieser Operation war es bei mir ja unter anderem auch, eine Versionsverwaltung über Git hinzubekommen und ich möchte sie schon nach wenigen Tagen nicht mehr missen. Als Git-Einsteiger half mir dabei auch ein Git-Client.

Nächster Level: Entwicklungsumgebung

Krönung des Ganzen ist, dass ich dann parallel auch noch eine Entwicklungsumgebung mit Deployment auf eine Testseite aufgebaut habe. Wenn ich also größere Änderungen (zum Beispiel am Layout) mache, entwickle ich in einen Develop-Branch und dessen Ergebnis wird auf eine Testseite publiziert. Alles, was ich dann tun muss, wenn mir die Ergebnisse gefallen: Die Änderungen im Develop-Branch via Git mit dem Master-Branch mergen.

Git für Content? Aber hallo!

Nicht nur unter technischen Gesichtspunkten finde ich die Publikation eines Blogs via Git spannend. Auch für Texte ist das Konzept, Änderungen nachvollziehbar, öffentlich und letztendlich auch rückgängig machen zu können, eine feine Sache. Denn nicht nur Code lebt im Internet, sondern auch Inhalte – da ist es nur logisch, diese nach denselben Prinzipien zu erstellen, zu verwalten und idealerweise auch frühere Versionen bereitzustellen. Für mein eigenes Blog bin ich aus verschiedenen Gründen noch nicht ganz so weit, dass das öffentlich ginge (dafür muss ich unter anderem das Berechtigungskonzept von GitLab erst besser verstehen); aber gerade für journalistische Inhalte wäre dieses Maß an Transparenz eine großartige Sache.

Titelfoto: Vidar Nordli-Mathisen bei Unsplash


Posts zu ähnlichen Themen: