fix some typos
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Robert Kaussow 2019-02-13 09:38:13 +01:00
parent 5b327870bb
commit e8252bfd2b

View File

@ -16,18 +16,18 @@ resources:
title: Drone Pipeline bei Änderungen am Content-Repository
---
Wie bereits in einem früheren Beitrag erwähnt, nutze ich für meinen Blog mittlerweile Hugo, einen Static Site Generator, anstelle einer Blog-Engine oder eines Content Management Systems. Bisher habe ich die Entscheidung nicht bereut, musste aber feststellen, dass sich mein Workflow im ersten Schritt nicht wirklich verbessert hat. Um das zu beheben, muss man sich als Erstes zwei Dinge anschauen: Wie hat es bisher funktioniert und wo will ich eigentlich hin? Dieser Beitrag soll eine Art Retrospektive sein und meinen Weg zu einer Continuous Deployment Strategie mit Hugo und Drone CI betrachten.
Wie bereits in einem früheren Beitrag erwähnt, nutze ich für meinen Blog mittlerweile Hugo, einen Static Site Generator, anstelle einer Blog-Engine oder eines Content Management Systems. Bisher habe ich die Entscheidung nicht bereut, musste aber feststellen, dass sich mein Workflow im ersten Schritt nicht wirklich verbessert hat. Um das zu beheben, sollte man zunächst zwei Dinge betrachten: Wie hat es bisher funktioniert und wo will ich eigentlich hin? Dieser Beitrag soll eine Art Retrospektive sein und meinen Weg hin zu einer Continuous Deployment Strategie mit Hugo und Drone CI veranschaulichen.
Den notwendigen Neuaufbau meiner Infrastruktur habe ich nicht nur zum Anlass genommen, um alles vollständig auf Ansible umzustellen, sondern auch um meinen Softwarestack kritisch zu hinterfragen und aufzuräumen. Jede Software erfüllt natürlich einen Zweck, entscheidend für mich war aber: Wie wartungsintensiv ist die Lösung, wie leicht lässt sie sich deployen und rechtfertigt der Aufwand den Zweck. Im Fall von meiner Blog-Engine Serendipity (s9y) bin ich zu dem Schluss gekommen, dass ich darauf eigentlich ganz gut verzichten kann. Nebenbei empfand ich mittlerweile die Weboberfläche zur Verwaltung meiner Beiträge als nicht optimal für mich. Ich wollte lieber in einem Artikel meiner Wahl, am besten auch Oflline arbeiten können als in einem Onlineeditor. Außerdem musste man für etwas komplexere Formatierungen dann doch wieder zu HTML und CSS wechseln, weil der WYSIWYG-Editor das nicht hergab und Markdown im Standard da auch relativ beschränkt ist. Damit war die Entscheidung auch schon getroffen, es soll eine neue Lösung her.
Den notwendigen Neuaufbau meiner Infrastruktur habe ich nicht nur zum Anlass genommen, um alles vollständig auf Ansible umzustellen, sondern auch um meinen Softwarestack kritisch zu hinterfragen und aufzuräumen. Jede Software erfüllt natürlich einen Zweck, entscheidend für mich war aber: Wie wartungsintensiv ist die Lösung, wie leicht lässt sie sich deployen und rechtfertigt der Aufwand den Zweck. Im Fall von meiner Blog-Engine Serendipity (s9y) bin ich zu dem Schluss gekommen, dass ich darauf eigentlich ganz gut verzichten kann. Nebenbei empfand ich die Weboberfläche zur Verwaltung meiner Beiträge als nicht optimal für mich. Ich wollte lieber in einem Editor meiner Wahl, am besten auch Offline, arbeiten können anstatt in einer Weboberfläche. Außerdem musste man für etwas komplexere Formatierungen dann doch wieder zu HTML und CSS wechseln, weil der WYSIWYG-Editor das nicht hergab und Markdown im Standard da auch relativ beschränkt ist. Damit war die Entscheidung auch schon getroffen, es soll eine neue Lösung her.
Der zweite Schritt war die "Suche" nach einer alternative. Zugegeben, da habe ich es mir tatsächlich etwas einfach gemacht und keinen großen Softwareauswahlprozess durchgeführt. Dass es ein Static Site Generator werden soll, stand für mich fest und [Hugo](https://gohugo.io/) war mir bereits bekannt. Nach den ersten Experimenten mit Hugo, die ohne große Zwischenfälle verliefen, fing ich an ein paar Punkte zu sammeln, die ich mir für die konkrete Umsetzung gewünscht habe:
Der zweite Schritt war die "Suche" nach einer Alternative. Zugegeben, da habe ich es mir tatsächlich etwas einfach gemacht und keinen großen Softwareauswahlprozess durchgeführt. Dass es ein Static Site Generator werden soll, stand für mich fest und [Hugo](https://gohugo.io/) war mir bereits bekannt. Nach den ersten Experimenten mit Hugo, die ohne große Zwischenfälle verliefen, fing ich an ein paar Punkte zu sammeln, die ich mir für die konkrete Umsetzung gewünscht habe:
- Keine Serverkomponente mehr, die gewartet werden muss, nur noch good old HTML
- Artikel können in Markdown geschrieben werden
- Artikel lassen sich bequem über Git verwalten
- Design und Inhalt sind voneinander getrennt und können separat verwaltet werden
Zur Trennung des Seitendesigns und des Inhaltes habe ich zwei Git Repositories. Das erste Repository beinhaltet tatsächlich nur das reine Theme. Im zweiten Repository befinden sich aber nicht nur die Markdown Dateien für die Artikel, sondern eigentlich die komplette Ordnerstruktur und Seitenkonfiguration für Hugo. Soweit alles nach meinen Vorstellungen. Aber wie bringe ich jetzt beides zusammen, damit Hugo daraus meinen Blog generieren kann? Theoretisch gibt es dafür aus meiner Sicht zwei Ansätze:
Zur Trennung des Seitendesigns und des Inhaltes verwende ich zwei Git Repositories. Das erste Repository beinhaltet tatsächlich nur das reine Theme. Im zweiten Repository befinden sich aber nicht nur die Markdown Dateien für die Artikel, sondern eigentlich die komplette Ordnerstruktur und Seitenkonfiguration für Hugo. Soweit alles nach meinen Vorstellungen. Aber wie bringe ich jetzt beides zusammen, damit Hugo daraus meinen Blog generieren kann? Theoretisch gibt es dafür aus meiner Sicht zwei Ansätze:
**Methode 1: Unabhängige Repositories**
@ -42,7 +42,7 @@ Diese Methode ist auf den ersten Blick die leichtere. Beide Repositories bleiben
**Methode 2: Integrierte Repositories**
Alternativ lassen sich die Repositories aber auch bereits im Vorfeld beispielsweise mit Git Submodules miteinander verbinden. Spart vor dem Generieren erstmal nicht viel, außer das separate klonen vom Theme.
Alternativ lassen sich die Repositories auch bereits im Vorfeld, beispielsweise mit Git Submodules, miteinander verbinden. Spart vor dem Generieren erstmal nicht viel, außer das separate klonen vom Theme.
- Content-Repository klonen und in den Themes Order wechseln
- Eventuell zum produktiven Branch wechseln
@ -92,7 +92,7 @@ Der hier zusammengestellte _defaultTask_ macht der Reihe nach folgendes:
Die aufbereitete Datei _default.min.css_ wird dann als CSS Datei für die fertige Seite verwendet. Wie gesagt, die Tasks lassen sich beliebig erweitern und bei Bedarf unterschiedlich gruppieren. Denkbar ist auch das Kompilieren von SASS oder SCSS Dateien.
Bleibt zum Schluss nur noch eines. Bei Änderungen sollen automatisch meine Gulp Tasks ausgeführt, die Seite generiert und auf meinen Webspace deployed werden. Am besten eignet sich dazu ein Continuous Integration System wie beispielsweise Travis CI. Ich habe mich allerdings für [Drone CI](https://drone.io/) entschieden. Drone selbst wird als Docker Image bereitgestellt und kann auf dem eigenen Server betrieben werden. Wem das zuviel Aufwand ist, für den gibt es mittlerweile aber auch eine [Cloud Version](https://cloud.drone.io/). Wie bei den meisten CI Lösungen wird für jedes Repository eine Pipeline definiert, die beschreibt, welche Schritte bei welcher Aktion (Push, Tag, Pull Request) ausgeführt werden sollen. Drone führt dabei jeden Schritt der Pipeline in einem eigenen Docker Container aus. Meine definierten Pipelines für das [Theme-Repository](https://gitea.rknet.org/xoxys/theme-geeklab/src/branch/master/.drone.yml) und das [Content-Repository](https://gitea.rknet.org/xoxys/theme-geeklab/src/branch/master/.drone.yml) findet ihr auf meiner Gitea Instanz. Ich habe an dieser Stelle nur den Ablauf für beide Repositories skizziert.
Bleibt zum Schluss nur noch eines. Bei Änderungen sollen automatisch meine Gulp Tasks ausgeführt, die Seite generiert und auf meinen Webspace deployed werden. Am besten eignet sich dazu ein Continuous Integration System wie beispielsweise Travis CI. Ich habe mich allerdings für [Drone CI](https://drone.io/) entschieden. Drone selbst wird als Docker Image bereitgestellt und kann auf dem eigenen Server betrieben werden. Wem das zuviel Aufwand ist, für den gibt es auch eine [Cloud Version](https://cloud.drone.io/). Wie bei den meisten CI Lösungen wird für jedes Repository eine Pipeline definiert, die beschreibt, welche Schritte bei welcher Aktion (Push, Tag, Pull Request) ausgeführt werden sollen. Drone führt dabei jeden Schritt der Pipeline in einem eigenen Docker Container aus. Meine definierten Pipelines für das [Theme-Repository](https://gitea.rknet.org/xoxys/theme-geeklab/src/branch/master/.drone.yml) und das [Content-Repository](https://gitea.rknet.org/xoxys/theme-geeklab/src/branch/master/.drone.yml) findet ihr auf meiner Gitea Instanz. Ich beschreibe an dieser Stelle nur kurz den groben Ablauf für beide Repositories.
{{< imgproc theme resize "950x" />}}
@ -100,6 +100,6 @@ Die Pipeline für das Theme-Repository ist relativ einfach gehalten. Gulp Tasks
{{< imgproc content resize "950x" />}}
Auch die Pipeline bei Änderungen am Content-Repository ist nicht wirklich kompliziert, hat aber ein paar mehr Schritte. Zuerst wird die neue Version der Seite generiert, die verwendete Hugo Version kann hierbei über das Drone Plugin gesteuert werden. Als Nächstes wird dann der aktuelle Stand der Seite auf dem Webserver "eingefroren". Dazu wird der aktuelle Ordner kopiert und ein Symlink auf die Kopie erstellt. Anschließend löscht Drone den Ordner der alten Version auf dem Webserver und erstellt ihn wieder mit der neuen Version. Zum Abschluss wird der Symlink wieder umgelenkt und die Kopie gelöscht. Warum das ganze? Ich habe das Drone Plugin so konfiguriert, dass die Dateien beim Deployment nicht einfach über den alten Stand drüber kopiert werden, sondern die alte Version vorher gelöscht wird. Dadurch kann ich sicherstellen, dass Überreste von alten Artikeln oder im Theme tatsächlich auch entfernt werden, wenn sie nicht mehr benötigt werden. Das führt beim Deployment aber zu einer kurzen Downtime meines Blogs, da zwischen dem löschen und dem kopieren nichts von der Seite mehr da ist. Um das zu vermeiden, der der beschrieben Workaround für in Zero-Downtime-Deployment.
Auch die Pipeline bei Änderungen am Content-Repository ist nicht wirklich kompliziert, hat aber ein paar mehr Schritte. Zuerst wird die neue Version der Seite generiert, die verwendete Hugo Version kann hierbei über das Drone Plugin gesteuert werden. Als Nächstes wird dann der aktuelle Stand der Seite auf dem Webserver "eingefroren". Dazu wird der aktuelle Ordner kopiert und ein Symlink auf die Kopie erstellt. Anschließend löscht Drone den Ordner der alten Version auf dem Webserver und erstellt ihn wieder mit der neuen Version. Zum Abschluss wird der Symlink wieder umgelenkt und die Kopie gelöscht. Warum das ganze? Ich habe das Drone Plugin so konfiguriert, dass die Dateien beim Deployment nicht einfach über den alten Stand drüber kopiert werden, sondern die alte Version vorher gelöscht wird. Dadurch kann ich sicherstellen, dass Überreste von alten Artikeln oder im Theme tatsächlich auch entfernt werden, wenn sie nicht mehr benötigt werden. Das führt beim Deployment allerdings zu einer kurzen Downtime meines Blogs, da zwischen dem löschen und dem kopieren nichts von der Seite mehr da ist. Um das zu vermeiden, der der beschrieben Workaround für in Zero-Downtime-Deployment.
Mit diesem Workflow bin ich aktuell ganz zufrieden, ich kann offline in einem Editor meiner Wahl arbeiten, ich kann meine Arbeit mittels Git synchronisieren und am Handy oder einem anderen PC weiter schreiben und das Veröffentlichen geht bequem mit einem einfachen Push von der Kommandozeile aus.