Labor-VM mit Vagrant erstellen
Die Verwendung von vorkonfigurierten virtuellen Maschinen (VMs) hat sich gerade für Laborveranstaltungen bewährt. Dadurch erhalten alle Teilnehmer eine identische Arbeitsumgebung für die Übungen, außerdem verringert sich der (technische) Betreuungsaufwand enorm.
Am Beispiel eines Datenbank-Labors (FIXME Link auf Git-Repo) wird hier gezeigt, wie man eine solche VM konfiguriert und größtenteils automatisch erzeugt. Am Ende steht eine OVA-Datei (open virtualization format), die dann an die Teilnehmer verteilt werden kann. Das Format ist herstellerübergreifend und kann somit in jede gängige Virtualisierungs-Software (z.B. VirtualBox, VmWare) importiert werden.
Vagrant
Vagrant ist eines von mehreren verfügbaren Werkzeugen zur Erzeugung von VMs. Die zentrale Konfiguration steht dabei in einem Vagrantfile.
Beispiel für Vagrantfile
vagrant-vm/Vagrantfile (Source)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# -*- mode: ruby -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" # cf. https://github.com/hashicorp/vagrant/issues/8878#issuecomment-345112810 class VagrantPlugins::ProviderVirtualBox::Action::Network def dhcp_server_matches_config?(dhcp_server, config) true end end Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define "moderne_dbs" do |moderne_dbs| moderne_dbs.vm.box = "debian/bullseye64" moderne_dbs.vm.network "private_network", type: "dhcp" moderne_dbs.vm.provider "virtualbox" do |vb| vb.memory = "2048" vb.name = "moderne_dbs" end moderne_dbs.vm.provision "shell", privileged: false do |s| s.path = "provision.sh" s.args = "moderne-dbs" end end if Vagrant.has_plugin?("vagrant-proxyconf") && ENV['http_proxy'] config.proxy.http = ENV['http_proxy'] config.proxy.https = ENV['https_proxy'] config.proxy.no_proxy = "localhost,127.0.0.1" end end |
Hier wird neben dem Namen und dem RAM der VM das Basis-Image (Debian-Bullseye) sowie die Netzwerkkonfiguration definiert.
Sobald die VM (mit vagrant up
) erstellt wird, wird das erste Shell-Skript (provision.sh) ausgeführt. Dieses übernimmt die erste Stufe der Konfiguration.
Shell-Skripte
provision
Das Skript erzeugt im Prinzip einen neuen Benutzer (student) und gibt diesem Administrator-Rechte (sudo). Außerdem wird die Anmeldung per SSH mit Paßwort aktiviert.
vagrant-vm/provision.sh (Source)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
set -x HOSTNAME=$1 export DEBIAN_FRONTEND=noninteractive sudo apt-get update sudo apt-get -y install gnupg curl unzip libuser net-tools # sudo für student ohne PW echo "student ALL=(ALL:ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/student if [[ -d "/vagrant" ]] then USERNAME=student PASSWORD=123456 : "Set hostname" && { sudo hostname $HOSTNAME echo $HOSTNAME | sudo tee /etc/hostname > /dev/null sudo sed -i "s/bullseye/$HOSTNAME/g" /etc/hosts } : "Create user student" && { sudo useradd -m -G sudo,vagrant -s /bin/bash $USERNAME echo -e "$PASSWORD\n$PASSWORD" | sudo passwd $USERNAME } : "Enable SSH password authentication" && { sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config sudo systemctl restart sshd.service } : "Run install" && { sudo -u $USERNAME bash /vagrant/install.sh } else bash /vagrant/install.sh fi |
Im Anschluß wird die zweite Phase der Konfiguration unter dem neuen Benutzerkonto gestartet.
install
vagrant-vm/install.sh (Source)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
export DEBIAN_FRONTEND=noninteractive cd $HOME HBASE_VERSION=2.4.9 HBASE_ARCHIVE=hbase-$HBASE_VERSION-bin.tar.gz # HBase sudo apt-get -y install default-jdk-headless wget -nv https://archive.apache.org/dist/hbase/$HBASE_VERSION/$HBASE_ARCHIVE tar xvf $HBASE_ARCHIVE rm $HBASE_ARCHIVE echo "export PATH=$PATH:$HOME/hbase-2.4.9/bin" >> ~/.profile echo "export JAVA_HOME=/usr/lib/jvm/default-java" >> ~/.profile # MongoDB wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - echo "deb https://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list sudo apt-get update sudo apt-get -y install mongodb-org # Neo4J wget -O - https://debian.neo4j.com/neotechnology.gpg.key | sudo apt-key add - echo 'deb https://debian.neo4j.com stable latest' | sudo tee -a /etc/apt/sources.list.d/neo4j.list sudo apt-get update sudo apt-get -y install neo4j # zwei Zeilen in /etc/neo4j/neo4j.conf aktivieren (cf. https://neo4j.com/docs/operations-manual/current/configuration/password-and-user-recovery/) # dbms.security.auth_enabled=false sudo sed -i "s/^#dbms.security.auth_enabled/dbms.security.auth_enabled/g" /etc/neo4j/neo4j.conf # dbms.default_listen_address=0.0.0.0 sudo sed -i "s/^#dbms.default_listen_address/dbms.default_listen_address/g" /etc/neo4j/neo4j.conf # Zugriffsrechte Import-Verzeichnis anpassen sudo chmod a+w /var/lib/neo4j/import # Postgres # cf. https://linuxhint.com/install-postgresql-debian/ sudo apt -y install postgresql postgresql-contrib sudo systemctl disable postgresql # externer Zugriff: # * in /etc/postgresql/13/main/pg_hba.conf allow echo 'host all all 0.0.0.0/0 md5' | sudo tee -a /etc/postgresql/13/main/pg_hba.conf # * /etc/postgresql/13/main/postgresql.conf listen sudo sed -i "s/^#listen_addresses.*$/listen_addresses = '*'/g" /etc/postgresql/13/main/postgresql.conf echo "CREATE USER student WITH PASSWORD '123456';" | sudo -i -u postgres psql echo "CREATE DATABASE student;" | sudo -i -u postgres psql echo "GRANT ALL PRIVILEGES ON DATABASE student TO student;" | sudo -i -u postgres psql sudo apt-get -y install redis sudo systemctl disable redis # cf. https://askubuntu.com/questions/217358/how-can-i-display-my-machines-ip-address-on-a-tty-login-screen cat << 'EOF' > /tmp/update-issue #!/bin/sh MSG=$(cat /etc/issue | grep -v IP) IP_ADDRESSES=$(/sbin/ifconfig | grep 'inet' | grep -v '127' |grep -v 'inet6'|awk '{ print $2 }' ) printf "%s\n" "$MSG" > /etc/issue for i in $IP_ADDRESSES; do printf "%s\n" "IP: $i" >> /etc/issue done; EOF sudo mv /tmp/update-issue /etc/network/if-up.d/ sudo chmod 0755 /etc/network/if-up.d/update-issue # Linuxlogo :-) sudo apt-get -y install linuxlogo echo "linuxlogo" >> ~/.profile # set locale sudo apt-get -y install locales sudo sed -i 's/^# *\(de_DE.UTF-8\)/\1/' /etc/locale.gen sudo locale-gen # set timezone sudo timedatectl set-timezone Europe/Berlin # (apt-)cache löschen sudo rm -rf /var/cache/* |
Makefile
Damit das OVA nicht manuell erzeugt werden kann, bietet sich die Automatisierung mittels make an.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
.SILENT: clean .DEFAULT_GOAL := all clean: rm dist/moderne-dbs.ova all: clean ova ova: mkdir -p dist vagrant destroy -f; \ vagrant up; \ vagrant halt vboxmanage sharedfolder remove moderne_dbs --name vagrant vboxmanage export moderne_dbs -o dist/moderne-dbs.ova |
Nun erzeugt ein einfacher Aufruf von make
die OVA-Datei im Unterverzeichnis dist
. Da die VM in diesem Format bereits komprimiert ist, kann diese nun direkt an die Teilnehmer verteilt werden.
Weitere Ideen/Ausblick
- Versionierung der VM und Anzeige beim Einloggen