Hintergrundbild
Navigation

Literate Vagrant

Version: 0.1.1
Beitrag als PDF-Datei

Inhaltsverzeichnis

Erste Schritte

Installation

Die Installation von Vagrant kann über den Paketmanager erfolgen; für Debian-basierte Systeme bspw. so:

<test-setup.sh>=

  sudo aptitude install vagrant virtualbox

Je nach Distribution kann es aber sein, dass die angebotene Version zu alt ist. Erst ab Vagrant v1.3.0 ist der Salt-Provisioner verfügbar, weshalb eine manuelle Installation der aktuellen Version sinnvoll sein kann.

Eine erste virtuelle Maschine erstellen

Zunächst wird Arbeitsverzeichnis erstellt

<test-setup.sh 2>=

  mkdir ~/vagrant-tests && cd ~/vagrant-tests

und anschließend initialisiert:

<test-setup.sh 3>=

  vagrant init

Bevor eine VM erstellt werden kann, muss das zugehörige System - im Vagrant-Jargon auch Box genannt - dem Host-System bekannt gemacht werden. Diese Informationen werden im Verzeichnis ~/.vagrant.d verwaltet. Dort landen auch die aus dem Netz geladenen Boxen.

<test-setup.sh 4>=

  vagrant box add ubuntu http://files.vagrantup.com/precise32.box

Welche Boxen verfügbar sind, zeigt vagrant box list.

Bei der Initialisierung wird eine Datei namens Vagrantfile erzeugt, in der Details zu der zu erstellenden virtuellen Maschine stehen. Der Eintrag config.vm.box beschreibt, welche Box die Grundlage für die VM sein soll:

<Vagrantfile-Beispiel>=

  Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu"
  end

Sobald dieser Eintrag gemacht wurde, lässt sich die VM schon erstellen und betreten:

<test-setup.sh 5>=

  vagrant up
  vagrant ssh

Jetzt befinden wir uns in einer normalen SSH-Session in der VM. Vagrant synchronisiert das Verzeichnis /vagrant mit dem oben erstellten Arbeitsverzeichnis, was einen bequemen Dateiaustausch ermöglicht.

Zum Verlassen der VM wird wie bei jeder SSH-Session ein exit ausgeführt. Ob die VM nun gelöscht oder suspendiert wird, obliegt dem Anwender.

  • Löschen: vagrant destroy
  • Suspendieren: vagrant suspend
  • Stoppen: vagrant halt, entspricht einem halt in der der VM.

Suspendierte oder angehaltene VMs können jederzeit mit vagrant up neu gestartet werden, eine komplette Neueinrichtung ist nicht notwendig.

Netzwerk: Port Forwarding

Die VM laufen standardmäßig über ein NAT und sind von außen nicht erreichbar. Möchte man bspw. einen Webserver testen, kann mittels Port Forwarding ein Host-Port an einen Gast-Port weitergeleitet werden. Dazu muss die Konfigurationsdatei Vagrantfile folgendermaßen angepasst werden:

  config.vm.network :forwarded_port, host: 8080, guest: 80

Damit wird der lokale Port 8080 auf den VM-Port 80 weitergeleitet.

Provisionierung mit Shell-Skripten

Vagrant unterstützt die Provisionierung von VMs auf einfachste Art durch Shell-Skripte, aber auch Werkzeuge wie Puppet oder Salt können verwendet werden.

Ein Beispiel: In der VM soll ein Apache Webserver installiert werden. Zunächst wird dazu ein Installationsskript geschrieben:

<bootstrap.sh>=

  #!/usr/bin/env bash
  
  apt-get update
  apt-get install -y apache2
  if ! [ -L /var/www ]; then
    rm -rf /var/www
    ln -fs /vagrant /var/www
  fi

Dann muss in der Konfigurationsdatei Vagrantfile die Provisionierung eingerichtet werden:

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu"
  config.vm.network :forwarded_port, host: 8080, guest: 80
  config.vm.provision :shell, path: "bootstrap.sh"
end

Der Pfad zum Skript ist relativ zum Arbeitsverzeichnis zu sehen. Das Skript muss nicht ausführbar sein.

Die Provisionierung wird automatisch beim ersten Start (vagrant up) ausgeführt. Läuft die VM schon, kann mit vagrant reload --provision das Skript manuell erneut gestartet werden.

Eigene Boxen

Eine Box ist eine fertig eingerichtete VM. Bevor ein konkretes Projekt aufgesetzt werden kann, muss die gewünschte Box mit vagrant box add <name> <url> import werden.

Alternativ zu den auf HashiCorps Atlas verfügbaren Boxen können auch eigene sog. Base Boxes aufgebaut werden. Diese müssen folgende Anforderungen erfüllen:

  • Disk Space: abhängig vom zu installierenden System, 8-10 GB sollten aber reichen
  • Speicher: 512 Mb reichen aus, er kann in der Konfigurationsdatei der späteren VM geändert werden
  • deaktivierte Audio- und USB-Peripherie (nicht notwendig)
  • Default User: vagrant mit sudo-Rechten (s.u.)
  • root-Passwort: vagrant
  • laufender SSH-Dienst

Einstellungen für VirtualBox-Provider

Kommt VirtualBox als Provider zum Einsatz, muss bei der Konfiguration Folgendes beachtet werden:

  • Netzwerkadapter 1: muss NAT sein
  • MAC-Adresse muss im Vagrantfile stehen (geschieht aber beim Packen automatisch; s.u.)
  • die VirtualBox Guest Additions müssen installiert sein, damit Ordner geteilt werden können:
  • sudo apt-get install linux-headers-generic build-essential dkms
  • CD via GUI “einlegen” und mounten: sudo mount /dev/cdrom /media/cdrom
  • Shellskript ausführen: /media/cdrom/VBoxLinuxAdditions.run

Wird als Gast Debian GNU/Linux installiert, geschieht die Einrichtung der Guest Additions automatisch und muss nicht manuell erfolgen. U.U. kommt es dann aber zu Versionsunterschieden zwischen VirtualBox und den Guest Additions.

Systemeinstellungen

Damit Vagrant via SSH arbeiten kann, wird ein unsicheres Schlüsselpaar verwendet. In der VM muss dazu in /home/vagrant/.ssh/authorized_keys der öffentliche Schlüssel vagrant.pub liegen (s. auch Insecure Keypair). Die Rechte des Ordners müssen auf 0700 und die der Datei auf 0600 stehen.

<vagrant.pub>=

  ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key

Um SSH zu beschleunigen, sollte in der VM die SSH-Serverkonfiguration die Option UseDNS auf no stehen (wenn diese Option in der jeweiligen Version verfügbar ist).

Weiterhin ist ein passwortloses sudo erforderlich. Dazu muss in der VM mittels visudo die Zeile

vagrant ALL=(ALL) NOPASSWD: ALL

eingefügt werden.

Weitere Einstellungen

Bootloader-Timeout vermeiden

Damit das installierte System im Bootloader nicht unnötig auf eine potenzielle User-Eingabe wartet, sollte der GRUB-Timer auf 0 Sekunden stehen. Dazu muss in /etc/default/grub die Option GRUB_TIMEOUT=0 gesetzt und update-grub ausgeführt werden.

Salt installieren

Da Salt in der aktuellen Fassung noch nicht in den Debian-Repositories vorliegt, ist zunächst der Import der Paketquelle samt zugehörigem Schlüssel erforderlich:

~/etc/apt/sources.list (für Debian 7.8 (wheezy)):

deb http://debian.saltstack.com/debian wheezy-saltstack main

Der Schlüssel wird importiert mit wget -q -O- "http://debian.saltstack.com/debian-salt-team-joehealy.gpg.key" | apt-key add -.

Erst jetzt lässt sich der Salt Minion mit aptitude update install salt-minion installieren. Für Tests reicht es aus, wenn der Minion Masterless läuft. Dazu muss in /etc/salt/minion die Option file_client: auf local stehen.

Um in der später zu erstellenden VM zu testende YAML-Skripte nicht umständlich kopieren zu müssen, kann man sich mit einer passenden Verzeichnissynchronisierung behelfen. Die Skripte können auf dem Host bspw. im Verzeichnis roots liegen. Die Zeile

config.vm.synced_folder "roots/", "/srv/"

hängt dieses Verzeichnis dann in der VM unter /srv ein.

Die nachfolgende Konfigurationsdatei unterbindet zudem die Installation des Salt Minions durch Vagrant und löst zudem ein salt state.highstate aus.

Vagrant.configure("2") do |config|
    config.vm.box = "precise64"

    ## For masterless, mount your salt file root
    config.vm.synced_folder "roots/", "/srv/"

    ## Use all the defaults:
    config.vm.provision :salt do |salt|
      salt.no_minion = true
      salt.run_highstate = true
    end
  end

Packen der Box

Ist alles installiert, kann die Box gepackt werden:

vagrant package --base my-virtual-machine

my-virtual-machine ist hier der Name, der bei der Installation der Base Box in VirtualBox gewählt wurde. Es sollte jetzt eine .box-Datei im aktuellen Verzeichnis liegen. Vagrant Boxdateien sind gzip-tar-Archive und können bei Bedarf mit den üblichen Werkzeugen aus- und wieder verpackt werden. Die Datei Vagrantfile wird automatisch mit der korrekten MAC-Adresse generiert.

Testen der Box

Bevor die eigene Base Box getestet werden kann, muss sie zunächst dem Host bekannt gemacht werden: vagrant box add debian ./debian-base.box. Im anschließend erstellen Arbeitsverzeichnis erzeugt ein vagrant init die Konfigurationsdatei Vagrantfile, in der noch der Name der Box anzupassen ist: config.vm.box = "debian".

Möglicherweise kommt es zu einem Warnhinweis, wenn eine Differenz zwischen der Host-VirtualBox-Version und der Gast-Erweiterungsversion besteht. Host 4.2 und Gast 4.1.8 funktioniert aber bisher problemlos.

Ab Vagrant 1.5 können Boxen intern versioniert werden. Bei älteren Versionen bietet sich für Bbase-Boxen eine Versionsangabe im Dateinamen an: debian-base-7.8-1.box mit 7.8: Debian-Version (wheezy), -1: Box-Version.

Workflow-Beispiel: Testen von Salt States

Zunächst ein Hinweis: vagrant init erzeugt bei der Initialisierung nur ein noch zu bearbeitendes Vagrantfile. Wenn diese Datei schon vorliegt, kann init übersprungen und eine schon vorbereitete Datei verwendet werden.

Ziel dieses Beispiels ist, Salt States auf Basis der eben eingerichteten Base Box zu testen. Dazu sind folgende Schritte notwendig:

  1. Base Box importieren: vagrant box add debian /path/to/debian-base.box holen
  2. Vagrantfile vorbereiten und ins Arbeitsverzeichns kopieren
  3. Salt-Dateien erstellen (kann auch später erfolgen) und kopieren
  4. VM starten und betreten

Der Import sollte problemlos funktionieren. In der vorzubereitenden Konfigurationsdatei muss der passende Box-Name stehen:

<Vagrantfile.debian>=

  Vagrant.configure("2") do |config|
    config.vm.box = "debian"
    # Create a forwarded port mapping which allows access to a specific port
    # within the machine from a port on the host machine. In the example below,
    # accessing "localhost:8080" will access port 80 on the guest machine.
    # config.vm.network :forwarded_port, guest: 80, host: 8080
  
    # Create a private network, which allows host-only access to the machine
    # using a specific IP.
    # config.vm.network :private_network, ip: "192.168.33.10"
  
    # Create a public network, which generally matched to bridged network.
    # Bridged networks make the machine appear as another physical device on
    # your network.
    # config.vm.network :public_network
  
    # Provider-specific configuration so you can fine-tune various
    # backing providers for Vagrant. These expose provider-specific options.
    # Example for VirtualBox:
    #
    # config.vm.provider :virtualbox do |vb|
    #   # Don't boot with headless mode
    #   vb.gui = true
    #
    #   # Use VBoxManage to customize the VM. For example to change memory:
    #   vb.customize ["modifyvm", :id, "--memory", "1024"]
    # end
    #
    # View the documentation for the provider you're using for more
    # information on available options.
  

Hilfreich ist auch das Mapping des roots-Verzeichnisses:

<Vagrantfile.debian 2>=

    # map folders
    config.vm.synced_folder "roots/", "/srv/"
  

Für das Testen von Salt States bietet Vagrant mit config.vm.provision die Möglichkeit, direkt Einfluss Chef, Puppet, Salt etc. zu nehmen. Im Beispiel wird Vagrant angewiesen, keinen Salt Minion zu installieren (ist schon vorhanden) und beim ersten Start der VM ein salt state.highstate auszuführen.

<Vagrantfile.debian 3>=

    config.vm.provision :salt do |salt|
      #salt.minion_config = "salt/minion"
      salt.no_minion = true
      salt.run_highstate = true
    end
  end

Die Salt States müssen nicht sofort vorliegen, es reichen auch die folgenden leeren top.sls-Dateien (Salt wird dazu allerdings eine Fehlermeldung ausgeben):

<roots/salt/top.sls>=

  # top.sls
  base:
    '*':
  

<roots/pillar/top.sls>=

  # top.sls
  base:
    '*':
  

Der Start der VM erfolgt wie schon beschrieben mit vagrant up. Mit vagrant ssh kann die laufende VM betreten und mit Salt getestet werden. Da der Salt Minion Masterless (s.o.) arbeitet, muss beim Aufruf der States darauf geachtet werden, dass der Befel salt-call --local state.highstate lautet.

Sämtliche Arbeitsschritte sind im Skript setup.sh zusammengefasst. Ggf. muss die Variable PATH_TO_BASE_BOX angepasst werden.

<setup.sh>=

  #!/bin/bash
  
  PATH_TO_BASE_BOX="/mnt/data/mtessmer/debian-base-7.8-1.box"
  BOX_NAME=debian
  
  [ -d ${BOX_NAME} ] || mkdir ${BOX_NAME}
  cp -R roots ${BOX_NAME}/
  
  cd ${BOX_NAME}
  
  BOX_FOUND=$(vagrant box list | grep debian)
  [[ -z ${BOX_FOUND} ]] && vagrant box add ${BOX_NAME} ${PATH_TO_BASE_BOX}
  
  cp ../Vagrantfile.debian Vagrantfile
  
  vagrant up
  vagrant ssh
  

Im Verzeichnis code befinden sich nach dem tangle-Laufe nun folgende Dateien und Verzeichnisse:

  code
  ├── roots
  │   ├── pillar
  │   │   └── top.sls
  │   └── salt
  │       └── top.sls
  ├── setup.sh
  ├── test-setup.sh
  ├── Vagrantfile.debian
  └── vagrant.pub

Mit ./setup.sh erhält man ein Unterverzeichnis debian mit einer komplett eingerichteten und laufenden VM, in der nach Belieben Salt States getestet werden können.

Fazit

Mit den hier vorgestellten Skripten reduziert sich das Aufsetzen einer VM zum Testen auf einen einzigen Befehl, dessen Ausführung auf einer Mittelklasse-Maschine ca. 1 Minute in Anspruch nimmt. Ein weiterer Vorteil besteht in der Portabilität dieses Ansatzes: Die Entwicklungsumgebung kann jederzeit auf anderen Maschinen repliziert werden.


<build-script>=

  #!/bin/sh
  if [ -z "${NOWEB_SOURCE}" ]; then
          NOWEB_SOURCE=literate_vagrant.nw
  fi
  if [ -z "${NOWEB_CODE}" ]; then
          NOWEB_CODE=`pwd`/code
  fi
  
  # check if we need to create target dirs
  [ -d ${NOWEB_CODE} ] || mkdir -p ${NOWEB_CODE}
  [ -d ${NOWEB_CODE}/roots/salt ] || mkdir -p ${NOWEB_CODE}/roots/salt
  [ -d ${NOWEB_CODE}/roots/pillar ] || mkdir -p ${NOWEB_CODE}/roots/pillar
  
  FILES="test-setup.sh Vagrantfile.debian vagrant.pub setup.sh
  roots/salt/top.sls roots/pillar/top.sls"
  
  for f in ${FILES}; do
          tangle -R"$f" "${NOWEB_SOURCE}" > "${NOWEB_CODE}/$f"
  done
  chmod u+x "${NOWEB_CODE}/setup.sh"
  

Code Chunks

Aktuelles

ipmi-telegraf

2017-02-09

ipmi-telegraf: IPMI-Skript für Telegraf-exec-Plugin veröffentlicht.

blockdiag-Filter für pandoc

2016-10-28

Die Version 0.1.0 des pandoc-Filters für blockdiag-ASCII-Bilder wurde veröffentlicht.

Update nw2md2ctags auf v0.1.3

2015-04-21

Das Werkzeug nw2md2ctags wurde auf die Version 0.1.3 aktualisiert.

Filter für die Verwendung von ASCII-Art mit pandoc

2015-04-08

Der pandoc_aafigure_filter ermöglicht die Verwendung von ASCII-Art-Bildern in pandoc-Dokumenten und generiert automatisch die entsprechenden Bilder.