Häufig befinden sich Entwicklerteams in der Situation, dass für das lokale Testen während der Entwicklung eine Vielzahl unterschiedlicher Systeme, die der Produktivumgebung möglichst ähnlich sind, benötigt werden. Dies führt häufig zu langen Anleitungen in irgendwelchen Wikis oder Ähnlichem, in denen versucht wird festzuhalten, welche Schritte notwendig sind, um eine Umgebung auf einem neuen Rechner einzurichten. Jeder Entwickler der neu in das Projekt kommt, ist dann erst einmal Stunden oder Tage damit beschäftigt diese Schritte nachzuvollziehen, bevor er produktiv arbeiten kann. Je mehr Systeme (Datenbank, FTP-Server, etc.) benötigt werden, umso größer entsprechend der Aufwand. Daher ist es sicher nicht verkehrt über eine Automatisierung und Virtualisierung solch einer Testumgebung nachzudenken.
Vagrant
Vagrant ist ein Werkzeug für das einfache Verwalten und Konfigurieren von virtuellen Maschinen, welches ideal für das Bereitstellen von Entwicklungsumgebungen geeignet ist. Die Virtualisierung wird nicht von Vagrant selbst übernommen, sondern an einen dafür zuständigen Provider gegeben. Als Virtualisierungsprovider können die bekannten Technologien wie Oracle VirtualBox, VMWare, KVM oder Docker genutzt werden. Häufig wird man VirtualBox vorfinden, da dies kostenfrei ist und für alle gängigen Plattformen zur Verfügung steht. Vagrant selbst ist ebenfalls für die Betriebssysteme Linux, FreeBSD, OS X, und Windows erhältlich.
Vagrant ist von der Handhabung her sehr einfach zu bedienen, da lediglich eine Datei für die Konfiguration (die z.B. mit dem Sourcecode in die Versionsverwaltung eingecheckt werden kann) und eine Handvoll Befehle für das Steuern notwendig sind.
Boxes
Vagrant arbeitet mit Basisimages welche als Boxes bezeichnet werden. Ein solches Basisimage könnte z.B. ein vorinstalliertes nacktes Betriebssystem sein. Diese Images können von Vagrant selbstständig heruntergeladen werden. Anschließend werden die Boxes zentral auf dem lokalen Rechner abgelegt, sodass ein erneutes Herunterladen nicht notwendig ist. Jedes Vagrant-Projekt klont dann diese Box noch einmal, damit nicht auf demselben Image gearbeitet wird. Eine gewisse Anzahl Vagrant-Boxes stehen bereits im Internet zur Verfügung, das Suchen nach Boxes ist unter https://atlas.hashicorp.com/boxes/search möglich. Darüber hinaus besteht auch die Möglichkeit eigene Boxes auf einem eigenem Server bereitzustellen. Alle Images sind jeweils an einen Virtualisierungsprovider gebunden. Die Boxes können Versioniert werden, sodass es möglich ist Updates bereitzustellen und bei der Verwendung genau festlegen zu können, mit welchem Stand gearbeitet werden soll.
Getting Started
Ein Vagrant-File beschreibt eine virtuelle Maschine. Es definiert ein Basisimage, sowie einen oder mehrere Virtualisierungsprovider. Ein neues File kann einfach über den Init-Befehl erzeugt werden. Um z.B. ein neues Vagrant-Projekt zu erzeugen, welches ein Debian-Basisimage referenziert, kann der folgende Befehl verwendet werden.
vagrant init debian/jessie64
Die Virtuelle-Umgebung kann anschließend direkt gestartet werden über den Befehl:
vagrant up
Dies führt zu einem Herunterladen (falls nicht vorhanden) der Box und einem anschließendem Hochfahren der VM. Um jetzt schon mal einen Blick in die VM zu werfen, kann man sich direkt mit dem entsprechenden Vagrant-Befehl verbinden und einloggen:
vagrant ssh
Anschließend kann die virtuelle Maschine heruntergefahren werden über:
vagrant halt
Dabei bleibt der Zustand den man bei Arbeiten in der Maschine hinterlassen hat erhalten. Möchte man den Zustand verwerfen und wieder auf einem frischen Image arbeiten, so hat man die Möglichkeit das alte Image zu verwerfen über:
vagrant destroy
Vagrant-File
Von der Syntax her werden Vagrant-Files in Ruby geschrieben, allerdings sind keine großen Kenntnisse erforderlich, da es sich in der Regel hauptsächlich um Variablen-Zuweisungen handelt. In dem File können verschiedene Eigenschaften der VM konfiguriert werden, wie z.B.: Image+Version, Networking, Folder-Syncing, Arbeitsspeicher, CPU und das Provisioning. Es besteht auch die Möglichkeit eine bestimmte Vagrant-Version als Mindestanforderung zu definieren.
Beispiel für ein Vagrant-File:
Vagrant.require_version ">= 1.7.2" Vagrant.configure("2") do |config| config.vm.box = "debian/jessie64" config.vm.box_version = "= 8.4.0" config.vm.network "private_network", ip: "172.28.128.4" config.vm.hostname = "vagrant-demo.local" config.vm.provider "virtualbox" do |v| v.memory = 4000 v.cpus = 2 v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] end config.vm.synced_folder ".", "/vagrant", type: "virtualbox" config.vm.provision "shell", inline: $provisionScript, keep_color: true end
Die „2“ in Vagrant.configure legt die Version der Konfigurationsart fest, 2 ist die aktuelle, es werden aber auch noch ältere unterstützt.
Provisioning
Um jetzt das nackte Image mit der Projekt-bezogenen Software zu bestücken, kann das Provisioning verwendet werden. Es gibt dafür verschiedene Provisioner die dazu herangezogen werden können. Das einfachste ist vermutlich zunächst die Variante „shell“. Diese Erlaubt es ein Shell-Skript anzugeben, welches nach dem erstmaligen Hochfahren der VM ausgeführt wird und für das Einrichten der Software sorgt. Das Skript kann als zusätzliche Datei vorliegen, oder inline in dem Vagrant-File definiert werden.
Alternativ gibt es auch noch die Möglichkeit ein Provisioning via Chef, Puppet oder anderen Werkzeugen vorzunehmen, die dann allerdings auch entsprechende Kenntnisse erfordern. Auch möglich ist es mit Docker als Provisioning-Verfahren zu arbeiten. In diesem Fall wird automatisch in der VM Docker installiert und in der Konfiguration können Images angegeben werden, welche automatisch geladen und gestartet werden sollen. Diese Möglichkeit ist sicherlich interessant, wenn ohnehin, z.B. auf der Produktions- und/oder Testumgebung mit Docker gearbeitet wird und die Docker-Images daher sowieso vorliegen.
Provisioning wird per Default einmal beim ersten Einrichten durchgeführt. Allerdings besteht die Möglichkeit ein erneutes Provisioning anzustoßen mit Hilfe des Parameters –provision .
Vagrant up –provision
Es ist ebenfalls möglich für die einzelnen Provisions festzulegen, ob diese nur zu Beginn (und bei expliziter Anforderung über –provision) oder jedes Mal ausgeführt werden sollen. Sinn macht ein erneutes Provisioning natürlich nur, wenn die Skripte in einer Art geschrieben sind, dass diese wiederholt fehlerfrei und ohne Nebeneffekte funktionieren.
Networking/Sharing
Die Netzwerkeinstellungen können in dem Vagrantfile unter dem Punkt config.vm.network vorgenommen werden. Hier besteht die Möglichkeit festzulegen, ob es ein privates Netzwerk, oder ein öffentliches Netzwerk sein soll. In der Regel möchte man ein privates, sodass die VM nur auf dem Host-Rechner selber sichtbar ist. Eine IP kann entweder per DHCP vergeben, oder fest eingetragen werden.
config.vm.network "private_network", ip: "172.28.128.4";
Es besteht auch die Möglichkeit eine Portweiterleitung zu konfigurieren, sodass Dienste auf bestimmten Ports direkt auf dem Host-Rechner unter localhost erreichbar sind.
config.vm.network "forwarded_port", guest: 8080, host: 8080
Mit Hilfe des Befehls share kann Zugriff von außerhalb auf die Maschine ermöglicht werden. Dabei wird eine URL bzw. ein Name generiert, welche von der Remote-Maschine aus genutzt werden kann, um auf das Vagrant-Environment zuzugreifen.
Dateienaustausch
Häufig wird man vor dem Problem stehen, Dateien zwischen Host und Gast austauschen zu wollen. Vagrant bietet dafür eine einfache Möglichkeit indem das Verzeichnis auf dem Host, welches das Vagrant-File enthält, im Gastsystem zur Verfügung gestellt wird. Es gibt verschieden Verfahren für das Synchronisieren der Daten. Im Falle von VirtualBox als Provider bietet es sich an, den Typ „virtualbox“ zu wählen, welcher mit Hilfe der VirtuelBox-Gasterweiterungen arbeitet. Dies setzt natürlich voraus, dass diese Erweiterungen in der Box installiert sind.
Plugins
Es gibt eine Reihe von Plugins die für Vagrant verfügbar sind und zusätzliche Funktionalität anbieten. Ein Beispiel für so ein Plugin ist z.B. das VirtualBox-Guest Plugin, welches beim Einrichten der VM nachschaut, ob die Gasterweiterungen für VirtualBox installiert sind und diese ansonsten bei Bedarf nachinstalliert. Um ein Vagrant-Plugin zu installieren reicht wiederum ein einfacher Befehl:
vagrant plugin install vagrant-vbguest
Demo
Das Demo-Projekt enthält ein Vagrant-File, welches ein Debian-Basis-Image nutzt und darin Java, eine MySql-Datenbank und einen Wildfly-Applicationserver einrichtet. Erforderlich für das Verwenden sind: VirtualBox, Vagrant und die Plugins vagrant-vbguest und vagrant-triggers. Das erstmalige Starten dauert eine Weile, da sowohl die Box, als auch die Software heruntergeladen werden. Zu finden ist das Projekt unter: https://github.com/GEDOPLAN/vagrant-demo