Das System-Perl zu verwenden hat viele Nachteile. Diese können behoben werden, wenn man ein eigenes Perl in seinem Benutzerverzeichnis installiert. Mit dem Werkzeug perlbrew
kannst du mehrere Perl-Installationen nebeneinander auf einem System konfliktfrei betreiben.
Die Anwendungsentwicklung mit dem System-Perl zu koppeln bringt viele Nachteile mit sich. Hier einige Beispiele:
Eine Lösung ist perlbrew
, das die Installation mehrerer Perl-Versionen im Benutzerverzeichnis ermöglicht, so dass keine Administratorrechte benötigt werden. Das Werkezeug isoliert diese Installationen voneinander und ermöglicht einen einfachen Wechsel zwischen ihnen.
Die Installation von perlbrew
ist auf zwei Wegen möglich. Die einfachste geht über cpanm
:
$ cpanm App::perlbrew
$ perlbrew init
Solltest du keine Module von CPAN installieren können (siehe meine Anmerkung oben zu fehlenden Adminstratorrechten), kannst du dir ein Installationsskript herunterladen und es von der Shell ausführen lassen. Aus Sicherheitsgründen verweise ich dich dafür auf die Homepage.
perlbrew
kann alle offiziell verfügbaren Perl-Versionen bauen und installieren. Welche das sind, kannst du dir auflisten lassen:
$ perlbrew available
perl-5.33.7
perl-5.32.1
perl-5.30.3
perl-5.28.3
perl-5.26.3.tar.bz2
...
perl-5.8.9.tar.bz2
perl-5.6.2
perl5.005_03
perl5.004_05
cperl-5.29.2
cperl-5.30.0
cperl-5.30.0-RC1
Aus diesen Versionen wählst du dir eine aus. Diese wird dann in das Verzeichnis perl5/perlbrew
im Benutzerverzeichnis installiert:
perlbrew install perl-5.33.7
$ perlbrew install perl-5.33.7
Fetching perl 5.33.7 as $HOME/perl5/perlbrew/dists/perl-5.33.7.tar.gz
Download http://www.cpan.org/src/5.0/perl-5.33.7.tar.gz to $HOME/perl5/perlbrew/dists/perl-5.33.7.tar.gz
Installing /Users/glauschwuffel/perl5/perlbrew/build/perl-5.33.7/perl-5.33.7 into ~/perl5/perlbrew/perls/perl-5.33.7
This could take a while. You can run the following command on another shell to track the status:
tail -f ~/perl5/perlbrew/build.perl-5.33.7.log
Wenn du den in der letzten Zeile angegeben Befehl in einer zweiten Shell ausführt, kannst du dem Installationprozess »zusehen«.
Welches Perl die Shell ausführt, wird durch den Ausführungspfad bestimmt. Durch die Änderung dieses Ausführungspfads wird zwischen den installierten Perl-Versionen umgeschaltet. Dafür gibt es den perlbrew-Befehl use
:
$ perlbrew use perl-5.33.7
Durch mehrfache Verwendung von perlbrew use
kannst du in einer Arbeitssitzung in der Shell zwischen den Versionen wechseln. Beim Öffnen einer weiteren Shell wird aber weiterhin das System-Perl verwendet. Wenn du dauerhaft eine Perl-Version verwenden möchtest, kann du mit dem Befehl switch
die gewünschte Version in der Shell-Konfiguration ablegen:
perlbrew switch perl-5.33.7
Gelegentlich kommt es bei der Arbeit mit perlbrew
vor, dass kurzfristig das System-Perl benutzt werden soll:
perlbrew switch-off
Mit den hier gezeigten Befehlen hast du nun die grundlegenden Werkzeuge zusammen, um dir die Perl-Versionen zu installieren, die du benötigst. Da sich alles in deinem Benutzerverzeichnis abspielt, hast du die volle Kontrolle.
In diesem Artikel habe ich einen kurzen Überblick über die Möglichkeiten gegeben, die perlbrew
bietet. Dabei konnte ich vieles nur anreißen. Wenn du jetzt neugierig geworden bist und tiefer einsteigen möchtest, empfehle ich dir die Homepage des Projekts, um mehr über weitere Befehle zu erfahren.
Permalink: /2021-07-14-perlbrew
Gitlab ist eine webbasierte Plattform für die kontinuierliche Auslieferung von Software. Diese Plattform bietet viele Funktionen, die über die reine Softwareentwicklung und das Deployment hinausgehen. Wir erstellen damit Perl-Distributionen, Docker-Images sowie Dokumentation.
Gitlab ist eine webbasierte Plattform für die kontinuierliche Auslieferung von Software. Unter anderem integriert es Komponenten wie ein Wiki, ein Ticket-System und die Unterstützung des Versionskontrollsystems Git. Außerdem bietet es eine automatisierte Ausführung von beliebigem Code in Docker-Images an, die von Commits ausgelöst werden können.
Welche Befehle ausgeführt werden, kann man in einer YAML-Datei beschreiben. Dort wird auch beschrieben, welches Docker-Image dafür verwendet werden soll und unter welchen Bedingungen die Befehle ausgeführt werden sollen.
Wie wir bei Perl-Services diese Möglichkeiten nutzen, beschreibe ich in diesem Artikel.
Als wir begonnen haben, Gitlab zu evaluieren, haben wir zunächst kleinere Perl-Distributionen als Projekt angelegt und die Git-Repositorys eingebunden. In den YAML-Dateien dieser Projekte haben wir dann konfiguriert, dass nach jedem Commit die Unit-Tests ausgeführt werden und zum Abschluss die Perl-Distribution paketiert werden sollen. Hier ein Auszug aus einem mittlerweile so nicht mehr existenten Projekt:
image: ubuntu:rolling
build:
script:
- apt-get update -qq
- cpanm --installdeps .
- dzil authordeps | cpanm
- dzil listdeps | cpanm
- dzil build
artifacts:
when: always
name: "${CI_BUILD_STAGE}_${CI_BUILD_REF_NAME}"
paths:
- *.tar.gz
Unser Ansatz war zunächst, Fehler durch Tests zu finden und bei erfolgreichem Testdurchlauf die Perl-Distribution zu erstellen. Die benötigten Abhängigkeiten haben wir mit cpanm
installiert. Dabei haben wir festgestellt, dass wir gerne schneller Rückmeldung erhalten würden. Dies führte dann dazu, dass wir die Build-Pipeline optimiert haben.
Verkürzte Durchlaufzeiten erreichen wir einerseits durch eine Anpassung der Befehle, andererseits aber auch dadurch, dass wir ein Docker-Image verwenden, das für diese Distribution optimiert ist und bereits alle Abhängigkeiten enthält.
Was sind die nächsten Schritte? Wir prüfen, ob wir die erfolgreich gebauten Distributionen automatisiert in einen Pinto-Server laden oder auf CPAN veröffentlichen.
Im vorherigen Abschnitt habe ich erwähnt, dass wir Docker-Images für die Entwicklung von Perl-Distributionen optimieren. Wir wollen dafür alle Abhängigkeiten einer Perl-Distribution in einem Docker-Image zur Verfügung stellen, damit wir die Durchlaufzeit der Perl-Distribution klein halten und dann schnell Rückmeldung nach einem Commit bekommen.
Wie haben wir dies mit Gitlab erreicht? Wir setzen Dist::Zilla
ein und beschreiben Abhängigkeiten über dessen Konfiguration dist.ini
und das cpanfile
. Im verwendeten Docker-Image werden diese darüber beschriebenen Abhängigkeiten mit cpanm
installiert.
Dafür haben wir Gitlab so konfiguriert, dass bei einer Änderung dieser Dateien im Master-Branch der Perl-Distribution das verwendete Docker-Image neu erstellt wird. Hier ein beispielhafter Auszug aus einer Gitlab-Konfiguration:
trigger_image_build:
stage: trigger
script:
- curl --request POST --form "token=$CI_JOB_TOKEN" --form ref=master https://gitlab.com/api/v4/projects/9398220/trigger/pipeline
only:
refs:
- /^master$/
changes:
- cpanfile
- dist.ini
Die Beschreibungen der Abhängigkeiten werden beim Erstellen des Docker-Images aus dem abhängigen Projekt gelesen. Hier ein beispielhafter Auszug aus einem Dockerfile:
RUN cd /home/mydocker/src && \
git clone https://gitlab-ci-token:${CI_TOKEN}@gitlab.com/perlservices/project.git && \
[...]
RUN cd /home/mydocker/src/project && \
cpanm --skip-satisfied --installdeps . && \
dzil authordeps --missing | cpanm --skip-satisfied && \
dzil listdeps | cpanm --skip-satisfied
Die Gitlab-Dokumentation hat uns hier teilweise eher verwirrt als geholfen, aber letzten Endes haben wir ein perfekt abgestimmtes Image erhalten, in dem alle Abhängigkeiten enthalten sind. Dadurch können in dem Projekt, das auf diesem Image basiert, nach einem Commit sofort die Unit-Tests ausgeführt werden können.
Die Durchlaufzeiten sind daher sehr gering und liegen bei einem gehosteten Gitlab-Repository bei etwa drei Minuten. Der Löwenanteil dieser drei Minuten liegt darin begründet, dass wir auf einen freien Gitlab-Runner warten müssen.
Um die Durchlaufzeiten weiter zu verringern, migrieren wir die Repositorys derzeit auf einen eigenen Gitlab-Server.
Hinweis: Das müssen wir wegen dem Fall des Privacy Shields ohnehin machen 🙂
Die in Projekten zu erstellende Dokumentation reicht je nach Wunsch des Kunden von kurzen Beschreibungen über HTML-Dateien bis zu sauber mit LaTeX gesetzten Dokumenten. Das Ausgangsformat der Dokumente ist für uns stets Markdown, da dies einfach zu schreiben ist, wir uns auf das Wesentliche konzentrieren können und alle gewünschten Zielformate erzeugt werden können.
In Gitlab erzeugen wir mit pandoc
aus den Quelldateien das Zielformat. Gegebenenfalls verarbeiten wir das Resultat automatisiert weiter. Wenn als Ergebnis beispielsweise ein PDF erzeugt werden soll, dann bedeutet dies, dass wir aus Markdown LaTeX-Dokumente erzeugen und diese im Anschluss mit lualatex
in ein PDF wandeln. Damit dies möglich ist, haben wir uns ein Docker-Image erstellt, in dem TeX Live installiert ist.
Da wir lualatex aus TeX Live einsetzen, ist unser Docker-Image mehrere Gigabyte groß. Diese Kröte müssen wir wohl schlucken
. Pandoc
leistet sehr gute Dienste und die Entscheidung für Markdown als Ausgangsformat hat sich bewährt.
Wir werden diese Kombination beibehalten, jedoch gelegentlich prüfen, ob wir das Docker-Image etwas verkleinern können 🙂
Wir erstellen mit Gitlab automatisiert Perl-Distributionen, Docker-Images und Dokumente in unterschiedlichen Formaten. Gitlab als Plattform hat sich hierfür bewährt. Durch den Einsatz einer selbst betriebenen Gitlab-Instanz erhoffen wir uns geringere Durchlaufzeiten.
Permalink: /2020-09-01-wie-nutzen-wir-gitlab