Ziel: Du kannst mit Vagrant eine reproduzierbare Multi-VM-Umgebung (mehrere Nodes) definieren, starten, vernetzen und verwalten – als Praxis-Setup für verteilte Systeme.
| Begriff | Kurz erklärt |
|---|---|
| Vagrant | Tool, um VM-Umgebungen als Code zu definieren (Vagrantfile) und reproduzierbar zu starten. |
| VM (Virtual Machine) | Komplettes virtuelles Betriebssystem (Kernel + Userspace) auf einem Host. |
| Provider | VM-Backend, z.B. VirtualBox, VMware, Hyper-V (je nach System). |
| Box | Vorgefertigtes VM-Image (Basis-OS), z.B. Ubuntu. |
| Provisioning | Automatische Konfiguration nach dem Boot: Pakete installieren, Services konfigurieren, Dateien kopieren… |
| Multi-Node | Mehrere VMs als „Cluster“ (z.B. db/api/proxy) inkl. Netzwerk. |
In verteilten Systemen geht es selten nur um „einen Dienst auf einem Rechner“. Typische Themen sind:
Vagrant liefert dir genau das: ein Vagrantfile → ein Befehl → identische Multi-VM-Umgebung.
Merke: Container sind „leicht“ und schnell – aber manchmal brauchst du das volle OS: systemd, Kernel-nahe Tools, realistische Netzwerkkonfiguration, Legacy-Stacks. Dafür sind VMs top.
Vagrant ist im Kern ein Orchestrator um diese Teile:
# im Projektordner vagrant init # Vagrantfile erstellen (Basis) vagrant up # VMs starten/erstellen vagrant status # Status ansehen vagrant ssh <name> # in eine bestimmte VM einloggen vagrant halt # sauber herunterfahren vagrant reload # Neustart (Konfigänderungen übernehmen) vagrant provision # Provisioning erneut ausführen vagrant destroy -f # VMs löschen (Achtung: Daten weg)
Typischer Fehler: Änderungen am Vagrantfile werden oft erst nach reload oder destroy/up vollständig wirksam (je nach Änderung).
In Multi-Node Labs sind diese Netzwerkarten zentral:
Beispiel:
config.vm.network "forwarded_port", guest: 80, host: 8080
Beispiel:
config.vm.network "private_network", ip: "192.168.56.11"
Didaktik-Tipp: Für verteilte Systeme ist ein Private Network mit fixen IPs am besten: reproduzierbar, einfach zu debuggen, klare Topologie.
Die Idee:
# Vagrantfile Vagrant.configure("2") do |config| config.vm.box = "ubuntu/jammy64" # Gemeinsame Defaults config.vm.provider "virtualbox" do |vb| vb.cpus = 2 vb.memory = 2048 end # --- db node --- config.vm.define "db" do |db| db.vm.hostname = "db" db.vm.network "private_network", ip: "192.168.56.11" # Optional: DB nach aussen testbar machen (nur falls nötig) # db.vm.network "forwarded_port", guest: 5432, host: 15432 end # --- api node --- config.vm.define "api" do |api| api.vm.hostname = "api" api.vm.network "private_network", ip: "192.168.56.12" # api.vm.network "forwarded_port", guest: 8000, host: 18000 end # --- proxy node --- config.vm.define "proxy" do |proxy| proxy.vm.hostname = "proxy" proxy.vm.network "private_network", ip: "192.168.56.13" # Reverse proxy nach aussen proxy.vm.network "forwarded_port", guest: 80, host: 8080 end end
vagrant up # in die proxy VM vagrant ssh proxy ip a ping -c 2 192.168.56.12 # api ping -c 2 192.168.56.11 # db
Standardmässig wird der Projektordner oft nach `/vagrant` gemountet.
vagrant ssh api ls -la /vagrant
Das ist praktisch, wenn du z.B. „api-code“ auf dem Host bearbeitest, aber in der VM laufen lässt.
Synced Folders können je nach OS/Provider Performance kosten. Für grosse Projekte: bewusst einsetzen.
Wenn „verteiltes System“ nicht funktioniert, geh systematisch vor:
| Ebene | Check |
|---|---|
| DNS/Hosts | Können die Nodes Namen auflösen? (oder IPs nutzen) |
| Routing/Netz | Ping / traceroute / `ip a`, `ip r` |
| Port offen? | `ss -tulpn`, `nc -vz <ip> <port>` |
| Firewall | `ufw status`, iptables/nftables |
| Service läuft? | `systemctl status <service>`, Logs |
Beispiel:
# von api -> db Port testen nc -vz 192.168.56.11 5432 # offene Ports ansehen ss -tulpn # systemd Service prüfen systemctl status nginx --no-pager journalctl -u nginx -n 50 --no-pager
Für Klassen: Lieber kleine VMs (1 CPU / 1024–2048 MB) und ein „Minimal-Cluster“ als zu viel auf einmal.