Pandoc und LaTeX CI-Pipeline
Inhaltsverzeichnis
Das Ergebnis dieser kleinen Übung sollte sein, dass ich auf egal welchem Gerät, auf dem kein Docker, LaTeX oder Pandoc existiert, Änderungen an meinem Lebenslauf machen kann, und am Ende in meinem selbst gehosteten GitLab für mich abgreifbar ein PDF herausfällt.
Das ist auch gelungen, aber im Laufe der Umsetzung, fand ich dann das Design des Auslösers gar nicht mal mehr so schön. Es wird wohl einen weiteren Post geben, bei dem ich dieses Setup erweitere.
Was ist Pandoc?
Pandoc ist ein Open-Source-Tool, mit dem man Textdokumente in verschiedenen Formaten konvertieren kann. Es unterstützt sehr viele Formate wie Markdown, HTML, LaTeX, PDF, DOCX und mehr. Pandoc ist besonders praktisch, wenn man Dokumente von einem Format in ein anderes umwandeln möchte.Was ist LaTeX?
LaTeX ist eine Markup-Sprache und ein Satzsystem. LaTeX ist besonders in der wissenschaftlichen Welt beliebt. Es wurde entwickelt, um Dokumente mit komplexen mathematischen Formeln, Tabellen und Abbildungen zu erstellen. Im Gegensatz zu herkömmlichen Textverarbeitungsprogrammen wie Microsoft Word, bei denen man das Aussehen des Dokuments direkt bearbeitet, gibt man in LaTeX den Inhalt des Dokuments mit einer Reihe von Befehlen an. LaTeX bietet enorme Flexibilität und Kontrolle über das Aussehen eines Dokuments.Hintergrund
Für andere Projekte hatte mich in der Vergangenheit mein Freund Florian bereits mehrfach auf Pandoc hingewiesen, und wir haben auch (seit Jahren) vor ein kleines Buch von unseren vergangenen D&D Abenteuern für die Spielgruppe zu drucken.
Mir kam dann irgendwann auf HackerNews eine Website unter, bei dem jemand moderncv benutzt, um sein Anschreiben und seinen Lebenslauf mit Pandoc und LaTeX zu bauen: https://mszep.github.io/pandoc_resume/
Der gute Mark beschwert sich hier zurecht, dass in vielen anderen Vorhaben, die PDF-Generierung automatisieren, auf wkhtmltopdf zurückgegriffen wird, obwohl Pandoc und LaTeX dazu viel besser geeignet sind.
Gleichzeitig wollte ich den gesamten Prozess vom erstellen des Docker Images, über das Veröffentlichen und die CI-Config schreiben bis zum Benutzen für mich einmal komplett selbst bearbeitet haben.
Vorraussetzungen
- Wissen über
git
- Ein GitLab (z.B. selbst gehostet) oder einen GitLab.com Account
- Ein GitLab-Runner oder CI bei GitLab.com
- mit Docker-Executor
- Eine lokale Docker-Installation
Ich betreibe privat meine eigene GitLab-Instanz, aber ich nehme an, dass auch ein Repository auf GitLab.com fast identisch funktioniert.
Ausblick
Um das Ziel zu erreichen, werden im Folgenden diese Punkte abgearbeitet:
- Ein GitLab Repository anlegen
- GitHub funktioniert auch, aber die CI-Config sieht dann anders aus
- Das Repository mit den Quelldaten füllen
- Als Grundlage habe ich mszep/pandoc_resume genommen
- Ein Docker Image erstellen
- Mit
pandoc
,context
undlatex
darin installiert
- Mit
- Das Image öffentlich erreichbar machen
- Das ist nicht zwingend nötig, ich wollte es aber mal gemacht haben
- Die GitLab CI-Config erstellen
- Hier werden alle vorherigen Schritte zusammengezogen
GitLab Repository
Wir brauchen ein git
Repository, damit wir unsere Daten versioniert vorhalten
und die Grundlage der CI-Pipeline haben. Ich habe mein GitLab Projekt zunächst
cv.md
genannt, aber ich möchte irgendwann nicht nur meine CV darin generieren
lassen, sondern auch Anschreiben und so weiter.
Ich habe mszep/pandoc_resume heruntergeladen und in mein eigenes Repository geschoben.
Wenn man möchte, kann man jetzt auf seinem Gerät auch pandoc
, texlive
und
context
installieren, um zu prüfen, ob das Makefile
für einen funktioniert,
aber ansonsten gehen wir gleich zum nächsten Schritt: Docker!
Docker
Was Docker ist, haben schon andere besser erklärt, und wer wirklich nicht weiß, was genau das ist, fängt vielleicht am Besten beim Wikipedia-Eintrag zu Docker an.
Wir benutzen Docker, weil es nicht nötig ist, die ganze Software, die bei der Erstellung der PDFs beteiligt ist, auf jedem Gerät zu installieren. Docker wird allerdings zwingend gebraucht um das Image zu bauen.
Docker Image
Das Docker Image ist das Herzstück unseres automatisierten PDF-Generierung. Es
basiert auf Ubuntu 22.04 und enthält pandoc
, texlive
und context
in den
relativ aktuellen Versionen aus den Ubuntu Repositories.
Pandoc kann unglaublich viele Konvertierungen vornehmen, aber die Start- und Ziel-Software muss dazu installiert sein, deswegen brauchen wir hier LaTeX.
Durch die Verwendung eines Docker Images müssen wir uns keine Gedanken über die Installation der Software auf jedem Gerät (Windows, Linux, mac OS) machen. Das spart viel Zeit und ist außerdem eine praktische Möglichkeit, um eine Komplettinstallation von LaTeX zu zentralisieren, die schon mehrere Gigabyte in Anspruch nehmen kann.
Das Dockerfile
, das wir in unserem Repository anlegen sieht so aus:
FROM ubuntu:22.04
LABEL description="A docker image with pandoc, texlive and context."
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y \
pandoc \
context \
make \
texlive \
texlive-latex-extra \
texlive-fonts-extra && \
rm -rf /var/lib/apt/lists/* && \
apt-get clean
WORKDIR /data
Wenn wir das Dockerfile
haben, müssen wir noch das Image tatsächlich bauen.
Dabei sollte man auch einen Namen für das Image haben. Ich war einfallslos und
nannte es pancontex
(wegen PANdoc
, CONText
und laTEX
). Das geht mit
folgendem Befehl:
docker build -t pancontex .
Nach dem Absetzen lädt Docker das ubuntu:22.04
Image herunter und führt die im
Dockerfile
angegebenen Befehle aus und installiert so alle benötigten Pakete.
Das kann einige Minuten dauern, denn am Ende war das Image etwa 3 Gigabyte groß.
[+] Building 206.3s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 786B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:22.04 0.9s
=> [auth] library/ubuntu:pull token for registry-1.docker.io 0.0s
=> CACHED [1/3] FROM docker.io/library/ubuntu:22.04@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 0.0s
=> [2/3] RUN apt update && apt install -y context 178.2s
=> [3/3] WORKDIR /data 0.1s
=> exporting to image 27.0s
=> => exporting layers 27.0s
=> => writing image sha256:46cab9516562f2807aed9f96821fbdbe97030bd362ff69f42ce8ce89aaafdbd1 0.0s
=> => naming to docker.io/library/pancontex 0.0s
So weit so gut, jetzt muss es nur noch veröffentlicht werden.
Docker Hub
Am Einfachsten ist es, wenn man das Docker Image in eine öffentlich erreichbare Docker Registry pusht. So ist sichergestellt, dass wir in den nächsten Schritten einfach auf das Image zugreifen können.
Eine davon ist z.B. https://hub.docker.com/. Hier kann man sich kostenlos einen Account anlegen.
Wenn man einen Account hat, fehlt noch, dass man seinem Docker sagt, wer man
ist, man loggt sich also mit seiner Docker Installation mit seinem Benutzernamen
auf hub.docker.com
an:
docker login -u $USERNAME
Unser Docker Image ist gebaut und wir sind gegenüber hub.docker.com
authentifiziert, jetzt fehlt unserem Image nur noch ein passendes Tag, mit dem
man es später gut identifizieren kann.
Docker Tagging ist fast ein eigenes Thema für sich, darum geht es in diesem Post aber nicht. Hier ist eine kurze Einführung dazu, es gibt viele mehr.
Wir brauchen nur den folgenden Befehl, der den Benutzernamen von Docker Hub enthält:
docker image tag pancontex $USERNAME/pancontex:latest
Nachdem Docker jetzt weiß, wer wir sind, und dass dieses Image uns gehört, können wir es mit dem folgenden Befehl auch endlich hochladen:
docker image push $USERNAME/pancontex:latest
Wer möchte, darf auch gerne einfach mein Docker Image benutzen. Ich garantiere allerdings nicht, dass ich noch Änderungen daran mache.
GitLab CI Config
Nun sollte alles an seinem Platz liegen, um über die folgenden CI-Konfiguration zu einem Ganzen zusammengefügt zu werden.
Wir nutzen das in mszep/pandoc_resume
vorbereitete Makefile
um die Generierung von allen vorkonfigurierten
Dateiformaten zu ermöglichen. Wer nur das PDF haben will, kann einfach make
durch make pdf
ersetzen.
Wir erstellen in unserem Repository eine Datei namens .gitlab-ci.yml
und dem
folgenden Inhalt:
stages:
- build
build:
stage: build
image:
name: $USERNAME/pancontex:latest
script:
- pandoc --version
- mtxrun --version
- make
artifacts:
paths:
- output/*
Das image
ist jenes, das wir zuvor zu hub.docker.com
gepusht haben. Um auf
die generierten Dateien zugriff zu bekommen, müssen wir sie als artifacts
kennzeichnen, andernfalls werden sie nach dem Ausführen der Befehle unter
script
einfach verworfen.
Beim Hinzufügen, der .gitlab-ci.yml
Datei zum Repository sollte das CI von
selbst anspringen und anfangen zu arbeiten.
Ergebnis
In dem GitLab Repository unter CI/CD und dort “Jobs” sollte unser CI-Job auftauchen und dessen Ausgabe im besten Fall mit den folgenden Zeilen enden:
Uploading artifacts for successful job
Uploading artifacts...
output/*: found 8 matching artifact files and directories
Uploading artifacts as "archive" to coordinator... 201 Created id=1881 responseStatus=201 Created token=64_zhdcz
Cleaning up project directory and file based variables
Job succeeded
In der rechten Sidebar in GitLab, sollte dann diese Box erscheinen:
Hier kann ein .zip
heruntergeladen, oder eine Online-Version der Artefakte
angesehen werden.
Zusammenfassung
Mit diesem Setup kann nun sehr einfach der Lebenslauf auf jedem Gerät aktualisiert werden, ohne aufwändige Installation der eigentlich nötigen Pakete.
Eigentlich kann man dank Pandoc und LaTeX das Design und die Struktur des Dokuments anpassen und erweitern, aber dazu muss man wegen der Vorlage leider ConTeXt lernen. Das habe ich festgestellt, als ich die Formattierung der linken Spalte (die Jahre, wann man wo gearbeitet hat) verkleinern wollte und es mit nicht gelungen ist. Da ich bereits LaTeX kann, war es mir auch keinen weiteren Aufwand wert, und ich werde das Setup anpassen, sodass ich gleich ganz auf Pandoc verzichten kann. Dass Pandoc noch in dem Image enthalten ist, ist Absicht, weil ich das für weitere Projekte nützlich finde und auch weiter verwenden werde.
Erweitern kann man dieses Setup noch, in dem der CI-Job das PDF oder die anderen erzeugten Dateien direkt auf einen Webspace deployed, damit die aktuellste Version des Lebenslaufs immer online abrufbar ist.
Optional kann man auch das Erstellen des Docker Images noch automatisieren. Wenn
die CI-Pipeline eine Änderung am Dockerfile
erkennt, könnte ein anderer Job
aktiv werden, der automatisiert das Image baut und veröffentlicht.