Funktionsweise von Docker-Images

Abgeschlossen

Sie haben bereits erfahren, dass ein Containerimage dazu verwendet werden kann, Anwendungen zu verteilen. Dabei liegt der Container, wie zuvor erwähnt, in einem standardisierten Format vor, das von Entwickler- und Betriebsteams gleichermaßen verwendet wird.

Im Folgenden erfahren Sie nun mehr über die Unterschiede zwischen Software, Paketen und Images, wie sie in Docker verwendet werden. Wenn Sie die Unterschiede zwischen diesen Konzepten kennen, können Sie auch die Funktionsweise von Docker-Images besser verstehen.

Außerdem erhalten Sie eine Einführung in die Rollen des Hostbetriebssystems und des Betriebssystem, dass im Container ausgeführt wird.

Im Container enthaltene Software

Die im Container enthaltene Software ist nicht auf die von Ihren Entwickler*innen erstellten Anwendungen begrenzt. Der Begriff „Software“ bezieht sich hier auf Anwendungscode, Systempakete, Binärdateien, Bibliotheken, Konfigurationsdateien und das im Container ausgeführte Betriebssystem.

Nehmen wir an, Sie sollen ein Portal zur Auftragsverfolgung für die verschiedenen Outlets des Unternehmens entwickeln. Dazu müssen Sie den gesamten Stapel von Software betrachten, die in der Webanwendung ausgeführt werden soll. Die Anwendung, die Sie erstellen, ist eine .NET Core-MVC-Anwendung, und Sie planen, die Anwendung mit nginx als Reverseproxyserver unter Ubuntu Linux bereitstellen. Alle diese Softwarekomponenten bilden einen Teil des Containerimages.

Was ist ein Containerimage?

Ein Containerimage ist ein portables Paket, das Software enthält. Es ist das Image, dass, sobald es ausgeführt wird, zum Container wird. Der Container ist die In-Memory-Instanz eines Images.

Ein Containerimage ist unveränderlich. Nachdem Sie ein Image erstellt haben, können Sie es nicht mehr ändern. Die einzige Möglichkeit, eine Änderung an einem Image vorzunehmen, besteht darin, ein neues Image zu erstellen. Diese Funktion stellt sicher, dass das in der Produktionsumgebung verwendete Image das gleiche ist, das auch bei der Entwicklung und Qualitätssicherung verwendet wird.

Was ist das Hostbetriebssystem?

Das Hostbetriebssystem ist ein Betriebssystem, auf dem die Docker-Engine ausgeführt wird. Docker-Container, die unter Linux ausgeführt werden, teilen sich den Kernel des Hostbetriebssystems und benötigen kein Containerbetriebssystem, solange die Binärdatei direkt auf den Kernel des Betriebssystems zugreifen kann.

Diagramm, das ein Docker-Image ohne Basisbetriebssystem und die Abhängigkeit vom Kernel des Hostbetriebssystems zeigt

Windows-Container benötigen jedoch ein Containerbetriebssystem. Der Container hängt vom Kernel des Betriebssystems ab, um Dienste wie Dateisystem, Netzwerkverwaltung, Prozessplanung und Speicherverwaltung zu verwalten.

Was ist das Containerbetriebssystem?

Das Containerbetriebssystem ist das Betriebssystem, das Teil des gepackten Images ist. Verschiedene Versionen von Linux- oder Windows-Betriebssystemen können in einen Container flexibel aufgenommen werden. Dadurch kann auf bestimmte Betriebssystemfunktionen zugegriffen werden oder zusätzliche Software installiert werden, die die Anwendungen verwenden können.

Diagramm, das ein Docker-Image mit einem Basisbetriebssystem von Ubuntu und die Abhängigkeit vom Kernel des Betriebssystems zeigt

Das Containerbetriebssystem ist vom Hostbetriebssystem isoliert und ist die Umgebung, in der die Anwendung bereitgestellt und ausgeführt wird. In Kombination mit der Unveränderlichkeit des Images bedeutet diese Isolierung, dass die Umgebung für die in der Entwicklung ausgeführten Anwendung die gleiche ist wie die in der Produktion.

In diesem Beispiel wird Ubuntu Linux als Containerbetriebssystem verwendet. Dieses Betriebssystem ändert sich nicht von der Entwicklung oder Produktion. Das verwendete Image ist immer das gleiche.

Was ist UnionFS (Unionfs)?

Wir verwenden Unionfs zur Erstellung von Docker-Images. Unionfs ist ein Dateisystem, das es Ihnen ermöglicht, mehrere Verzeichnisse (sogenannte Branches) so zu stapeln, dass es so aussieht, als ob der Inhalt zusammengeführt wird. Der Inhalt wird jedoch physisch getrennt gehalten. Unionfs ermöglicht es Ihnen, beim Aufbau Ihres Dateisystems Branches hinzuzufügen und zu entfernen.

Diagramm, das das Stapeln von Ebenen in einem mit unionfs erstellten Docker-Image zeigt

Nehmen wir zum Beispiel an, wir erstellen ein Image für unsere frühere Webanwendung. Die Ubuntu-Distribution wird als Basisimage über das Boot File System geschichtet. Als nächstes werden nginx und die Web-App installiert. ngingx und die Web-App werden effektiv über das ursprüngliche Ubuntu-Image geschichtet.

Eine endgültige beschreibbare Ebene wird erstellt, sobald der Container aus dem Image ausgeführt wird. Diese Ebene bleibt jedoch nicht bestehen, wenn der Container zerstört wird.

Was ist ein Basisimage?

Ein Basisimage ist ein Image, das das Docker-Image scratch verwendet. Das scratch-Image ist ein leeres Containerimage, das keine Dateisystemebene erstellt. Dieses Image geht davon aus, dass die Anwendung, die Sie ausführen werden, direkt den Kernel des Hostbetriebssystems verwenden kann.

Was ist ein übergeordnetes Image?

Ein übergeordnetes Image ist ein Containerimage, aus dem Sie Ihre Images erstellen.

Anstatt beispielsweise ein Image aus scratch zu erstellen und dann Ubuntu zu installieren, verwenden wir ein Image, das bereits auf Ubuntu basiert. Es kann auch ein Image verwendet werden, auf dem nginx bereits installiert ist. Ein übergeordnetes Image enthält normalerweise ein Containerbetriebssystem.

Was ist der Hauptunterschied zwischen einem Basisimage und einem übergeordneten Image?

Beide Imagetypen ermöglichen es, ein wiederverwendbares Image zu erstellen. Basisimages bieten jedoch die Möglichkeit, mehr Kontrolle über den Inhalt des endgültigen Images zu haben. Denken Sie daran, dass ein Image unveränderlich ist. Sie können nur zu einem Image hinzufügen und nicht subtrahieren.

Unter Windows können Sie nur Containerimages erstellen, die auf Windows-Basiscontainerimages basieren. Microsoft stellt diese Windows-Basiscontainerimages bereit und wartet sie.

Was ist eine Dockerfile-Datei?

Eine Dockerfile-Datei ist eine Textdatei, die Anleitungen enthält, die zum Erstellen und zur Ausführung eines Docker-Images verwendet werden. Er definiert die folgenden Aspekte des Images:

  • Das Basisimage oder das übergeordnete Image, das zur Erstellung eines neuen Images verwendet wird
  • Befehle zur Aktualisierung des Basisbetriebssystems und zur Installation zusätzlicher Software
  • Einzubeziehende Buildartefakte wie beispielsweise entwickelte Anwendungen
  • Verfügbar zu machende Dienste, z. B. Speicher- und Netzwerkkonfiguration
  • Ausführbare Befehle, wenn der Container gestartet wird

Diese Aspekte sollen in einer Dockerfile-Beispieldatei dargestellt werden. Nehmen wir an, dass ein Docker-Image für unsere ASP.NET Core-Website erstellt wird. Die Dockerfile-Datei kann wie im folgenden Beispiel aussehen:

# Step 1: Specify the parent image for the new image
FROM ubuntu:18.04

# Step 2: Update OS packages and install additional software
RUN apt -y update &&  apt install -y wget nginx software-properties-common apt-transport-https \
	&& wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
	&& dpkg -i packages-microsoft-prod.deb \
	&& add-apt-repository universe \
	&& apt -y update \
	&& apt install -y dotnet-sdk-3.0

# Step 3: Configure Nginx environment
CMD service nginx start

# Step 4: Configure Nginx environment
COPY ./default /etc/nginx/sites-available/default

# STEP 5: Configure work directory
WORKDIR /app

# STEP 6: Copy website code to container
COPY ./website/. .

# STEP 7: Configure network requirements
EXPOSE 80:8080

# STEP 8: Define the entry point of the process that runs in the container
ENTRYPOINT ["dotnet", "website.dll"]

Hier wird nicht auf die Dockerfile-Dateispezifikation oder die Details der einzelnen Befehle im vorherigen Beispiel eingegangen. Beachten Sie jedoch, dass es in dieser Datei mehrere Befehle gibt, die es ermöglichen, die Struktur des Images zu manipulieren. Der Befehl COPY kopiert beispielsweise den Inhalt eines bestimmten Ordners auf dem lokalen Computer in das erstellte Containerimage.

Wir haben bereits erwähnt, dass Docker-Images unionfs verwenden. Jeder dieser Schritte erstellt ein zwischengespeichertes Containerimage, während das endgültige Containerimage erstellt wird. Diese temporären Images werden über das vorherige geschichtet und nach Abschluss aller Schritte als einzelnes Image dargestellt.

Beachten Sie abschließend den letzten Schritt, Schritt 8. Der ENTRYPOINT in der Datei gibt an, welcher Prozess ausgeführt wird, sobald ein Container von einem Image aus ausgeführt wird. Wenn kein ENTRYPOINT oder ein anderer auszuführender Prozess vorhanden ist, geht Docker davon aus, dass für den Container nichts zu tun ist, und der Container wird beendet.

Verwalten von Docker-Images

Docker-Images sind große Dateien, die anfänglich auf Ihrem PC gespeichert werden. Zur Verwaltung dieser Dateien werden Tools benötigt.

Mit der Docker-CLI und Docker Desktop können Images durch Erstellen, Auflisten, Entfernen und Ausführen verwaltet werden. Docker-Images werden durch die Verwendung des docker-Clients verwaltet. Der Client führt die Befehle nicht direkt aus und sendet alle Abfragen an den dockerd-Daemon.

Es werden hier nicht alle Clientbefehle und Befehlsflags behandelt. Nur einige der am häufigsten verwendeten Befehle werden hier aufgezeigt. Der Abschnitt Weitere Informationen in der Einheit Zusammenfassung in diesem Modul enthält Links zur Docker-Dokumentation, die alle Befehle und Befehlsflags im Detail behandelt.

Erstellen eines Images

Der Befehl docker build wird zum Erstellen von Docker-Images verwendet. Nehmen wir an, wir verwenden die Dockerfile-Definition von vorhin, um ein Image zu erstellen. Hier finden Sie ein Beispiel, das den Buildbefehl zeigt:

docker build -t temp-ubuntu .

Dies ist die Ausgabe, die der Buildbefehl generiert:

Sending build context to Docker daemon  4.69MB
Step 1/8 : FROM ubuntu:18.04
 ---> a2a15febcdf3
Step 2/8 : RUN apt -y update && apt install -y wget nginx software-properties-common apt-transport-https && wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && dpkg -i packages-microsoft-prod.deb && add-apt-repository universe && apt -y update && apt install -y dotnet-sdk-3.0
 ---> Using cache
 ---> feb452bac55a
Step 3/8 : CMD service nginx start
 ---> Using cache
 ---> ce3fd40bd13c
Step 4/8 : COPY ./default /etc/nginx/sites-available/default
 ---> 97ff0c042b03
Step 5/8 : WORKDIR /app
 ---> Running in 883f8dc5dcce
Removing intermediate container 883f8dc5dcce
 ---> 6e36758d40b1
Step 6/8 : COPY ./website/. .
 ---> bfe84cc406a4
Step 7/8 : EXPOSE 80:8080
 ---> Running in b611a87425f2
Removing intermediate container b611a87425f2
 ---> 209b54a9567f
Step 8/8 : ENTRYPOINT ["dotnet", "website.dll"]
 ---> Running in ea2efbc6c375
Removing intermediate container ea2efbc6c375
 ---> f982892ea056
Successfully built f982892ea056
Successfully tagged temp-ubuntu:latest

Machen Sie sich keine Sorgen, wenn Sie die vorherige Ausgabe nicht verstehen. Beachten Sie jedoch die in der Ausgabe aufgeführten Schritte. Wenn jeder Schritt ausgeführt wird, wird dem Image, das erstellt wird, eine neue Ebene hinzugefügt.

Beachten Sie auch, dass eine Reihe von Befehlen ausgeführt wird, um Software zu installieren und die Konfiguration zu verwalten. In Schritt 2 werden beispielsweise die Befehle apt -y update und apt install -y ausgeführt, um das Betriebssystem zu aktualisieren. Diese Befehle werden in einem bestehenden Container ausgeführt, der für diesen Schritt erstellt wurde. Nach Ausführung des Befehls wird der Zwischencontainer entfernt. Das zugrunde liegende zwischengespeicherte Image wird auf dem Buildhost gespeichert und nicht automatisch gelöscht. Diese Optimierung stellt sicher, dass spätere Builds diese Images wiederverwenden, um die Buildzeiten zu verkürzen.

Was ist ein Imagetag?

Ein Imagetag ist eine Textzeichenfolge, die verwendet wird, um einem Image eine Version zuzuordnen.

Beachten Sie im vorherigen Buildbeispiel die letzte Buildmeldung „Successfully tagged temp-ubuntu: latest (temp-ubuntu: latest erfolgreich markiert“). Wenn ein Image erstellt wird, wird das Image benannt und optional mit dem Befehlsflag -t markiert. In diesem Beispiel wurde das Image mit -t temp-ubuntu benannt, während der resultierende Imagename mit temp-ubuntu: latest markiert war. Ein Image wird mit dem Tag latest gekennzeichnet, wenn Sie kein Tag angeben.

Einem einzelnen Image können mehrere Tags zugewiesen werden. Gemäß der Konvention wird der neuesten Version eines Images das Tag latest (Neueste) und ein Tag zugewiesen, das die Versionsnummer des Images beschreibt. Wenn Sie eine neue Version eines Images freigeben, können Sie das Tag „latest“ (Neueste) erneut zuweisen, damit es auf das neue Image verweist.

Für Windows stellt Microsoft keine Basiscontainerimages mit dem neuesten Tag bereit. Für Windows-Basiscontainerimages müssen Sie ein Tag angeben, das Sie verwenden möchten. Das Windows-Basiscontainerimage für Server Core ist mcr.microsoft.com/windows/servercore. Zu den Tags gehören ltsc2016, ltsc2019 und ltsc2022.

Hier sehen Sie ein weiteres Beispiel. Nehmen wir an, Sie möchten die Docker-Images für .NET Core-Beispiele verwenden. Hier finden Sie vier Plattformversionen, aus denen Sie auswählen können:

  • mcr.microsoft.com/dotnet/core/samples:dotnetapp

  • mcr.microsoft.com/dotnet/core/samples:aspnetapp

  • mcr.microsoft.com/dotnet/core/samples:wcfservice

  • mcr.microsoft.com/dotnet/core/samples:wcfclient

Anhand der vorherigen Liste der Images ist ersichtlich, dass Microsoft mehrere Beispiele für .NET Core bereitstellt. Tags geben an, auf welche Beispiele sich das Image bezieht: ASP.NET, den WCF-Dienst usw.

Listen von Images

Die Docker-Software konfiguriert automatisch eine lokale Imageregistrierung auf Ihrem Computer. Sie können die Images in der Registrierung mit dem Befehl docker images einsehen.

docker images

Die Ausgabe sieht wie folgt aus:

REPOSITORY          TAG                     IMAGE ID            CREATED                     SIZE
tmp-ubuntu          latest             f89469694960        14 minutes ago         1.69GB
tmp-ubuntu          version-1.0        f89469694960        14 minutes ago         1.69GB
ubuntu              18.04                   a2a15febcdf3        5 weeks ago            64.2MB

Beachten Sie, wie das Image mit seinem Namen, Tag und einer Image-ID aufgelistet wird. Erinnern Sie sich daran, dass einem Image mehrere Bezeichnungen zugewiesen werden können. Die vorherige Ausgabe zeigt ein Beispiel. Obwohl die Bildnamen unterschiedlich sind, können wir sehen, dass die IDs die gleichen sind.

Die Image-ID hilft Images zu identifizieren und zu verwalten, bei denen der Name oder das Tag eines Images nicht unbedingt eindeutig ist.

Entfernen eines Images

Mit dem Befehl docker rmi können Sie ein Image aus der lokalen Docker-Registrierung entfernen. Dies ist nützlich, wenn Sie Speicherplatz auf dem Datenträger des Containerhosts sparen müssen, da Containerimageebenen bis zum insgesamt verfügbaren Speicher hinzugefügt werden.

Geben Sie den Namen oder die ID des Images an, das entfernt werden soll. In diesem Beispiel wird das Image für die Beispiel-Web-App mithilfe des Imagenamens entfernt:

docker rmi temp-ubuntu:version-1.0

Sie können ein Image nicht entfernen, wenn ein Container das Image weiterhin verwendet. Der Befehl docker rmi gibt eine Fehlermeldung mit dem Container zurück, der das Image verwendet.

In dieser Einheit haben Sie grundlegende Informationen zu Docker-Images erhalten und erfahren, wie diese Images verwaltet werden und wie ein Container aus einem Image ausgeführt wird. In der nächsten Einheit wird beschrieben, wie Container verwaltet werden.

Überprüfen Sie Ihr Wissen

1.

Docker Desktop ist eine App zum Erstellen und Freigeben von Container-Apps und Microservices, die für welche der folgenden Betriebssysteme verfügbar ist?

2.

Welcher Docker-Befehl wird verwendet, um ein Containerimage neu zu erstellen?

3.

Welcher der folgenden Sätze beschreibt ein Containerimage am besten?