In diesem Blogbeitrag werden wir die Vereinfachung des Workflows der Provisionierung und Konfiguration virtueller Maschinenumgebungen mittels Vagrant demonstrieren, und uns auch Konzepte wie Multi-Machine, Shared Folders und Port Forwarding sowie Provisionierungs-Optionen ansehen.
Vagrant eignet sich als Schnittstelle zwischen Virtualisierungssoftware (VirtualBox, Hyper-V, Docker, VMWare, AWS, ...) und Konfigurations- bzw. Automatisierungstools wie z.B. Puppet, Chef oder SaltStack.
Als solche vereinfacht Vagrant das Erstellen und Warten von übertragbaren virtuellen Softwareentwicklungsumgebungen.
Wie einleitend beschrieben wird Vagrant zur Provisionierung von diverser Virtualisierungssoftware, auf eben dieser aufsitzend, eingesetzt. Für den Rahmen dieses Blogbeitrags entscheiden wir uns für VirtualBox, welches wir somit als Voraussetzung für Vagrant mitinstallieren werden.
Folgend werden wir die Installation von VirtualBox und Vagrant unter Linux Debian, Linux CentOS/RHEL7, MacOS und Windows behandeln.
2.1.1 VirtualBox
$ sudo apt-get update $ sudo apt-get install virtualbox
2.1.2 Vagrant
$ sudo apt-get install vagrant
2.2.1 VirtualBox
$ sudo cd /etc/yum.repos.d/ $ sudo wget http://download.virtualbox.org/virtualbox/rpm/rhel/virtualbox.repo $ sudo yum update $ sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm $ sudo yum install binutils gcc make patch libgomp glibc-headers glibc-devel kernel-headers kernel-devel dkms $ sudo yum install VirtualBox-5.2
2.2.2 Vagrant
$ sudo yum -y install ruby $ sudo gem install vagrant
2.3.1 VirtualBox
$ sudo brew cask install virtualbox
2.3.2 Vagrant
$ sudo brew cask install vagrant
2.4.1 VirtualBox
https://www.virtualbox.org/wiki/Downloads
2.4.2 Vagrant
box
(add, remove, etc.) boxes global-status
gibt den Status aller aktiven Vagrant Umgebungen auf dem System zurückhalt
schaltet die laufenden Maschine(n) ab, welche Vagrant verwaltetinit
initialisiert das aktuelle Verzeichnis, indem es ein initiales Vagrantfile generiertprovision
führt jeden konfigurierten provisioner gegen die laufenden von Vagrant verwalteten Maschinen ausreload
(entspricht halt && up
): normalerweise erforderlich, damit Änderungen, die im Vagrantfile vorgenommen wurden, wirksam werdenssh
Started eine SSH session in einer laufenden Vagrant Maschine und ermöglicht Zugriff auf deren Shellup
erstellt und konfiguriert guest machines gemäß Vagrantfile.Das Vagrantfile beschreibt unter anderem den für ein Projekt erforderlichen Maschinentyp, sowie Einstellungen / Anweisungen die Konfiguration und Provisionierung dieser Maschinen betreffend.
Im Regelfall wird je Projekt ein Vagrantfile ertellt, welches - z.B. via GiT - versioniert werden sollte. Dies ermöglicht es anderen am Projekt beteiligten Entwicklern, den Code auszulesen, Vagrant auszuführen und das Projekt somit bereits up-and-running zu haben.
Der Syntax des Vagrantfiles ist Ruby, allerdings sind Ruby-Programmier-Kenntnisse nicht zwingend notwendig, um Änderungen am Vagrantfile vorzunehmen bzw. dessen Aufbau zu verstehen, da es sich meist um einfache Variablenzuweisungen handelt.
Vagrant benötigt zumindest die Angabe des Images, welches für die Box heranzuziehen ist.
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/bionic64" end
Wird im Projektverzeichnis (in welchem sich auch das Vagrantfile befindet) nun vagrant up
ausgeführt, so erstellt Vagrant bereits eine Box mit Ubuntu als Betriebssystem eben dieser.
Im simpelsten Fall wird ein Vagrantfile verwendet, um Konfiguration und Provisionierungsparameter für eine einzelne guest machine zu definieren. Oftmals besteht die Infrastruktur eines Projektes aber auch aus mehreren Maschinen, die gegebenenfalls auch untereinander bekannt sein sollten oder zum Beispiel auch kommunizieren können sollten.
Folgende ein Beispiel für ein recht simples Vagrantfile, welches Beschreibungen für mehrere guest machines beinhaltet:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" end end
Oft beinhaltet das Projekt files / folders / executables, welche entsprechend auf die guest machine zu übertragen sind. Natürlich könnten diese nach boot-up der guest machine zum Beispiel via scp
übertragen werden - eine einfachere und vorteilhaftere Vorgehensweise ist aber das Konzept von Shared Folders - also Verzeichnisse, welche zwischen host machine und guest machine automatisch synchronisiert werden, so dass eine Änderung einer entsprechenden Datei auf dem host sofort in der guest machine entsprechend sichtbar / effektiv ist.
Wir erweitern das oben angeführte multi-machine Vagrant file, um auf der db
guest machine den Ordner, in welchem die Datenbankdateien abgelegt werden, zwischen host und guest zu sharen.
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" end end
In der Regel wird eine guest machine, sobald sie via Vagrant erstellt und hochgefahren wurde, weiter provisioniert, es wird Software ausgeliefert, installiert und konfiguriert, und sichergestellt dass die entsprechenden Services laufen.
Für solche Zwecke lässt sich Vagrant natürlich gut mit entsprechenden Automatisierungstools wie zum Beispiel Puppet, Ansible, Chef oder SaltStack kombinieren. Um den Rahmen dieses Blogbeitrages nicht zu sprengen beschränken wir uns in eben diesem aber erstmal auf zwei Möglichkeiten welche Vagrant selbst bietet: Inline-Provisionierung via direkter Übergabe der entsprechenden Kommandos, und Provisionierung durch Ausführung von zum Beispiel eines entsprechend vorbereiteten Shell Scripts.
Wir möchten auf der db
guest machine einen Postgres Datenbank Server installieren:
4.4.1 Inline-Provisionierung
Hierzu verwenden wir die Option vm.provision
:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", inline: "sudo apt-get update && sudo apt-get install -y postgresql" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" end end
4.4.2 Provisionierung via Shell-Script
Alternativ können wir die Kommandos auch in ein Shell-Script auslagern, und dieses gesamt ausführen. Dies macht bei umfangreicheren Kommandos gegenübergestellt der inline Provisionierung natürlich Sinn, vor dem Hintergrund von Lesbarkeit und Wartbarkeit. Auch hierfür wird die Option vm.provision
verwendet, und es wird der relative Pfad zum entsprechenden Shell-Script auf der host machine angegeben:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", path: "provision-db.sh" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" end end
Vagrant stellt einige high-level Netzwerkoptionen zur Verfügung, so zum Beispiel zwecks Portweiterleitung, Anbindung an ein öffentliches Netzwerk oder Erstellung eines privaten Netzwerks. Diese Optionen funktionieren als Abstraktions-Layer auch über mehrere Anbieter (VirtualBox, VMWare, ...) hinweg.
4.5.1 Private Networks
Vagrant private networks ermöglichen es über eine IP Adresse, welche aus dem globalen Internet nicht öffentlich zugänglich ist, auf die guest machine zuzugreifen.
Mehrere guest machines innerhalb eines privaten Netzwerks wiederum können über eben dieses miteinander kommunizieren, was natürlich insbesondere für multi-machine setups vorteilhaft ist.
Die einfachste Möglichkeit ein entsprechendes private network zu erstellen ist die Vergabe einer privaten IP Adresse via DHCP unter Verwendung der vm.network
Option und des private_network
identifiers:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.network "private_network", type: "dhcp" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", path: "provision-db.sh" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" web.vm.network "private_network", type: "dhcp" end end
Manchmal ist es allerdings vorteilhaft, die IP Adresse im Vorfeld statisch zu definieren. Auch dies ist via vm.network
und private_network
identifier möglich:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.network "private_network", ip: "10.0.2.1" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", path: "provision-db.sh" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" web.vm.network "private_network", ip: "10.0.2.2" end end
4.5.2 Public Networks
Vagrant public networks können, im Gegensatz zu privaten Netzwerken, aus dem globalen Internet öffentlich zugänglich sein.
Auch hier ist einfachste Möglichkeit die Vergabe einer dynamischen IP Adresse via DHCP unter Verwendung der vm.network
Option und des public_network
identifiers:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.network "public_network" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", path: "provision-db.sh" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" web.vm.network "public_network" end end
Und ein Beispiel unter Verwendung einer statischen IP Adresse:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.network "public_network", ip: "192.168.0.1" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", path: "provision-db.sh" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" web.vm.network "public_network", ip: "192.168.0.2" end end
Sollte mehr als ein network interface auf der host machine verfügbar sein, so kann das gewünschte interface definiert weden, zu welchem die guest machine eine Bridge erstellen soll, indem eine :bridge
-Klausel hinzugefügt wird wie folgt:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.network "public_network", bridge: "en0" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", path: "provision-db.sh" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" web.vm.network "public_network", bridge: "en0" end end
Manchmal ist es nötig, einen Port der host machine auf einen entsprechenden Port in einer Vagrant guest machine weiterzuleiten. Nehmen wir an unser webserver läuft virtualisiert in einer entsprechenden Vagrant guest machine auf Port 80
; wir werden höchstwahrscheinlich zum Beispiel Port 80
der host machine entsprechend weiterleiten wollen.
Auch für lokale Entwicklungsumgebungen macht dies Sinn; so könnte Port 8080
der host machine auf Port 80
des guests weitergeleitet werden, was dem Entwickler ermöglicht im lokalen Browser unter http://localhost:8080
den virtualisierten Webserver anzusteuern.
Letzteres setzen wir in unserem Vagrantfile von oben entsprechend um:
Vagrant.configure("2") do |config| # database server config.vm.define "db" do |db| db.vm.box = "ubuntu/bionic64" db.vm.synced_folder "./data/", "/usr/local/pgsql/data/" db.vm.provision "shell", path: "provision-db.sh" end # web server config.vm.define "web" do |web| web.vm.box = "ubuntu/bionic64" web.vm.network "forwarded_port", guest: 80, host: 8081 end end
Tags
Inhalt
Kommentare
Noch keine Kommentare