Prof. Dr.-Ing. Oliver Radfelder
Informatik / Wirtschaftsinformatik
Hochschule Bremerhaven

VM und darin Docker installieren und verwalten

In der Informatik-Infrastruktur haben wir eine Docker-basierte Umgebung, die Ihr vom ersten Semester an benutzt, um dort in einer isolierten Umgebung Web-Anwendungen zu entwickeln (docker).

Im dritten Semester untersuchen wir in dem Modul Vernetzte Systeme mit welchen Techniken und Werkzeugen skalierbare, redundante und separierte Systeme aufgebaut werden. Das wird üblicherweise in virtuellen Maschinen und Containern auf Servern in Rechenzentren - in der Cloud - durchgeführt.

Hier wollen wir Euch zeigen, wie Ihr auf Eurem Laptop eine kleine Umgebung mit docker aufbauen könnt, die derjenigen in der Infrastruktur ähnelt und mit der Ihr Vernetzung und Verteilung üben könnt und die Ihr mit in Euer Berufsleben nehmen könnt.

Dazu müsst Ihr die Umgebung so aufbauen, wie es unter setup.html, wezterm.html und hopper.html beschrieben ist.

Zudem muss nun unter Windows noch die WSL2 mit Ubuntu installiert sein und unter MacOS/ARM utm und darin Ubuntu/Server installiert sein.

Alternativ für MacOS und Linux probieren wir gerade lima (Linux Machine) aus (siehe unten).

Sorgt in jedem Fall dafür, dass Ihr eine aktuelle Ubuntu (ab 22.04) oder Debian-Distribution laufen habt und dass Ihr dort mit ssh hineinkommt.

Unter Windows:

Folgt der Anleitung unter Microsoft/wsl/install. Sorgt zuvor dafür, dass Eure Windows-Version auf dem aktuellen Stand ist.

Nach der Installation solltet Ihr noch dafür sorgen, dass Ihr schnell mit ssh ubuntu innerhalb des Terminals in Eure Ubuntu-Installation kommt. Startet dazu die wsl aus der Powershell heraus, installiert erst einmal die minimale Software (openssh-server, vim, curl) und sorgt dafür, dass der ssh-Server automatisch gestartet wird.

wsl
sudo apt update
sudo apt install -y openssh-server vim curl
sudo vim /etc/ssh/sshd_config
# passe dort die Einträge an
Port 2222
#ListenAddress 0.0.0.0
#PasswordAuthentication yes
sudo systemctl enable ssh
sudo systemctl restart ssh
      

Da wir nicht nur mal eben in die Linux-Umgebung hineinwollen, sondern sie eine ständig verfügbare Arbeitsumgebung sein soll, müssen wir noch dafür sorgen, dass sie sich nicht wieder abschaltet, wenn wir mal nicht im Terminal drin sind. Innerhalb der WSL gebt dafür an:

dbus-launch true

Und wenn sie automatisch beim Windowsstart mit hochgefahren werden soll, legt eine Datei runwsl.bat im Autostart-Ordner unter Windows an mit dem Inhalt:

wsl --exec dbus-launch true

Unter MacOS/utm

Für Mac-Systeme installiert utm als Virtualisieungssoftware wie unter https://mac.getutm.app/ beschrieben.

Nach der Installation von utm solltet Ihr darin Ubuntu 22.04 installieren (guides/ubuntu). Ich empfehle die Server-Variante. Achtet darauf, genügend Speicher zur Verfügung zu stellen (wenn möglich 32GB).

Unter Linux

Unter Linux könnt Ihr docker direkt installieren. Unter Windows und MacOS muss docker in einer Linux-VM installiert sein. Ihr könnt natürlich, wenn Ihr Euch herausfordern wollt, auch unter Linux eine Linux-VM mit kvm installieren und dort dann docker installieren.

Lima (Linux Machine)

Kürzlich habe ich lima kennengelernt - obwohl es schon ein länger existierendes Projekt ist. lima wirkt ausgesprochen leichtgewichtig und ist schnell mal eben installiert. Zudem gibt es lima für Linux und MacOS. Zur Zeit erprobe ich das für mich selbst und bin ziemlich beeindruckt. Bevor ich das allerdings in die Breite trage, möchte ich das noch eine Zeit untersuchen.

Sowohl unter MacOS als auch unter Linux (debian/ubuntu/) ging es bei mir nach der Anleitung unter https://lima-vm.io/docs/installation/ unter dem Abschnitt Binary

Für MacOS mit brew installiert es so wie es da steht.

Für Linux statt brew install jq dann einfach sudo apt install jq (was vermutlich schon passiert ist). Die beiden anderen Zeilen mit curl funktionieren dann auch. Lediglich vor dem tar muss ebenfalls sudo stehen. Danach dann limactl start und dann lima und man ist drin. Selbst ssh ist dann vorbereit (der Port wird ausgegeben (60022) und es müssten dann m.E. nach nur noch Einträge in der .ssh/config nachgezogen werden).

Falls angemerkt wird, dass noch ein Paket fehlt, ist es vermutlich qemu

sudo apt install qemu-system qemu-utils

Etwas ungewöhnlich ist, dass man mit dem Kommando lima in dem Verzeichnis auch innerhalb der VM ist, in dem das Kommando aufgerufen wurde. Mit cd kommt man dann wie gewöhnlich in das VM-spezifische Homeverzeichnis. Wenn Ihr hingegen mit ssh in die VM geht, ist das aktuelle Verzeichnis direkt das VM-Homeverzeichnis.

Bei meinem Lenovo X260 debian Notebook musste ich noch dafür sorgen, dass die Virtualisierung insgesamt aktiviert wird. Das stellt man im BIOS ein (bei mir: F1 beim Booten drücken und dann in den Menüs Virtualisierung suchen und aktivieren.

Mit:

grep --color vmx /proc/cpuinfo # intel
grep --color svm /proc/cpuinfo # amd
seht Ihr dann, ob Hardware-Virtualisierung aktiviert ist. (Quelle: cyberciti.biz)

Auf einem meiner Systeme (debian) musste ich mich noch zur Gruppe kvm hinzufügen (sudo usermod -aG kvm ...) und beim Start die Konfiguration so anpassen, dass unter firmware der Parameter legacyBIOS auf true steht (kvm-permission-denied).

Für alle

Sobald Ihr mit ssh in Eure Linux-Umgebung kommt, sorgt zunächst dafür, dass sie auf dem aktuellen Stand ist:

sudo apt update && sudo apt -y upgrade

Dann solltet Ihr dringend mit:

sudo update-alternatives --set editor /usr/bin/vim.basic
dafür sorgen, dass Ihr nicht im falschen Moment im nano landet und dann vielleicht nicht wisst, wie Ihr dort wieder herauskommt ...

Ich tendiere dazu, unter allen Systemen als Standard en_US.UTF-8 einzutragen, da ansonsten einige Programme (date, bc, ...) sich aufgrund der Lokalisierung anders verhalten.

sudo sed  -i "s/^# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g" /etc/locale.gen && \
sudo locale-gen en_US.UTF-8 && \
sudo update-locale LANG=en_US.UTF-8

Wenn Ihr genug Platz habt in der VM solltet Ihr Euch auch dort wieder unser Standard-Setup installieren - bzw. eine Variante ohne die grafischen Anwendungen - wir wollen ja im Server arbeiten. Dieses Mal nur als Liste für eine hopper-ähnliche Umgebung - jeweils einzeln oder alle zusammen könnt Ihr die Software mit sudo apt -y install selbständig hinzufügen:

a2ps apache2 apache2-utils bash-builtins bash-completion
bat bc bsdmainutils build-essential coreutils csvkit curl direnv dos2unix
ed emacs-nox ffmpeg fonts-liberation git gnuplot-nox
gpg graphviz html2text imagemagick inkscape
inotify-tools iperf3 iproute2 iputils-ping
jq jid libxml2-utils maven moreutils mutt ncat
net-tools nftables nmap openjdk-17-jdk openjdk-17-doc openjdk-17-source openssh-server
pdf2svg pdftk plantuml poppler-utils procps pv pwgen python-is-python3 python3-pygments
qrencode redis-server restic shellcheck
shfmt socat sqlite3 sshfs tcpdump
tidy tree unzip valgrind vim w3m wrk websocketd
wget wrk xml2 xmlstarlet xxd xsltproc
zbar-tools
Insgesamt ist dann mit den noch zu installierenden docker und nodejs in der VM etwa 10 GB für das System verbraucht. Wenn es bei Euch eng ist, sprecht mit uns, was Ihr weglassen könnt.

Denkt unter Ubuntu und Debian daran, dass Ihr auch hier einen Softlink für bat setzt:

sudo ln -s /usr/bin/batcat /usr/local/bin/bat

Unter Ubuntu gibt es im Moment noch kein openjdk-21 - von daher bleiben wir hier erst einmal auf 17.

Da wir in den docker-Containern auch einen Webserver auf Port 80 installieren, solltet Ihr baldmöglich den installierten apache2 deaktivieren.

sudo systemctl stop apache2
sudo systemctl disable apache2

Für diejenigen, die Linux direkt installiert haben (und nicht in einer VM): Ihr braucht nicht per ssh auf Euren Rechner zu kommen und solltet das auch vorerst abschalten:

sudo systemctl stop ssh
sudo systemctl disable ssh

Zudem ist vermutlich nftables bei Euch als Firewall eingerichtet. Die solltet Ihr auch gleich so einrichten, dass erst einmal Euer Rechner nach außen hin abgesichert ist. Prüft zuerst, ob nftables installiert und aktiviert ist:

sudo systemctl status nftables

Falls dort inactive angzeigt wird, sollte es mit

sudo systemctl enable nftables
sudo systemctl start nftables

aktiviert und gestartet werden. Gegebenenfalls muss dann auch der docker-Daemon einmal mit

sudo systemctl restart docker
neu gestartet werden, damit er seine Regeln dort wieder hineinschreiben kann. Nach dem nächsten Systemstart ist das nicht mehr notwendig.

Die unterschiedlichen Distributionen benutzen nun unterschiedliche Frontends für nftables oder gar andere Firewall-Systeme wie ufw. Mein Vorschlag wäre, direkt auf nftables zu setzen.

Bisweilen ist es notwendig, die lokale Zeitzone einzustellen:

sudo timedatectl set-timezone "Europe/Berlin"

Danach installiert docker nach der Anleitung auf Install Docker Engine on Debian bzw. Install Docker Engine on Ubuntu jeweils unter dem Abschnitt Install using the apt repository.

Sorgt dann dafür, dass Euer Standarduser, mit dem Ihr in die WSL oder VM kommt, Mitglied der Gruppe docker ist, damit Ihr nicht jedesmal sudo vor die docker-Befehle schreiben müsst.

sudo usermod -aG docker $USER

Damit Ihr dann für die aktuelle Sitzung auch in der Gruppe seid:

newgrp docker

Nach dem nächsten Einloggen seid Ihr dann automatisch in der Gruppe.

Auf keinen Fall installiert Euch irgendeine docker for ...-Variante.

Es mag einfacher erscheinen, mit dem grafischen Werkzeug zu arbeiten, bei dem die konkrete Arbeit wegabstrahiert wird. Hier geht es aber nur zum Teil um docker als solches, sondern vornehmlich um docker als Werkzeug, um auf Euren Notebooks eine Netzwerkumgebung einzurichten, wie sie dann in realen Umgebungen aus vernetzten Rechnern besteht.

Und natürlich könnt Ihr, wenn erst einmal VM und docker soweit eingerichtet sind, auch alle 'klassischen' docker-Dinge tun.

Upgrade auf Ubuntu 23.04 und 23.10

Sowohl unter Windows/WSL2 als auch in UTM/Ubuntu wird zunächst die derzeitige LTS (Long Term Support) Version 22.04 installiert. Von dieser lässt sich mit den folgenden Schritten auf Version 23.04 upgraden:

sudo apt update
sudo apt upgrade -y
sudo apt dist-upgrade -y
sudo apt install update-manager-core -y
sudo sed -i 's/lts/normal/g' /etc/update-manager/release-upgrades
sudo sed -i 's/jammy/lunar/g' /etc/apt/sources.list
sudo apt update
sudo apt upgrade -y
sudo apt dist-upgrade -y
sudo reboot 
# bzw. unter Windows in der git-bash: 
#   wsl shutdown 
#   wsl bash -i -c "nohup sleep 3600 &>/tmp/sleep.log &"
      

Dementsprechend kann nun auch das jdk-17 deinstalliert und jdk-21 installiert werden.

sudo apt purge openjdk-17-jdk openjdk-17-doc openjdk-17-source
sudo apt install -y openjdk-21-jdk openjdk-21-doc openjdk-21-source
sudo apt autoremove -y

Erst im nächsten Schritt lässt sich dann auf 23.10 upgraden, was sicher auch getan werden sollte, da im Januar 2024 die Version 23.04 ihr End of Life erfuhr:

sudo do-release-upgrade 

node.js in der VM installieren

Es gibt sehr unterschiedliche Arbeitsweisen mit docker und je nachdem, wie es praktiziert wird und in welcher Entwicklungswelt wir unterwegs sind, wird auch unterschiedliches in der VM selbst benötigt. Wir machen unterwegs einen kleinen Ausflug in die typische Entwicklung mit Javascript/Node und dort ist es üblich, dass eine aktuelle node-Umgebung zum Arbeiten in der VM bzw. dem umgebenden Linux installiert ist und dort entwickelt wird. Daher ist es wichtig, hier eine passende node-Version zu installieren. Macht das bitte unbedingt nach dem aktuell empfohlen Verfahren, wie es im unten stehenden Link beschrieben ist, und folgt nicht irgendwelchen veralteten Webseiten!

Auf der Seite https://github.com/nodesource/distributions findet Ihr den Weg - ähnlich wie bei docker - ein externes Repository in die eigene Paketverwaltung mit aufzunehmen. Das sind immer die drei Schritte:

Arbeiten mit node/npm unter Linux

Ihr werdet recht oft aufgefordert werden, mit dem Paketmanager irgendetwas global zu installieren und benötigt dann dafür sudo-Rechte. Das ist aber nicht immer vernünftig. Auch wenn es keine perfekte Lösung ist, scheint das Umbiegen des globalen Installationsverzeichnisses auf ein HOME-lokales der bessere Weg zu sein.

mkdir "${HOME}/.npm-packages"
npm config set prefix "${HOME}/.npm-packages"

Dann sollte die .bashrc mit den folgenden Zeilen ergänzt werden:

NPM_PACKAGES="${HOME}/.npm-packages"
export PATH="$PATH:$NPM_PACKAGES/bin"
export MANPATH="${MANPATH-$(manpath)}:$NPM_PACKAGES/share/man"

Damit wird dafür gesorgt, dass dann auch vermeintlich global installierte Pakete im Pfad gefunden werden und Binaries ebenfalls. Mit npm config list kann dann ab dem nächsten Einloggen auf die aktuelle Konfiguration zugegriffen werden und mit npm list -g die installierten globalen Pakete aufgelistet werden. Dependency-Management in der Javascript-Welt ist nicht so richtig rund gelöst. Zu npm kommen noch npx, nvm und yarn und manches andere dazu.