VMs mit Vagrant erstellen

Seite 4: VMs bestücken und Boxen erzeugen

Inhaltsverzeichnis

Häufig bedarf es jedoch nicht nur eines nackten Betriebssystems ohne zusätzliche installierte Anwendungen: In den vorangegangenen Beispielen war bereits von einem Webserver die Rede. Allerdings sind auch andere Dienste wie Datenbanken naheliegend.

Natürlich möchte man nicht nach jedem Neuaufsetzen einer virtuellen Maschine sämtliche Anwendungssoftware von Hand nachinstallieren müssen. Das wäre nicht nur lästig, sondern der durch Vagrant angezielten Einheitlichkeit innerhalb eines Teams abträglich: Zwar hätte dann jede VM ein gleich aufgesetztes Betriebssystem, sonst aber nichts.

Abhilfe schafft Vagrant durch die Möglichkeit, eine virtuelle Maschine automatisiert zu provisionieren, das heißt, sie mit einer vorgegebenen Menge von Anwendungssoftware zu bestücken und geeignet zu konfigurieren. Als einfachste Option bietet sich der Einsatz eines Shell-Skripts an, das sich bei Vagrant wahlweise in der Konfigurationsdatei oder extern ablegen lässt. Alternativ unterstützt es die dedizierten Konfigurationsverwaltungswerkzeuge Puppet, Chef, Ansible und Salt. Seit der im Dezember 2013 veröffentlichten Version 1.4.0 kann Vagrant darüber hinaus automatisch Docker in der virtuellen Maschine installieren und passende Abbilder herunterladen und starten.

Für die integrierte Angabe eines Shell-Skripts genügt es, Vagrantfile die folgende Zeile hinzuzufügen:

config.vm.provision :shell, :inline => "echo Hallo Vagrant!"

An Stelle des echo-Kommandos lässt sich jeder beliebige andere Aufruf angeben. Es liegt allerdings auf der Hand, dass solch ein Vorgehen höchstens dazu geeignet ist, beispielsweise – im Falle eines "Bridged"-Netzwerks – die eigene IP-Adresse auszugeben, oder bestenfalls ein externes Shell-Skript zu starten.

Dabei sind allerdings die Benutzerrechte zu beachten, weshalb in der Regel ein Aufruf via sudo sinnvoll ist:

config.vm.provision :shell, :inline => "sudo -iu vagrant
bash -c './vagrant/provision.sh'"

Es zeigt sich, dass dieses Vorgehen rasch unübersichtlich wird. Daher gibt es zwei Alternativen, wie man mit dem Aufruf eines Shell-Skripts umgehen kann. Zum Einen kann man ein externes Skript starten, indem man an Stelle von :inline den Parameter :path verwendet und ihm den Pfad zum auszuführenden Skript übergibt. Besonders praktisch ist, dass Vagrant das Skript in dem Fall automatisch mit sudo ausführt und der Pfad nicht nur auf das Dateisystem verweisen, sondern auch eine URL enthalten kann, von der Vagrant das Skript zunächst herunterladen soll:

config.vm.provision :shell, :path => "https://www.example.com/provision.sh"

Zum Anderen kann man das auszuführende Shell-Skript in die Konfigurationsdatei von Vagrant einbetten, und in der genannten Zeile darauf verweisen. Dazu ist prinzipiell eine Konfigurationsdatei nach folgendem Aufbau von Nöten:

$script = <<SCRIPT
echo "Hallo Vagrant!"
[...]
SCRIPT

Vagrant.configure("2") do |config|
[...]
config.vm.provision :shell, :inline $script
end

Analog zu dem Parameter :shell gibt es die Werte :puppet, :puppet_server, :chef_solo, :chef_client, :ansible, :salt und :docker. Mit ihnen ist eine deutlich komplexere Einrichtung und Konfiguration der virtuellen Maschine möglich. Praktischerweise unterstützt Vagrant zudem die Option, innerhalb einer Vagrantfile-Datei mehrere Provisionierungswege anzugeben, die sich dann nacheinander in der Reihenfolge ihres Auftretens abarbeiten lassen.

Im Gegensatz zu früheren Versionen von Vagrant führen die modernen Versionen die Provisionierung nicht mehr bei jedem Lauf des Kommandos vagrant up aus, sondern nur noch direkt nach dem Erstellen der virtuellen Maschine. Das verkürzt nicht nur deren Startzeit im normalen Betrieb, sondern erspart Shell-Skripten auch die Aufgabe, zu prüfen, ob sie bereits ausgeführt wurden.

Bei Bedarf kann man die Provisionierung jedoch durch die Angabe des Parameters --provision beim Aufruf von vagrant up erzwingen. Verwendet man stattdessen --provision-with, kann man zudem eine Art der Provisionierung angeben, um beispielsweise nur die Konfiguration von Puppet durchführen zu
lassen:

$ vagrant up --provision-with puppet

In der Regel genügt der Ansatz, die Konfiguration der virtuellen Maschine über Puppet, Chef & Co. durchzuführen. Gelegentlich kann es aber auch interessant sein, auf der Basis eines bestehenden ein neues Betriebssystemabbild zu erzeugen, das bereits fertig installierte und konfigurierte Anwendungssoftware enthält.

Glücklicherweise ist das Vorgehen in Vagrant hierfür ausgesprochen einfach: Zunächst erstellt man auf dem bereits bekannten Weg eine neue virtuelle Maschine, stellt per SSH eine Verbindung her und führt sämtliche Installations- und Konfigurationsschritte aus, die für das neue Abbild erforderlich sind.

Anschließend führt man das Kommando

$ vagrant package

aus. Als Ergebnis erzeugt Vagrant eine Datei namens package.box in einem temporären Verzeichnis, das das neue Betriebssystemabbild enthält. Letzteres lässt sich anschließend mit vagrant init beziehungsweise vagrant add verwenden.

Genügt ein vorhandenes Abbild nicht, kann man auch ein eigenes von Grund auf erstellen. Das ist jedoch deutlich aufwändiger, da unter anderem einige Vorgaben bezüglich der verwendeten Benutzer, Rechte und SSH-Konfiguration einzuhalten sind. Eine ausführliche Anleitung liefert Ryan Skoblenick in seinem Blogeintrag "Creating a Custom Vagrant Box from Scratch".

Generell sollte man sich allerdings zunächst die Frage stellen, ob das Erzeugen eines komplett neuen Abbilds den Aufwand wirklich wert ist, oder ob das Anpassen eines bestehenden nicht den gleichen Zweck erfüllt.