Zahnräder
Gears of industry, (CC BY-NC-ND 2.0), House Photography

Deployment einer Jekyll-Site via Git Bare Repository1 und post-receive Hook2 auf einen Webserver.

Zielstellung ist, dass ein git push auf das Remote Repository3 das weiter unten beschriebene Skript triggert. Dieses generiert aus dem Repository mit all seinen Änderungen, wie z.B. Markdown, Config, Layout, Include und den Abhängigkeiten im Gemfile4 das entsprechende HTML, dass dann der Welt in der DocumentRoot5 deines Webservers, in meinem Fall einem Uberspace ausgeliefert wird.

Vorbereitungen auf dem Zielserver

Wir starten nach erfolgreichem SSH-Login auf unserem Uberspace-Host in unserem Home-Verzeichnis und legen Ordner für unser Repository an,

mkdir repos

wechseln dort hinein

cd repos

und erstellen den Ordner für das Repository auf das wir später pushen wollen. In diesem Fall entspricht der Ordnername der Domain. Ab hier solltest du das exemplarische netzaffe.de durch deine Domain ersetzen.

mkdir netzaffe.de

und wechseln hinein.

cd netzaffe.de

Jetzt initialisieren wir den Ordner als Bare Repository1.

git init --bare

[DEPRECATED] The –path flag is deprecated …

Vor einiger Zeit tauchte die folgende Meldung beim Deployment auf:

[DEPRECATED] The --path flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use bundle config set --local path '~/.gem', and stop using this flag

Ich habe das --path aus dem Skript entfernt und statt dem Vorschlag folgendes gemacht:

bundle config set --global path '~/.gem'

Your application has set path to “~/.gem”. This will override the global value you are currently setting

Statt einer lokalen .bundle/config mit nur einer Zeile geht hierdurch die folgende Zeile nach ~/.bundle/config:

BUNDLE_PATH: "~/.gem"

Das Deployment Skript

Wenn der komplette Prozess der Übertragung (Push) abgeschlossen ist, greift serverseitig der sogenannte post-receive Hook2 und führt das gleichnamige Skript (sofern vorhanden) aus.

Das Jekyll uberspace deployment Skript welches wir als post-receive Hook2 nutzen findest du hier auf github. Hier der Stand vom 30. März 2021:

>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

# Deployment of Jekyll-Sites  
# via Git Bare Repository and post-receive hook.
#
# See https://netzaffe.de/jekyll-deployment-via-bare-repository-und-post-receive-hook.html
# for requirements and more detailed description (german)
# set -x

# Get pushed branch

read oldrev newrev ref 
pushed_branch=${ref#refs/heads/} 

## Source configuration from repository

config=$(mktemp)
git-show HEAD:deploy.conf > $config || exit 
source $config

## Do the magic

[ "$pushed_branch" != "$build_branch" ] && exit 1
tmp=$(mktemp -d)
git clone $git_repo $tmp
cd $tmp
bundle install || bundle install --redownload
bundle exec jekyll build --source $tmp --destination $www
rm -rf $tmp $config

Beschreibung des Skripts

  1. Einlesen des gepushten Branches um ihn später vergleichen zu könnnen (Zeile 12 & 13)
  2. Umleiten des Inhalts der Datei deploy.conf aus den Repository in eine temporäre Datei und Einlesen dieser(Zeile 17 bis 19)
  3. Prüfung ob der in 1. übertragene Branch mit der via Variable build_branchübereinstimmt, ansonsten Abbruch (Zeile 23).
  4. Anlegen eines temporären Verzeichnisses
  5. Klonen des Bare-Repos1 in ein temporäres Verzeichnis (Zeile 25).
  6. Verzeichniswechsel in das temporäres Verzeichnis.
  7. Installation der im Gemfile spezifizierten Abhängigkeiten via bundle install4. Falls bundle install fehlschlägt, wird das nochmal mit der Option --redownload6 versucht.
  8. Generierung des HTML aus tmp in die mit www spezifizierte Document Root via jekyll build
  9. Löschung temporäres Verzeichniss und Datei. Dat wor et!

post-receive Hook

Als Erstes entfernen wir den Default post-receive Hook aus dem Bare-Repository um ihn später durch einen Link auf unser Skript zu ersetzen.

rm ~/repos/netzaffe.de/hooks/post-receive

Dann clonen wir das Jekyll Deployment Skript, dort passiert später die ganze Magie.

git clone https://github.com/fl3a/jekyll_deployment.git ~/repos 

Jetzt legen wir einen Symlink namens post-receive im Bare-Repo an, der auf das gleichnamige Deployment Skript verweist:

ln -s ~/repos/jekyll_deployment/post-receive ~/repos/netzaffe.de/hooks/post-receive

Last but not least, muss das Skript noch ausführbar gemacht werden:

chmod +x ~/repos/jekyll_deployment/post-receive

deploy.conf - Anpassung der Variablen

Mit dieser Konfiguration für das post-receive Skript verfährst du wie folgt:

  1. Kopiere hierzu deploy.conf in die Hauptebene deines lokalen Jekyll Repositories
  2. Passe die Variablen auf die Bedürfnisse deines Zielsystems hin an
  3. Committe diese Datei anschließend

Sofern du alles wie oben beschrieben umgesetzt hast und du auch auf uberspace bist😙, sind nur subdomain und domain anzupassen. Alle anderen Variablen sind vorbelegt, werden zusammengesetzt oder sind optional.

  • build_branch, Der Branch der gebaut werden soll z.B. master.
  • subdomain, optional. z.B. sub. oder leer. Falls gesetzt, achte auf den . am Ende!
  • domain Name der Domain, z.B. ‘netzaffe.de’.
  • git_repo Pfad zu Jekyll Bare Repo auf dem Server z.B. ${HOME}/repos/${domain}
  • www Pfad zur Document root auf dem Server, wo das generierte HTML ausgeliefert wird,
    z.B www=/var/www/virtual/${USER}/${subdomain}${domain}. Dieses Pfadschema ist uberspace spezifisch, aber natürlich anpassbar.

Bonus Smash: jekyll_deployment.sh

Die Datei jekyll_deployment.sh ist für die direkte Ausführung auf dem Zielsystem und manchmal ganz nützlich um das Deployment ohne einen Push anzustoßen, wenn z.B. bundler4 mal wieder zickt.

Es sind die gleichnamigen Variablen wie vorigen Abschnitt im Skript selbst anzupassen und die Datei oder ein Link sollten sich im Suchpfad befinden.

Nötige Schritte im lokalen Git-Repository

Das waren die Schritte auf deinem Uberspace, weiter gehts in deinen lokalen Git Repository. Das oben erstellte Bare-Repository fügst du deinem lokalen Repository so als sog. Remote-Repository3 namens uberspace hinzu:

git remote add uberspace fl3a@bellatrix.uberspace.de:repos/netzaffe.de

Fertig, jetzt noch der push vom master nach uberspace.

git push uberspace master

Nach der Übertragung der Daten solltest du jetzt die Ausgaben von git clone, bundle install und jekyll build sehen.

Learnings

  • Get file from git repo https://stackoverflow.com/questions/610208/how-to-retrieve-a-single-file-from-a-specific-revision-in-git
  • Eine Erkenntnis zu exit7 [sic]

    Es ist eine verbreitete Unsitte als letzten Befehl eines Scripts ‘exit 0’ zu verwenden. Ein Skript das zu Ende ist, ist zu Ende und braucht keinen ausdrücklichen Abbruch, vor allem keinen, der den letzten Fehler kaschiert.

  • Darauf bin ich beim Recherchieren zu exit gestoßen: traps8
  • git ours9, darauf bin ich gestoßen, während ich den Hook überarbeitet habe und in Richtung Config in Repository gegangen bin und an eine Config je Branch gedacht habe. Kannte ich nicht, das will ich mal ausprobieren.
  • Noch keine README im Repository, aber über goldene Türklinken nachdenken. jekyll_deployment.sh ist im Vergleich zu post-receive nicht so schön und schlank, aber die grundlegenede Funktionalität ist in beiden Skipten gleich… Auslagern🧠, es geht schöner⌨️! Verlieren wir uns nicht in Schönheit und bringen wir diesen Post erstmal ins Netz, Florian☝️. Es handelt sich hierbei ja eigentlich um ein Abfallprodukt, dass aus einer Ur-Version basiert.

Credits

Dieser Artikel basiert im wesentlichen auf Jekyll Auf Uberspace Mit Git von Daniel Wittberger und Jekyll Auf Uberspace von Franz aka laerador. Danke!

Dieser Artikel ist eine aktuelle Essenz, die sich nur auf das Deployment bezieht. Seit 2012, 2013 hat sich einiges in Jekyll und auf Uberspace etc. getan und das Skript hat noch etwas Liebe erfahren.

Verwandte Artikel