21.2    Management von Images und Containern

21.2.1    Das Docker-CLI (Command Line Interface)

Das Kommandozeilentool docker ist bis auf Weiteres unser primäres Administrationstool. Werfen wir also einmal einen genaueren Blick darauf.

Aufbau und Dokumentation

Die vielen Möglichkeiten des docker-Kommandos werden durch Subkommandos erschlossen. Nach letzter Zählung sind es gut 50(!) Stück. Viele von ihnen haben dann noch mal Subkommandos. Die Offline-Dokumentation ist dabei jedenfalls recht gelungen. Jedes Subkommando kann mit --help aufgerufen werden; z. B.:

$ docker system      --help
$ docker system info --help

Und in der Regel gibt es auch jeweils noch mal Manpages mit teilweise etwas ausführlicheren Informationen:

$ man docker-system
$ man docker-system-info

Um etwas mehr Ordnung hineinzubringen, sind die Subkommandos in Version 1.13 teilweise neu strukturiert worden. Vor allem sind Container- und Image-spezifische Kommandos nun unterhalb von docker container bzw. docker image angesiedelt. Die »alte« Form steht in der Regel aber nach wie vor zur Verfügung:

# "Alt":
$ docker start […]
# "Neu":
$ docker container start […]

RESTful API

Der Docker-Client (docker) kommuniziert mit dem Docker-Service (dockerd) über eine HTTPRESTAPI. Das ist eine moderne Herangehensweise, die unter anderem folgende Vorteile hat:

Falls Sie sich für den zweiten Punkt interessieren: Das wäre relativ schnell eingerichtet, aber wenn Sie es »richtig« und sicher machen wollen, kommen Sie um SSL/TLS und eine eigene CA nicht herum; siehe https://docs.docker.com/engine/security/https/.

Wenn Sie ein geeignetes curl mit UNIX-Socket-Support installiert haben, können Sie die REST-API auch einmal exemplarisch testen:

$ curl -s --unix-socket /var/run/docker.sock http://localhost/images/json

# Etwas menschenlesbarer:
$ curl […] | jq

21.2.2    Erste Schritte

Jedes Mal, wenn Sie das Kommando docker run absetzen, erzeugen Sie damit einen neuen Container:

$ docker run hello-world
[…]
$ docker run hello-world
[…]

docker run ist dabei nur die Kurzform für das ausführlichere docker container run. Aus Gründen der Bequemlichkeit wird aber meistens die alte Form verwendet.

Schauen wir also einmal nach, wie es mit unseren Containern aussieht:

$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
43740d29e166 hello-world […] Exited naughty_northcutt
d4a488efcbd6 hello-world […] Exited mystifying_fermat
[…]

Die Option -a brauchen wir, um alle Container zu sehen, nicht nur die aktiven. Auch hier hätten wir alternative Kommandos mit identischer Wirkung zu Verfügung: docker container ps -a oder das kürzere docker ps -a.

Das zugrunde liegende Image gibt es natürlich nur einmal:

$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest f2a91732366c 4 months ago 1.85kB

docker images ist hier das alternative Kommando.

Docker erzeugt für jeden Container einen synthetischen, eindeutigen Namen. Diese Bezeichnungen sind zwar ziemlich witzig, aber wahrscheinlich wollen Sie doch eher eigene, definierte Namen haben. Dies gelingt mit der Option --name:

$ docker run --name hello1 hello-world
$ docker run --name hello2 hello-world

Wie schon erwähnt, sind Container nichts »Wertvolles«: Man erzeugt sie, lässt sie laufen und wirft sie wieder weg. Deswegen hat das run-Kommando sogar eine Option --rm. Damit wird der Container automatisch nach Beendigung wieder gelöscht:

$ docker run --rm hello-world

Untersuchen wir nun interessehalber noch, was das Kommando docker run unter der Haube alles tut. Es sind mehrere Schritte, und wir geben jeweils auch das Kommando an, um diese Schritte selbst einzeln zu tätigen.

  1. Zunächst wird geprüft, ob das gewünschte Image lokal schon in der gewünschten Version vorhanden ist. Wenn nicht, wird es vom Docker Hub (der voreingestellten Registry) heruntergeladen:

    $ docker image pull hello-world
  2. Nun wird ein Container erzeugt und auf den Start vorbereitet. Unter anderem bekommt er eine eindeutige ID und einen Namen. Wenn Sie diesen nicht selber wählen, vergibt Docker – wie schon erwähnt – synthetische Namen:

    $ docker container create --name hw hello-world
  3. Schließlich wird der Container gestartet. Um in unserem speziellen Fall die Standardausgabe sehen zu können, ist die Option -a nötig:

    $ docker container start -a hw

21.2.3    Löschen von Containern und Images

Einen Container löscht man mit dem container rm-Subkommando, wobei man seinen Namen oder seine ID angibt:

docker container rm [-f] <NAME_ODER_ID>

Die Option -f ist nötig, wenn Sie laufende Container löschen möchten.

Um alle vorhandenen Container zu löschen, lassen Sie sich zunächst mittels docker container ls -aq die Liste der IDs geben, und diese übergeben Sie dann per Kommandosubstitution direkt ans Löschkommando:

$ docker container rm -f $(docker container ls -aq)

Ein Image löscht man analog mit dem image rm-Subkommando:

docker image rm [-f] <NAME>

Und alle vorhandenen Images zu löschen ist dann auch nicht mehr schwer:

$ docker image rm -f $(docker image ls -q)

In einer reinen Testumgebung könnten Sie Aliasse zum Löschen aller Container bzw. Images anlegen, da die eigentlichen Kommandos ja doch etwas sperrig sind.

Statt einer Kommandosubstitution wäre eine Lösung mit xargs praktischer, weil Sie die Löschkommandos ja gar nicht starten möchten, wenn es keine Images bzw. Container gibt:

alias rm-all-containers='docker container ls -aq | xargs -r docker container rm -f'
alias rm-all-images='docker image ls -q | xargs -r docker image rm -f'

Listing 21.4    Ausschnitt aus der »~/.bashrc«: Aliasse zum Löschen aller Container bzw. Images

21.2.4    Handling von Containern

Interaktive Container

Am Beispiel eines BusyBox-Images wollen wir nun einmal den Umgang mit interaktiven Containern demonstrieren.

$ docker run -it --name bb busybox

Die Option -i ermöglicht die interaktive Bedienung bzw. hält STDIN offen. Mit der Option -t wird ein Pseudo-Terminal zugewiesen.

Wir befinden uns nun in einer BusyBox. Das ist eine minimale Linux-Umgebung, die meist im Embedded-Bereich anzutreffen ist:

/ # ls
bin dev etc home proc root sys tmp usr var
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 sh
8 root 0:00 ps -ef
/ # du -sh /
1.2M /
/ # exit

Durch das exit-Kommando haben wir den Hauptprozess des Containers beendet – und damit auch den Container selbst. Einen erneuten interaktiven Start desselben Containers erreichen Sie mit:

$ docker start -ai bb

Die Option -a verbindet STDOUT/STDERR, während -i nur STDIN verbindet.

Hätten Sie keinen eigenen Namen wie »bb« vergeben, so wäre der synthetische Name oder die Container-ID zu verwenden. Im letzteren Fall wäre auch eine Abkürzung möglich, die aber eindeutig sein muss.

Detach

Mit der Tastensequenz (Strg)+(P) (Strg)+(Q) können Sie sich von einen interaktiven Container lösen, ohne ihn beenden zu müssen:

/ # (Strg)+(P) (Strg)+(Q)

Damit sind wir wieder im Hostsystem, aber der Container läuft weiter. Falls Sie wieder interaktiv mit ihm arbeiten wollen, geben Sie Folgendes ein:

$ docker attach bb
[+]  Andere Container, andere Sitten

Bei manchen interaktiven Linux-Containern kann es schon mal sein, dass Sie nach dem attach noch eine Taste (z. B. (¢)) drücken müssen, damit die Eingabeaufforderung sichtbar wird!

Befehle »von außen«

Als Alternative zum interaktiven Arbeiten gibt es auch die Möglichkeit, mit docker [container] exec quasi »von außen« Befehle aufzurufen:

[+]  Alternative Shell

Ein docker exec kann damit auch eine Alternative zu docker attach sein – schließlich bekommen Sie via docker exec -it bb sh ja auch eine Shell, die Sie auf ganz gewöhnlichem Wege wieder verlassen können. Und wenn im Container andere Shells wie z. B. bash installiert sind, können Sie selbstverständlich auch diese starten.

Service-Container

Die meiste Zeit werden Sie wahrscheinlich Container betreiben, die einen Dienst anbieten wie beispielsweise Webserver oder Datenbankserver.

Diese sind in erster Linie nicht zum interaktiven Arbeiten gedacht und werden deswegen mit der Option -d zumeist im Detached Mode (also im Hintergrund) gestartet. Hier sehen Sie den Start am Beispiel eines Apache- und eines Redis-Containers:

$ docker run -d --name httpd httpd
$ docker run -d --name redis redis

Ein Start mit der Option -it wäre hier auch relativ nutzlos, da der Hauptprozess ja in diesen Fällen keine Shell ist. Da solche Container trotzdem in aller Regel auch eine Shell mit an Bord haben, können Sie sich jederzeit interaktiv wie folgt verbinden:

$ docker exec -it httpd bash

21.2.5    Prozessverwaltung

Mit dem Kommando docker [container] top können Sie die Prozesse eines Containers auflisten. Wir starten exemplarisch mal ein Alpine Linux und ein paar zusätzliche Prozesse darin:

$ docker run -itd --name a1 alpine

$ docker container exec -d a1 sleep 1000
$ docker container exec -d a1 sleep 2000

docker top zeigt die »echten« PIDs aus der Sicht des Hosts:

$ docker container top a1
UID PID PPID C STIME TTY TIME CMD
root 21108 21092 0 11:39 pts/0 00:00:00 /bin/sh
root 21149 21092 0 11:40 ? 00:00:00 sleep 1000
root 21171 21092 0 11:40 ? 00:00:00 sleep 2000

Hinter den Containernamen können Sie noch ps-Optionen wie z. B. -x anfügen.

Dank Kernel Namespaces hat der Container selbst aber eine andere Sicht der Dinge:

$ docker container exec a1 ps -ef
PID USER TIME COMMAND
1 root 0:00 /bin/sh
13 root 0:00 sleep 1000
17 root 0:00 sleep 2000
37 root 0:00 ps -ef

Für das Beenden von Prozessen haben Sie nun die Wahl, die PIDs aus der Host-Sicht zu killen oder über die Container-eigenen PIDs zu gehen, was weniger fehlerträchtig ist:

$ docker container exec a1 kill 13
Auf Container warten

Mit docker [container] wait können Sie warten, bis Container sich beenden, und dann den Exit-Code weiterverarbeiten:

$ docker run -itd --name a2 --rm alpine sh -c "sleep 10; exit 42"
7568fd857a4f4b76e14fac469de328bd7609170fbc549acad8a814161cf36f7a

$ docker container wait a2
[...einige Sekunden vergehen...]
42
Container pausieren

Mit docker [container] pause/unpause können Sie schließlich noch einen Container mit all seinen Prozessen pausieren (»suspenden«) und zu gegebener Zeit wieder aktivieren.

21.2.6    Umgebungsvariablen

Mitunter gibt es die Anforderung, einen Container beim Start von außen mit irgendwelchen Informationen zu versorgen. Beispielsweise benötigt ein Datenbank-Container möglicherweise ein Master-Password, um sich beim ersten Start initialisieren zu können.

Die präferierte Vorgehensweise ist die Übergabe von Umgebungsvariablen. Es gibt dafür drei Möglichkeiten:

21.2.7    (Zentralisiertes) Logging

Alle Ausgaben von Docker-Containern (nach STDOUT oder STDERR) werden von einem Logging-Treiber »eingefangen« und entsprechend der treiberspezifischen Konfiguration weiterverarbeitet. Es stehen diverse Logging-Treiber zur Verfügung:

Die Treiber json-file und journald ermöglichen als einzige die interaktive Betrachtung mit:

docker [container] logs [-f] <NAME>

Der gewünschte Treiber ist über den Startparameter --log-driver einstellbar; mit --log-opt=[] können Sie treiberspezifische Einstellungen ändern. Diese Parameter können auf zwei Arten gesetzt werden:

Zentralisiertes Logging

Ein Beispiel mit Syslog: Einen entsprechend konfigurierten Syslog-Server im Intranet vorausgesetzt, ginge z. B.:

$ docker run -d --name httpd --rm \
--log-driver=syslog \
--log-opt syslog-address=udp://192.168.27.1:514 \
httpd

Ein Beispiel mit Graylog: Einen entsprechend konfigurierten Graylog-Server im Intranet vorausgesetzt, ginge z. B.:

$ docker run -d --name httpd --rm \
--log-driver=gelf \
--log-opt gelf-address=udp://192.168.27.1:12201 \
httpd

Dabei ist GELF das Graylog Extended Log Format.

21.2.8    Verteilung von Images über Dateiversand

Wollen Sie ein Image einfach und ohne Informationsverlust von einen Host auf den anderen bringen, so können Sie mit docker [image] save bzw. load arbeiten:

# Host 1:
$ docker image save <IMAGE> -o <name>.tar

[... Dateitransfer von <name>.tar nach Host 2 ...]

# Host 2:
$ docker image load -i <name>.tar

Sofern Host 2 »kompatibel« zu Host 1 ist, können Sie aus dem Image jetzt Container erzeugen und starten.

Mit SSH-Direktverbindung

Wenn der zweite Docker-Host via SSH erreichbar ist, geht das alles noch viel eleganter:

# Host 1:
$ docker image save <IMAGE> | ssh <HOST_2> docker image load

21.2.9    Der Docker Hub

Momentan ist unsere hauptsächliche Quelle für Images der Docker Hub, wo Abertausende von Applikationen zum Download bereitstehen. Suchen Sie über das Webinterface z. B. nach »debian«, so bekommen Sie immens viele Treffer; selbiges passiert mit der Kommandozeilenschnittstelle docker search:

$ docker search debian

Dass hier als Ergebnis scheinbar weniger zurückkommt, liegt lediglich daran, dass die Ausgabe per Default auf 25 Treffer beschränkt ist (Option --limit).

Welche Qualitätskriterien gibt es hier? Zunächst mal gibt es eine Bewertung mit »Sternen« – was viele Leute gut finden, kann so schlecht nicht sein. Zum anderen sind manche Images mit dem Zusatz »offiziell« gekennzeichnet.

Das bedeutet, dass diese Images von einem gesponsorten Team gepflegt werden, das eng mit Distributoren, Softwareherstellern und Sicherheitsexperten zusammenarbeitet. Sicherheitspatches werden typischerweise innerhalb von 24 Stunden eingepflegt; Garantien gibt es (natürlich) aber nicht.

Weiterhin spricht noch für die offiziellen Images, dass hier sehr auf gute Dokumentation, geringen Platzbedarf und Best Practices beim Bauen geachtet wird. Letztlich sollten Sie also immer erst nach offiziellen Images schauen, wenn Sie sich auf dem Docker Hub bedienen wollen. Die Kommandozeile kann übrigens auch filtern:

# Nur offizielle Images:
$ docker search -f is-official=true debian

# Mindestens 10 Sterne:
$ docker search -f stars=10 debian
Registrieren lohnt sich!

Das Registrieren auf dem Docker Hub ist kostenlos und benötigt nur eine E-Mail-Adresse. Dafür kommen Sie in den Genuss eines besonderen Service: Alle offiziellen Images werden regelmäßig auf Sicherheitslücken überprüft, und das Ergebnis dieser Tests können Sie sich jederzeit online ansehen (einfach ein Image anwählen und dann den Reiter »Tags«).

21.2.10    Image-Tags und Namenskonventionen

Sie haben sicher schon gesehen, dass Images stets mit einem Tag versehen sind. Tags sind alphanumerische Bezeichner, typischerweise sind es Versionskennungen.

Immer wenn Sie kein explizites Tag angeben, wird das Tag latest verwendet. Auch das haben Sie schon oft gesehen:

$ docker pull centos
Using default tag: latest
[…]

latest ist leider kein ganz glücklicher Name, denn es ist nicht automatisch immer die neuste Version eines Images. Der Maintainer muss sich explizit darum kümmern, dieses Tag »richtig« zu setzen! So sah zum Beispiel im März 2018 das Angebot verfügbarer offizieller MySQL-Images aus:

Wenn es darauf ankommt, sollten Sie das gewünschte Tag daher immer explizit angeben:

$ docker pull mysql:8.0
$ docker pull centos:7

Alle zur Verfügung stehenden Tags eines Repositorys sehen Sie gegebenenfalls entweder online, etwa unter https://hub.docker.com/r/library/centos/tags/.

Oder – nicht so trivial – via Kommandozeile:

$ curl -sL https://index.docker.io/v1/repositories/library/centos/tags | \
jq '.[].name'
Namenskonventionen für Images

Auf dem Docker Hub können Sie offizielle Images leicht daran erkennen, dass ihr Name nicht mit Slashes unterteilt ist. httpd ist also offiziell, publici/httpd nicht.

Sobald Sie selbst beginnen, eigene Images zu erstellen, sollten Sie dieser Konvention ebenfalls folgen und ein organisationsspezifisches oder persönliches Präfix wählen, sodass insgesamt so etwas entsteht wie:

meinefirma/debian:9.4

Wir werden in solchen Fällen möglichst durchgängig das Präfix local verwenden:

local/debian:9.4

21.2.11    Informationen über Images gewinnen

docker image inspect

Mit docker [image] inspect können Sie Informationen zu lokalen Images erfragen:

$ docker image inspect httpd
[…]

Hier wird man von einer Fülle an Informationen erschlagen. Das ganze in Farbe und ein wenig sortiert, ist auch nur geringfügig besser:

$ docker image inspect httpd | jq -CS . | less -r
[…]

Wenn Sie nun gezielt nach Informationen filtern wollen, kommt dem gemeinen Admin zunächst grep in den Sinn. Jedoch brauchen Sie in einigen Fällen etwas mehr Kontext:

$ docker image inspect httpd | grep -i -C1 ports
[…]
"ExposedPorts": {
"80/tcp": {}
[…]

Ohne die eine Zeile Kontext um den Treffer herum hätten Sie nichts Brauchbares bekommen.

docker image history

Mit docker [image] history können Sie die Build-Historie eines Images anschauen:

$ docker image history httpd
[…]

Insbesondere sehen Sie hier sehr schön, wie viel die einzelnen Schritte des Build-Prozesses jeweils zum Platzbedarf des Images beigetragen haben.

21.2.12    Go-Templates

Viele Docker-Subkommandos bieten Ihnen die Möglichkeit, die Ausgabe über GoTemplates (https://golang.org/pkg/text/template/) zu formatieren bzw. zu filtern. Die OnlineHilfe liest sich dann typischerweise etwa so:

Options:
[…]
-f, --format string Format the output using the given Go template
[…]

Damit eröffnen sich recht komplexe Möglichkeiten, denn wie bei allen Template-Engines verbirgt sich dahinter fast eine komplette Programmiersprache. Wir geben hier nur ein paar Aufrufbeispiele, um die Möglichkeiten zu demonstrieren (bitte selbst ausprobieren):

$ docker image inspect httpd --format '{{.Config.Cmd}}'
[httpd-foreground]

$ docker image inspect httpd --format '{{.Config.ExposedPorts}}'
map[80/tcp:{}]

$ docker image inspect httpd --format '{{json .Config.Env}}' | jq
[
"HTTPD_PREFIX=/usr/local/apache2",
"NGHTTP2_VERSION=1.18.1-1",
"OPENSSL_VERSION=1.0.2l-1~bpo8+1",
"HTTPD_VERSION=2.4.33",
[…]
]

$ docker container ls -a --format '{{json .}}' | jq
[…]

$ docker container ls -a --format '{{printf "%-20s%-20s" .Names .RunningFor}}'
[…]

$ docker container ls -a --format 'table {{.Names}}\t{{.RunningFor}}'
[…]

21.2.13    Erstellen eigener Base-Images

In letzter Konsequenz sind Images aus fremden Repositorys (wie dem Docker Hub) natürlich nie gänzlich vertrauenswürdig. Wir müssen deshalb an dieser Stelle selbstverständlich den weisen Ratschlag geben, dass Sie Ihre Images doch lieber selbst herstellen mögen. (Jetzt fragen Sie nicht, wer das wirklich macht.)

Grundsätzlich können Sie mittels docker image import aus jedem Tarball ein Image erstellen. Im Falle eines Betriebssystem-Basisimages besteht die Kunst jetzt nur noch darin, das Ganze möglichst minimal zu gestalten.

Debian/Ubuntu

Für Debian und Ubuntu gibt es das nette Tool debootstrap aus dem gleichnamigen Paket. Es kann jede beliebige Debian- und Ubuntu-Version in ein Verzeichnis installieren:

$ debootstrap --variant=minbase stretch ./rootfs
$ tar -C ./rootfs -c . | docker import - local/debian:9

CentOS/Red Hat

Unter CentOS/Red Hat gibt es kein Bordwerkzeug, aber immerhin ein Shell-Script auf GitHub (das noch übersichtlich genug ist, um es vor dem Aufruf prüfen zu können):

$ wget https://raw.githubusercontent.com/moby/moby/master/contrib/mkimage-yum.sh
$ bash mkimage-yum.sh local/centos

Damit wird ein Image mit dem gegebenen Namen erstellt. Es bekommt automatisch ein Tag entsprechend der CentOS-Build-Version (etwas wie »7.4.1708«).

openSUSE

Unter openSUSE scheint es bislang leider kein Tool zu geben. Starten Sie bei Bedarf auf einem wirklich minimalen System, etwa mit:

$ tar --numeric-owner \
--exclude=/proc \
--exclude=/sys \
--exclude=/.snapshots \
-cvf opensuse.tar /

Übertragen Sie das Tarfile dann auf Ihren Docker-Host, und importieren Sie es mit:

$ docker import opensuse.tar local/opensuse:42.3

Installation verkleinern

Wenn Ihr Image jetzt etwas zu groß ist (und das wird es sein), könnten Sie nun folgende Strategie versuchen:

  1. Container starten:

    $ docker run -it <IMAGE_NAME> /bin/bash
  2. Das System verschlanken: Pakete deinstallieren, Cache- und Logverzeichnisse löschen, usw.

  3. Nach Beenden des Containers:

    $ docker export <CONTAINER_NAME> | docker import - <NEUER_NAME:NEUER_TAG>

21.2.14    Container limitieren

Standardmäßig hat ein Container unbegrenzten Zugang zu allen Host-Ressourcen wie Hauptspeicher, CPU oder Block-IO.

Mit docker [container] stats können Sie sich zunächst einmal einen kompakten Überblick verschaffen:

$ docker container stats -a --no-stream
CONTAINER ID NAME CPU % MEM USAGE/LIMIT MEM % NET I/O BLOCK I/O PIDS
46f3276f7591 h1 0.00% 10.66MiB/1.788GiB 0.58% 428kB/628kB 15.6MB/0B 82
[…]

Um nun zu vermeiden, dass einzelne Container »über die Stränge schlagen«, ist es möglich, deren Ressourcen zu limitieren. Die dafür vorgesehenen Optionen können Sie im Großen und Ganzen wie folgt auf den Bildschirm bringen:

$ docker run --help | egrep 'cpu|memory|blkio|device'
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
-m, --memory bytes Memory limit
[…]
... jede Menge anderer Optionen ...
[…]

Damit eine Ressource limitiert werden kann, muss der zugrunde liegende Host-Kernel dies aber auch unterstützen. Oft fehlt das Feature »Swap limit support«; prüfen Sie dies auf Ihrem System:

$ docker system info
[…]
WARNING: No swap limit support

Bei Bedarf können Sie dieses Feature über den Kernelparameter swapaccount=1 aktivieren. Dies geschieht wie gewohnt in der Datei /etc/default/grub, und zwar mit der Variablen GRUB_CMDLINE_LINUX_DEFAULT. Vergessen Sie danach nicht, die GRUB-Config neu zu generieren. Oben in der Datei steht ein Kommentar, wie das auf Ihrem Linux-System zu erledigen ist.

Um die Limitierungen eines bereits laufenden Containers zu ändern, steht docker [container] update zur Verfügung. Sie können nicht alle Starteinstellungen ändern, aber doch die wesentlichsten.

In jedem Fall sollten Sie https://docs.docker.com/config/containers/resource_constraints/ lesen, wenn Sie sich genauer mit dem Thema beschäftigen möchten!

21.2.15    Packungsdichte

Ein oft gespriesenes Feature der Containertechnologie ist die erhöhte Packungsdichte im Vergleich zu klassischen VMs.

Natürlich können Sie auf einem Host, der vielleicht 10 VMs verkraften würde, möglicherweise Hunderte von Containern unterbringen. Das gilt aber zunächst nur in Bezug auf den Platzbedarf. Die zur Verfügung stehenden Ressourcen wie CPU, RAM und Netzwerk vervielfachen sich jedoch leider nicht automatisch.

[ ! ] Bringen Sie also stets Ihre Hardwarekonfiguration mit der gewünschten Packungsdichte in Einklang!