Dieser Text dokumentiert die Bereitstellung einer aktuellen JShell mittels Docker und kombiniert das mit einigen grundsätzlichen Infos zu Docker. Der konkrete Anwendungsfall ist, die aktuelle JShell in der CloudShell von Google verwenden zu können. Wenn man bereit ist, sich auf Google als Dienstleister einzulassen, steht einem über die CloudShell kostenfrei ein Linux-Rechner zur Verfügung (→ Kurzes Video zur Einrichtung), wo Docker, etliche Cloud-Werkzeuge und Theia als Entwicklungsoberfläche vorinstalliert sind.
Docker kapselt Prozesse in sogenannten Containern, die als gewöhnliche Prozesse im Kernel des Gast-Systems laufen. Ein Container ist keine virtuelle Maschine und verschwendet deswegen auch keine Ressourcen. (Mahn, 2021, S. 147)
Container sehen weder andere Prozesse noch ein Dateisystem. Sie werden mit einem virtuellen Dateisystem ausgestattet (und zwar in Form einer tar
-Datei), das als Image bezeichnet wird. Zudem können Zugriffe auf virtuelle Hardware-Komponenten (z.B. Netzkarte) eingerichtet werden. Solche, vom Image abweichenden Konfigurationen, können mit Hilfe eines Dockerfiles vorgenommen werden. Ein Docker Daemon, auch Docker-Host, verwaltet die Container zur Laufzeit. (S. 147 f.).
Da ein Container nur genau einen Prozess ausführt, sind mehrere Container mittels Docker Compose (docker compose
bzw. docker-compose
) zusammenstellbar. Mit einer YAML-Datei, standardmäßig docker-compose.yaml
, konfiguriert man die Container und ihre Einstellungen. Üblich ist es, die YAML-Dateien für die verschiedensten Zusammenstellungen in separaten Verzeichnissen einzupflegen. (S. 152)
Der Docker Hub bietet vorbereitete Images an. Vorsicht ist bei der Auswahl der Images geboten, da jeder dort Images bereitstellen kann. Offizielle Images sind gekennzeichnet, wie z.B. das OpenJDK-Image. (S. 148 f.)
Mit docker pull
zieht man sich ein Image, hier das offizielle OpenJDK-Image. Hinter dem Namen openjdk
folgt optional ein Doppelpunkt mit einem Tag, das in dem Fall die Version kennzeichnet.
docker pull openjdk:17
Der Befehl docker run
startet einen Container mit einem Image (→ Befehlsübersicht):
docker run --rm -it -v $(pwd):$HOME openjdk:17-jdk /bin/jshell -R-ea
Die Optionen bedeuten Folgendes:
-it
ist notwendig für interaktive Prozesse wie eine Shell; die Kurzform steht für-i -t
:-i
hält STDIN für Eingaben offen-t
stellt ein Terminal bereit
-v
bindet einVOLUME
, einen Datenträger ein; hier ist es das Heimverzeichnis$(pwd):$HOME
. Auf diese Weise teilen sich das Gastsystem und der Container Verzeichnisse und Dateien zum gemeinschaftlichen Zugriff--rm
entfernt (remove) den Container, wenn der Prozess endet
Mit -w
bzw. --workdir
(auch als WORKDIR
in einem Dockerfile) kann man statt des Wurzelverzeichnisses ein Arbeitsverzeichnis setzen.
Mit -u=
bzw. --user=
(USER
) können der Username, die UserId und die Usergruppe gesetzt werden.
Statt sogleich die JShell zu starten, ist es klüger, eine "normale" Shell aufzurufen, von der aus die JShell aufgerufen und beeendet werden kann. Beendet man die bash
-Shell mit einem exit
, sorgt das --rm
dafür, dass in Folge auch der Container mit diesem Ausstieg beendet wird.
docker run --rm -it -v $(pwd):$HOME openjdk:17-jdk /bin/bash
Man kann diesen Befehl auch sehr gut als Bash-Script in eine Datei z.B. namens jshell.sh
packen:
#!/bin/bash
docker run --rm -it -v $(pwd):$HOME openjdk:17-jdk /bin/bash
Übrigens lädt der Befehl das Image selbsttätig aus dem Internet nach, wenn es lokal nicht (mehr) vorhanden sein sollte.
Die Container, die ja Prozesse sind, werden mit docker ps
aufgelistet (→ Befehlsübersicht)
docker ps -a
-a
bzw.--all
zeigt alle Container an; in der Grundeinstellung werden nur die aktiven angezeigt
Einen aktiven Container kann man mit dem Befehl docker stop
(→ Befehlsübersicht) anhalten und mit docker rm
(→ Befehlsübersicht) entfernen. Man kann nur nicht aktive Container entfernen. Als Argument gibt man den Container-Namen oder die Container-ID an. Beispiele:
docker rm competent_haslett
docker stop beautiful_hellman
In Googles CloudShell läuft der Docker Daemon (Docker Host) standardmäßig. Er lässt sich stoppen (dann kann z.B. docker run
nicht mehr ausgeführt werden) und wieder starten.
sudo service docker stop
sudo service docker start
Die Übersicht über den Status der verschiedensten Services weist laufende Dienste mit einem [ + ]
aus, angehaltene mit einem [ - ]
und Dienste, die keinen Status-Befehl unterstützen, mit einem [ ? ]
.
service --status-all
Quellen
Mahn, Jan (2021). Zu neuen Ufern. Nach dem Hype: Docker verstehen und loslegen, c't, Nr. 24, Hannover: Heise Medien, S. 146-152
Bei meinen ersten Docker-Gehversuchen haben mich die Studierenden Lars Wächter, René Gentzen und Ahmet Cetin mit ihren Hilfestellungen unterstützt. Vielen Dank!