Die Entwicklung moderner Anwendungen erfordert meistens, dass die Entwickler eine Vielzahl von Tools und Services auf ihren Rechnern zur Verfügung haben: Compiler, Laufzeitumgebungen und IDEs um Quellcode editieren und bauen zu können, Infrastrukturservices wie Datenbanken und Messaging Dienste um die Anwendungen testen zu können, sowie Clients beispielsweise für Kubernetes um Probleme auf Test- oder Stagingumgebungen analysieren zu können. Für alle Entwickler eines Teams sollte transparent und nachvollziehbar sein welche Tools benötigt werden. Welche Möglichkeiten gibt es das umzusetzen?
Meistens wird die Installation der benötigten Software in Wikis oder READMEs dokumentiert. Dies birgt jedoch die Gefahr, dass die Informationen schnell veralten oder unvollständig sind, weil weitere Tools hinzugekommen sind und wird spätestens dann unübersichtlich, wenn Anleitungen für mehrere Betriebssysteme geschrieben werden müssen, beispielsweise weil im Entwicklungsteam mit Linux und macOS gearbeitet wird. Vor allem erfordert es aber ein manuelles Installieren und Aktualisieren der jeweiligen Toolchain, was aufwendig und fehleranfällig ist.
Vielfach arbeiten Entwickler auch an mehr als einer Anwendung, weshalb sie darauf angewiesen sind, schnell zu den spezifischen Tools der jeweiligen Anwendung – beispielsweise unterschiedliche Versionen von node.js, Python, Java oder auch Postgres – wechseln zu können. Dafür gibt es zwar eine Reihe plattformspezifischer Version Manager wie etwa nvm, den Node Version Manager, welche die parallele Installation mehrerer Versionen und den nahtlosen Wechsel dazwischen ermöglichen, diese lösen das Problem jedoch nur auf der Ebene der einzelnen Entwicklungsplattform, nicht für die komplette Toolchain.
Gesucht wird eine Möglichkeit, diese beiden Aufgaben plattformunabhängig zu automatisieren. Wünschenswert wäre ein Skript, welches zusammen mit dem Quelltext in die Versionsverwaltung eingecheckt wird, die Installation der benötigten Tools übernimmt und kurz und verständlich genug ist um von allen Entwicklern des Teams bei Bedarf angepasst und erweitert werden zu können. Im Idealfall weitgehend unabhängig davon, welches Betriebssystem ein Entwickler verwendet. Damit wäre es nicht nur möglich, neuen Mitarbeitern einen schnellen Start zu ermöglichen, sondern auch Änderungen schnell im Team zu verbreiten. Welche Möglichkeiten gibt es dafür?
Für Infrastrukturservices, wie Datenbanken, Messaging Server oder auch Authentisierungsprovider
ist es oftmals sinnvoll mit Containern oder, sofern Kubernetes für den Betrieb verwendet wird, mit speziellen Entwicklungstools für Kubernetes zu arbeiten, welche zusätzliche Möglickeiten bieten.
Genannt seien hier docker-compose, kubefwd,
MicroK8s oder minikube.
Auch für Entwicklungstools wie Compiler, Laufzeitumgebungen, Testtools oder CLIs kann man
prinzipiell auf Container zurückgreifen – auf DockerHub finden sich für die meisten Tools
entsprechende Images. Das ist jedoch ein relativ umständliches und ressourcenintensives Unterfangen: Für jedes Tool muss ein Image heruntergeladen werden, für jeden Toolaufruf
ein neuer Container erzeugt und nach Beendigung wieder gelöscht werden. Sollen Dateien
verarbeitet werden, beispielsweise beim kompilieren, muss das lokale Quelltextverzeichnis
in den Container gemountet werden, unter Umständen muss auch noch eine passende User ID
für die Ausführung innerhalb des Containers gesetzt werden.
Beispiel für einen Maven Build:
$ docker run -it --rm --name my-project -v "$(pwd)":/usr/src/mymaven \ -w /usr/src/mymaven maven:3.6.1-jdk-11 mvn install
Uns erschien das für einen dauerhaften Einsatz zu kompliziert, weshalb wir uns auf die Suche nach Alternativen gemacht haben. Und genau darum geht es in diesem ersten Teil einer zweiteiligen Reihe zur Automatisierung von Entwicklungsumgebungen: Wie kommen Entwicklungstools von denen jeder Entwickler häufig mehr als ein Dutzend benötigt möglichst umkompliziert auf seinen Rechner? Im zweiten Teil wird es dann um das Setup von Infrastrukturdiensten wie Datenbanken und Messaging Server und das Arbeiten mit Docker Containern und Kubernetes Clustern gehen.
Package Manager
Package Manager gibt es in unzählichen Varianten: Von plattformspezifisch, wie beispielsweise npm für node.js, über Linuxdistributions-spefisich wie apt für Debian bis hin zu Meta-Varianten in unterschiedlichen Ausprägungen. Für unseren Einsatzzweck suchen wir nach Paketmanagern mit den folgenden Eigenschaften:
- Beinhalten Pakete für mehr als eine Entwicklungsplattform
- Funktionieren betriebssystemübergreifend
- Erlauben die parallele Installation mehrere Versionen eines Pakets
- Bringen eine Scripting-Möglichkeit mit
Nix
Nix ist ein Package Manager für alle
Linux-Distributionen sowie macOS und außerdem
Bestandteil der Linux-Distribution NixOS. Er entstand aus einer Doktorarbeit heraus und
beinhaltet eine eigene Scripting-Sprache, die ebenfalls nix heißt. Das Paketverzeichnis
kann entweder über eine Weboberfläche
oder mittels Kommandozeile durchsucht werden. Bei der Auswahl der Pakete ist darauf zu
achten, dass einige wenige Pakete nur für Linux oder nur für macOS verfügbar sind.
Mehrere Versionen eines Pakets, beispielsweise Python 2.7 und 3.7 können parallel installiert
und je nach Projektanforderungen geladen werden.
Um einzelne Pakete oder eine komplette Projektumgebung zu laden, wird das Tool
Kommandozeilentool nix-shell
verwendet.
$ nix-shell -p nodejs-11_x
startet beispielsweise eine Shell in der node.js 11
vorhanden ist. Allerdings nur solange die Shell aktiv ist. Wird die Shell mit
Strg + D
wieder verlassen, wird auch node.js 11 wieder aus dem Pfad entfernt.
Das folgende Skript-Beispiel installiert eine Reihe von Tools – OpenJDK, Maven, curl, etc.
und führt anschließend noch zwei npm
Kommandos aus.
Diese Datei wird als default.nix
im Projektverzeichnis abgelegt. Geladen wird sie,
indem im Verzeichnis nix-shell
aufgerufen wird. Es ist auch möglich Version Pinning
zu verwenden und so immer die exakt gleiche Softwareversionen zu installieren.
Pakete die nicht im Store vorhanden sind, können selbst paketiert werden. Hierbei ist darauf zu achten, dass von manchen Projekten unterschiedliche Pakete für macOS und Linux bereitgestellt werden. Je nach Programmtyp – im Folgenden gekürzten Beispiel handelt es sich um eine Electron Desktopanwendung – muss außerdem ein entsprechender Wrapper verwendet werden.
Conda
Ist ein Package Manager für Windows, macOS und Linux der ursprünglich aus dem Datenanalyseumfeld stammt, mittlerweile aber um sehr viele allgemeine Tools erweitert wurde. Zu unterscheiden sind die beiden Ausgaben Anaconda und Miniconda. Anaconda beinhaltet einen kompletten Python und R Stack, Miniconda mehr oder weniger nur den Package Manager Conda, was für unsere Zwecke völlig ausreichend ist. Das Paketverzeichnis kann wieder entweder über eine Weboberfläche oder mittels Kommandozeilentool durchsucht werden.
Conda beinhaltet das Konzept Environments, damit sind voneinander isolierte Umgebungen gemeint in denen jeweils unterschiedliche Tools installiert werden können. Diese Environments können entweder über die Kommandozeile angelegt oder aus einem Skript geladen werden.
- Umgebung anlegen:
$ conda create --name meinProjekt
- Aktivieren:
$ conda activate meinProjekt
- Software installieren:
$ conda install -c anaconda-platform kubectl
- Umgebung in Datei speichern:
$ conda env export > environment.yaml
- Umgebung aus Datei laden:
$ conda env create -f=./environment.yaml
- Umgebung verlassen:
$ conda deactivate
Die Versionen für die zu installierenden Pakete können auch explizit angegeben werden. Zu beachten ist, das nicht immer für alle Betriebssysteme die gleichen Versionen vorliegen.
Weitere Möglichkeiten
Bei macOS Benutzern ist Homebrew sehr beliebt, dieses unterstützt seit einiger Zeit auch Pakete für Linux. Allerdings werden unter Linux keine Casks unterstützt, weshalb sich in diesem Fall keine graphischen Tools installieren lassen. Snapcraft ist ein Package Manager der ursprünglich für das Ubuntu Phone entwickelt wurde mittlerweile aber für alle gängigen Linux-Distributionen verfügbar ist. Es ist gut für die Installation einzelner Tools geeignet, da das Angebot an Packages sehr groß ist. Es bringt jedoch keine Möglichkeit mit, ein komplettes Toolset zu verwalten, auch wird momentan keine Möglichkeit geboten zwischen verschiedenen Versionen eines Tools zu wechseln. Chocolatey ist ein Package Manager für Windows der in einer Open Source und einer kommerziellen Version angeboten wird. Die kommerzielle Version beinhaltet unter anderem Tools, um das Erstellen neuer Pakete zu vereinfachen. Die Dokumentation ist umfangreich und es sind Pakete für alle gängigen Entwicklungsplattformen enthalten. Die Installation mehrerer Versionen eines Tools ist grundsätzlich möglich, die Verwendung erfordert jedoch manuelle Anpassungen am PATH.
Name | unterstützte Betriebssysteme | Fileformat/Scripting zur Definition von Umgebungen | mehrere Versionen | Webseite |
---|---|---|---|---|
Nix | Linux, macOS | ja | ja | https://nixos.org/nix |
Conda | Linux, macOS, Windows | ja | ja | https://conda.io |
Homebrew | macOS, Linux mit Einschränkungen | nein | ja | https://brew.sh/ bzw. https://docs.brew.sh/Homebrew-on-Linux |
Snapcraft | Linux | nein | nein | https://snapcraft.io |
Chocolatey | Windows | nein | jain ( manuelle Anpassungen erforderlich ) | https://chocolatey.org |