Funktionsweise von Docker-Containern

Abgeschlossen

Sie haben bereits gelernt, dass ein Container dazu verwendet wird, Anwendungen zu verteilen. Dabei liegt der Container in einem standardisierten Format vor, das von Entwickler- und Betriebsteams gleichermaßen verwendet wird.

In Ihrem Beispiel soll ein Portal zur Auftragsverfolgung für die verschiedenen Filialen des Unternehmens entwickelt werden. Nachdem das Docker-Image erstellt wurde, ist das Betriebsteam nun für die Bereitstellung, den Rollout von Updates und die Verwaltung des Portals zur Auftragsverfolgung verantwortlich.

In der vorherigen Einheit haben Sie gelernt, wie ein Docker-Image erstellt wird. In dieser Einheit werden der Lebenszyklus eines Docker-Containers und die Verwaltung von Containern beschrieben. Zudem erhalten Sie Informationen zur Konfiguration der Datenspeicher- und Netzwerkoptionen für Ihre Container.

Verwalten von Docker-Containern

Der Lebenszyklus eines Docker-Containers kann verwaltet und der Status des Containers nachverfolgt werden.

Diagramm: Lebenszyklus eines Containers und Übergang zwischen den Lebenszyklusphasen

Mit dem Befehl run wird ein Container in den Ausführungsstatus versetzt. Sie können einen Container, der bereits ausgeführt wird, auch neu starten. Wird ein Container neu gestartet, empfängt er ein Beendigungssignal und fährt alle laufenden Prozesse ordnungsgemäß herunter, bevor der Kernel des Containers beendet wird.

Ein Container befindet sich im Ausführungsstatus, bis er angehalten oder beendet wird. Die Ausführung kann jedoch auch vom Container selbst beendet werden. Wird der laufende Prozess abgeschlossen oder in einen Fehlerzustand versetzt, kann der Container sich selbstständig beenden.

Mit dem Befehl pause wird ein Container angehalten. Damit werden alle Prozesse im Container angehalten.

Mit dem Befehl stop wird ein ausgeführter Container beendet. Mit dem Befehl stop werden laufende Prozesse ordnungsgemäß über ein Beendigungssignal heruntergefahren. Der Kernel des Containers wird beendet, nachdem der Prozess heruntergefahren wurde.

Mit dem Befehl kill wird ein Abbruchsignal gesendet, um den Container zu beenden. Der Kernel des Containers erfasst das Abbruchsignal, der ausgeführte Prozess jedoch nicht. Mit diesem Befehl wird die Beendigung des laufenden Prozesses im Container erzwungen.

Mit dem Befehl remove werden schließlich Container entfernt, die sich im Status „Beendet“ befinden. Nach dem Entfernen eines Containers werden alle darin gespeicherten Daten gelöscht.

Anzeigen verfügbarer Container

Mit dem Befehl docker ps werden alle ausgeführten Container aufgelistet. Übergeben Sie das Argument -a, wenn Sie alle Container mit sämtlichen Status anzeigen möchten.

Ein Beispiel:

docker ps -a

Mit diesem Befehl wird die folgende Ausgabe erzeugt:

CONTAINER ID    IMAGE        COMMAND         CREATED       STATUS           PORTS        NAMES
d93d40cc1ce9    tmp-ubuntu:latest  "dotnet website.dll …"  6 seconds ago    Up 5 seconds        8080/tcp      happy_wilbur
33a6cf71f7c1    tmp-ubuntu:latest  "dotnet website.dll …"  2 hours ago     Exited (0) 9 seconds ago            adoring_borg

Überprüfen Sie in der vorherigen Ausgabe die folgenden drei Elemente:

  • Der in der Spalte IMAGE aufgeführte Image-Name; in diesem Beispiel tmp-ubuntu: latest. Wie Sie sehen, können Sie mehr als einen Container aus demselben Image erstellen. Dieses leistungsstarke Verwaltungsfeature ermöglicht die Skalierung innerhalb Ihrer Lösungen.

  • Der Status des Containers ist in der Spalte STATUS aufgeführt. In diesem Beispiel wird ein Container ausgeführt, und ein anderer wurde beendet. Der Status eines Containers stellt in der Regel den ersten Indikator für dessen Integrität dar.

  • Der Namen des Containers in der Spalte NAMES aufgeführt. Zusätzlich zur Container-ID in der ersten Spalte erhalten Container auch einen Namen. In diesem Beispiel haben Sie nicht explizit einen Namen für jeden Container angegeben. Daher wurde dem Container von Docker ein zufälliger Name zugewiesen. Sie können einem Container bei der Verwendung des Befehls run mit dem Flag --name einen expliziten Namen geben.

Wozu erhalten Container einen Namen?

Mit dieser Funktion ist es möglich, mehrere Containerinstanzen desselben Images auszuführen. Containernamen sind eindeutig. Das bedeutet, dass Sie einen bereits angegebenen Namen nicht erneut verwenden können, um einen neuen Container zu erstellen. Die einzige Möglichkeit, einen bestimmten Namen erneut zu verwenden, besteht darin, den vorherigen Container zu entfernen.

Ausführen eines Containers

Verwenden Sie den Befehl docker run, um einen Container zu starten. Wenn Sie den Container aus dem Image starten möchten, geben Sie das auszuführende Image über dessen Namen oder ID an. Ein Container, der auf diese Weise gestartet wird, bietet interaktive Funktionen.

Fügen Sie hier das Flag -d hinzu, damit der Container mit der Website im Hintergrund ausgeführt wird.

docker run -d tmp-ubuntu

Der Befehl gibt in diesem Fall nur die ID des neuen Containers zurück.

Nachdem Sie ein Image für die Ausführung angegeben haben, sucht Docker das Image, lädt den Container aus dem Image und führt den als Einstiegspunkt angegebenen Befehl aus. Ab diesem Zeitpunkt kann der Container verwaltet werden.

Anhalten eines Containers

Führen Sie den Befehl docker pause aus, um einen Container anzuhalten. Ein Beispiel:

docker pause happy_wilbur

Durch das Anhalten eines Containers werden alle Prozesse angehalten. Dieser Befehl ermöglicht es dem Container, Prozesse zu einem späteren Zeitpunkt fortzusetzen. Mit dem Befehl docker unpause werden alle Prozesse im angegebenen Container fortgesetzt.

Neustarten eines Containers

Führen Sie den Befehl docker restart aus, um einen Container neu zu starten. Ein Beispiel:

docker restart happy_wilbur

Der Container erhält einen Befehl zum Beenden, gefolgt von einem Startbefehl. Wenn der Container nicht auf den Befehl zum Beenden antwortet, wird ein Abbruchsignal gesendet.

Beenden eines Containers

Führen Sie den Befehl docker stop aus, um einen Container zu beenden. Ein Beispiel:

docker stop happy_wilbur

Der Befehl zum Beenden sendet ein Beendigungssignal an den Container und den Prozess, der im Container ausgeführt wird.

Entfernen eines Containers

Führen Sie den Befehl docker rm aus, um einen Container zu entfernen. Ein Beispiel:

docker rm happy_wilbur

Alle Daten im Container werden zerstört, nachdem Sie den Container entfernt haben. Es ist wichtig, Container beim Speichern von Daten immer als temporär zu betrachten.

Speicherkonfiguration für Docker-Container

Wie bereits erwähnt, müssen Container immer als temporär betrachtet werden, wenn die App in einem Container Daten speichern muss.

Nehmen Sie an, dass Ihr Überwachungsportal eine Protokolldatei in einem Unterordner des Stamms der App erstellt, d. h. direkt im Dateisystem des Containers. Wenn Ihre App Daten in die Protokolldatei schreibt, schreibt das System die Daten in die beschreibbare Containerschicht.

Obwohl dieser Ansatz funktioniert, hat er leider mehrere Nachteile.

  • Containerspeicher sind temporär.

    Die Protokolldatei wird zwischen den Containerinstanzen nicht beibehalten. Nehmen Sie beispielsweise an, dass Sie den Container beenden und entfernen. Wenn Sie eine neue Containerinstanz starten, basiert die neue Instanz auf dem angegebenen Image, und alle Ihre vorherigen Daten fehlen. Denken Sie daran, dass alle Daten in einem Container zusammen mit dem Container zerstört werden, wenn dieser entfernt wird.

  • Containerspeicher sind mit dem zugrunde liegenden Hostcomputer gekoppelt.

    Vom Container aus auf die Protokolldatei zuzugreifen oder diese zu verschieben ist schwierig, da der Container mit dem zugrunde liegenden Hostcomputer gekoppelt ist. Wir müssen eine Verbindung mit der Containerinstanz herstellen, um auf die Datei zuzugreifen.

  • Laufwerke von Containerspeichern sind weniger leistungsfähig.

    Container implementieren einen Speichertreiber, damit Ihre Apps Daten schreiben können. Dieser Treiber führt eine zusätzliche Abstraktion ein, um mit dem Kernel des Hostbetriebssystems zu kommunizieren, und ist weniger leistungsfähig als das direkte Schreiben in ein Dateisystem des Hosts.

Container können zwei Optionen zum Speichern von Daten verwenden. Die erste Option besteht darin, Volumes zu verwenden, und die zweite sind Bindungseinbindungen.

Was ist ein Volume?

Ein Volume wird im Dateisystem des Hosts in einem bestimmten Ordner gespeichert. Wählen Sie einen Ordner aus, von dem Sie wissen, dass seine Daten nicht von Nicht-Docker-Prozessen geändert werden.

Docker erstellt und verwaltet das neue Volume, indem der Befehl docker volume create ausgeführt wird. Dieser Befehl kann einen Teil der Dockerfiledefinition bilden. Das bedeutet, dass Sie bei der Containererstellung auch Volumes erstellen können. Wenn Sie zum ersten Mal versuchen, ein Volume in einen Container einzubinden, und noch kein Volume vorhanden ist, wird es von Docker erstellt.

Volumes werden in Verzeichnissen auf dem Dateisystem des Hosts gespeichert. Docker bindet die Volumes im Container ein und verwaltet sie. Nach der Einbindung werden diese Volumes vom Hostcomputer isoliert.

Mehrere Container können gleichzeitig dieselben Volumes verwenden. Volumes werden auch nicht automatisch entfernt, wenn ein Container das Volume nicht mehr verwendet.

In diesem Beispiel können Sie auf dem Containerhost ein Verzeichnis erstellen und dieses Volume in den Container einbinden, wenn Sie den Container des Überwachungsportals erstellen. Wenn das Überwachungsportal Daten protokolliert, können Sie über das Dateisystem des Containerhosts auf diese Informationen zugreifen. Sie haben Zugriff auf diese Protokolldatei, auch wenn der Container entfernt wurde.

Docker bietet auch eine Möglichkeit für Drittanbieter, Add-Ons zu erstellen, die als Volumes verwendet werden sollen. Azure Storage umfasst beispielsweise ein Plug-In zum Einbinden von Azure Storage als Volumes in Docker-Containern.

Was ist eine Bindungseinbindung?

Eine Bindungseinbindung ist im Prinzip identisch mit einem Volume, Sie können jedoch anstelle eines bestimmten Ordners eine beliebige Datei oder einen beliebigen Ordner im Host einbinden. Sie erwarten auch, dass der Host die Inhalte dieser Einbindungen ändern kann. Genau wie Volumes wird die Bindungseinbindung erstellt, wenn sie eingebunden wird, und ist noch nicht auf dem Host vorhanden.

Bindungseinbindungen haben im Vergleich zu Volumes eine eingeschränkte Funktionalität, und obwohl sie leistungsfähiger sind, sind sie davon abhängig, dass der Host über eine bestimmte Ordnerstruktur verfügt.

Volumes gelten als die bevorzugte Datenspeicherstrategie für Container.

Für Windows-Container ist eine weitere Option verfügbar: Sie können einen SMB-Pfad als Volume einbinden und für Container verfügbar machen. So können Container auf verschiedenen Hosts denselben persistenten Speicher verwenden.

Netzwerkkonfiguration für Docker-Container

Die standardmäßige Docker-Netzwerkkonfiguration ermöglicht die Isolation von Containern auf dem Docker-Host. Dieses Feature ermöglicht es Ihnen, Apps zu erstellen und zu konfigurieren, die sicher miteinander kommunizieren können.

Docker stellt verschiedene Netzwerkeinstellungen für Linux und Windows zur Verfügung.

Für Linux gibt es sechs vorkonfigurierte Netzwerkoptionen:

  • Bridge
  • Host
  • Überlagerung
  • IPvLan
  • MACvLan
  • Keine

Für Windows gibt es sechs vorkonfigurierte Netzwerkoptionen:

  • Netzwerkadressenübersetzung (NAT)
  • Transparent
  • Überlagerung
  • L2Bridge
  • L2Tunnel
  • Keine

Abhängig von den Netzwerkanforderungen wählen Sie aus, welche dieser Netzwerkkonfigurationen auf Ihren Containern angewendet werden sollen.

Was ist das Bridge-Netzwerk?

Das Bridge-Netzwerk ist die Standardkonfiguration, die beim Start auf Container angewendet wird, ohne dass weitere Netzwerkkonfigurationen angegeben werden. Dieses Netzwerk ist ein internes, privates Netzwerk, das vom Container verwendet wird und das Containernetzwerk vom Docker-Hostnetzwerk trennt.

Jedem Container im Bridge-Netzwerk wird eine IP-Adresse und Subnetzmaske zugewiesen, wobei der Hostname standardmäßig dem Containernamen entspricht. Container, die mit dem standardmäßigen Bridge-Netzwerk verbunden sind, können über die IP-Adresse auf andere mit Bridge verbundene Container zugreifen. Das Bridge-Netzwerk lässt die Kommunikation zwischen Containern mithilfe von Hostnamen nicht zu.

Standardmäßig werden von Docker keine Containerports veröffentlicht. Verwenden Sie das Flag --publish für „docker port“, um die Portzuordnung zwischen den Containerports und den Docker-Hostports zu aktivieren.

Das Flag „publish“ konfiguriert effektiv eine Firewallregel, die die Ports zuordnet.

In diesem Beispiel ist das Überwachungsportal für Clients verfügbar, die Port 80 ansteuern. Sie müssen Port 80 aus dem Container einem verfügbaren Port auf dem Host zuordnen. Auf dem Host ist Port 8080 geöffnet, sodass Sie das Flag wie folgt festlegen können:

--publish 8080:80

Alle Clients, die zur Docker-Host-IP und Port 8080 navigieren, können auf das Überwachungsportal zugreifen.

Abgesehen von Linux-spezifischen Konfigurationen funktioniert das NAT-Netzwerk unter Windows genauso wie ein Bridge-Netzwerk. Außerdem ist NAT das Standardnetzwerk unter Windows, und alle Container stellen eine Verbindung mit dem Netzwerk her, sofern nicht anders angegeben.

Was ist das Host-Netzwerk?

Mit dem Hostnetzwerk können Sie den Container direkt im Hostnetzwerk ausführen. Durch diese Konfiguration wird die Isolation zwischen dem Host und dem Container auf Netzwerkebene effektiv entfernt.

In diesem Beispiel wird davon ausgegangen, dass die Netzwerkkonfiguration in die Netzwerkoption „host“ geändert wird. Das Überwachungsportal ist weiterhin über die Host-IP verfügbar. Nun kann der bekannte Port 80 anstelle eines zugeordneten Ports verwendet werden.

Bedenken Sie dabei, dass der Container nur Ports verwenden kann, die nicht bereits vom Host verwendet werden.

Unter Windows ist das Host-Netzwerk nicht verfügbar. Auf Windows-Hosts gibt es keine Option, dieselbe IP-Adresse (Netzwerkstapel) gemeinsam für Host und Container zu verwenden. Das NAT-Netzwerk funktioniert ähnlich wie ein Bridge-Netzwerk, und die Überlagerungsoption stellt eine IP-Adresse für den Container in demselben Netzwerk wie der Host bereit, aber nicht die gleiche IP-Adresse.

Überlagerung und andere Netzwerkoptionen

Für komplexere Szenarien bieten sowohl Linux als auch Windows zusätzliche Netzwerkoptionen. Beispielsweise erstellt die Überlagerungsoption einen virtuellen Switch aus dem Host-Netzwerk, sodass Container in diesem Netzwerk IP-Adressen von DHCP-Servern abrufen oder mit IP-Adressen aus diesem Netzwerksegment arbeiten können. Darüber hinaus ermöglicht Docker Drittanbietern die Erstellung von Netzwerk-Plug-Ins.

Was ist das none-Netzwerk?

Mit der Netzwerkoption none werden Netzwerke für Container deaktiviert. Dies kann nützlich sein, wenn Sie über eine Anwendung verfügen, die das Netzwerk nicht verwendet oder nur überprüfen möchten, ob eine Anwendung wie erwartet in einem Container ausgeführt wird.

Überlegungen zum Betriebssystem

Beachten Sie, dass es Unterschiede zwischen den Desktopbetriebssystemen für die Docker-Netzwerkkonfigurationsoptionen gibt. Die Netzwerkschnittstelle Docker0 ist beispielsweise nicht für macOS verfügbar, wenn das Bridge-Netzwerk verwendet wird. Ebenso wird die Verwendung der Konfiguration für das Host-Netzwerk für Windows- und macOS-Desktops nicht unterstützt.

Diese Unterschiede können sich auf die Art und Weise auswirken, in der Ihre Entwickler ihren Workflow zum Verwalten der Containerentwicklung konfigurieren. Darüber hinaus können Containerorchestratoren zusätzlich zum Docker-Setup auch andere Netzwerkkonfigurationen bereitstellen.

Überprüfen Sie Ihr Wissen

1.

Ein Container wird mit dem Flag „--publish 8080:80“ gestartet. Welche der folgenden Optionen ist die wahrscheinlichste Netzwerkkonfiguration, die für den Container verwendet wird?

2.

Mit welcher Speicheroption kann eine Datei zur Verwaltung der Namenserverauflösung, wie etwa die Datei „resolve.conf“ unter Linux, von Host und Container am besten gemeinsam genutzt werden?