Docker-Images verstehen und erstellen: Ein Leitfaden für Anfänger

In dieser Einführung bringen wir Ihnen nicht nur die Grundlagen von Docker-Images näher, sondern zeigen Ihnen auch, wo Sie fertige Standard-Images finden, damit Sie gleich mit dem Erstellen Ihrer eigenen containerisierten Anwendungen, Tools und Services loslegen können.

Als Docker-Newbie müssen Sie außerdem lernen, wie Sie Ihre eigenen benutzerdefinierten Images erstellen können. Daher werden wir kurz darauf eingehen, wie Sie Docker-Images für die Bereitstellung Ihres Codes und die Zusammenstellung von container-basierten Services erstellen. Aber zuerst sehen wir uns die Grundlagen und die Zusammensetzung eines Docker-Images im Detail an.

Was ist ein Docker-Image?

Ein Docker-Image ist ein schreibgeschütztes Template, das eine Reihe von Anweisungen zur Erstellung eines Containers enthält, der auf der Docker-Plattform ausgeführt werden soll. Es bietet eine praktische Möglichkeit, Anwendungen und vorkonfigurierte Serverumgebungen, die Sie privat nutzen oder mit anderen Docker-Benutzern öffentlich teilen, zu verpacken. Docker-Images sind außerdem der Ausgangspunkt für alle, die Docker zum ersten Mal verwenden.

Aufbau eines Docker-Images

Ein Docker-Image besteht aus einer Sammlung von Dateien, in der alle wesentlichen Elemente, die zur Konfiguration einer voll funktionsfähigen Container-Umgebung erforderlich sind (wie Installationen, Anwendungscode und Abhängigkeiten), gebündelt sind. Sie können ein Docker-Image auf zwei Arten erstellen:

  • Interaktiv: Durch das Ausführen eines Containers aus einem bereits vorhandenen Docker-Image, manuellen Änderungen dieser Container-Umgebung (während der Container ausgeführt wird ) und Speichern des Endergebnisses als neues Image.
  • Dockerfile: Durch das Erstellen eines Plain-Text-Files, auch als Dockerfile bekannt, das die Details für die Erstellung eines Docker-Images enthält.

Wir werden diese beiden Methoden später noch ausführlicher behandeln. Zunächst konzentrieren wir uns jedoch auf die wichtigsten Konzepte von Docker-Images.

Docker-Layers

Jede der Dateien, aus denen ein Docker-Image besteht, wird als “Layer” (auf Deutsch “Schicht”) bezeichnet. Diese Layer bilden mehrere Zwischen-Images, die stufenweise aufeinander aufbauen, wobei jeder Layer von dem unmittelbar darunter liegenden Layer abhängig ist. Die Hierarchie Ihrer Layer ist entscheidend für die effiziente Verwaltung des Lebenszyklus-Managements Ihrer Docker-Images. Daher sollten Sie die Layer, die sich am häufigsten ändern, möglichst weit oben im Stack anordnen. Wenn Sie nämlich Änderungen an einem Layer in Ihrem Image vornehmen, erstellt Docker nicht nur diesen bestimmten Layer neu, sondern auch alle darauf aufbauenden Layer. Daher erfordert eine Änderung zur Neuerstellung des gesamten Images an einem Layer ganz oben im Stack den geringsten Rechenaufwand.

Container-Layer

Jedes Mal, wenn Docker einen Container aus einem Image startet, fügt es einen dünnen, beschreibbaren Layer hinzu, den sogenannten “Container-Layer”, der alle Änderungen am Container während seiner Laufzeit speichert. Da dieser Layer der einzige Unterschied zwischen einem ausgeführten Container und dem Source-Docker-Image selbst ist, können beliebig viele vergleichbare Container auf dasselbe zugrunde liegende Image zugreifen, während sie ihren eigenen individuellen Status beibehalten.

Graphic showing the Docker containers and other layers that make up a Docker image.

Parent-Image

In den meisten Fällen wird die erste Schicht eines Docker-Images als “Parent-Image” bezeichnet. Es bildet das Fundament, auf dem alle anderen Layer aufgebaut werden, und liefert die grundlegenden Bausteine für Ihre Container-Umgebungen. Auf der öffentlichen Container-Registry Docker Hub finden Sie eine große Auswahl an fertigen Images, die Sie als Parent-Image verwenden können.

Auch bei Drittanbietern wie z. B. der Google Container Registry können Sie fündig werden. Außerdem gibt es die Möglichkeit, dass Sie eines Ihrer eigenen, bereits bestehenden Images als Grundlage für die Erstellung neuer Images verwenden.

Ein typisches Parent-Image kann eine abgespeckte Linux-Distribution bei cloudbasierten Bereitstellungen sein oder mit einem vorinstallierten Service wie einem Database-Management-System (DBMS) oder Content-Management-System (CMS) ausgestattet sein.

Base-Image

Ein Base-Image ist im Grunde genommen ein leerer erster Layer, mit dem Sie Ihre Docker-Images von Grund auf erstellen können. Base-Images geben Ihnen die volle Kontrolle über den Inhalt der Images, sind aber in der Regel für fortgeschrittene Docker-Benutzer gedacht.

Docker-Manifest

Ein Docker-Image enthält neben mehreren Layer-Dateien auch eine zusätzliche Datei, die als “Manifest” bezeichnet wird. Dabei handelt es sich im Wesentlichen um eine Beschreibung des Images im JSON-Format, die Informationen wie Image-Tags, digitale Signatur und Details zur Konfiguration des Containers für verschiedene Arten von Host-Plattformen enthält.

 

A Docker File build → Docker Image run → Docker Container

Container-Registries

Container-Registries sind Kataloge von Speicherorten (sogenannte “Repositories”), in denen Sie Container-Images hoch- und herunterladen können. Die drei wichtigsten Registry-Typen sind:

  • Docker Hub: Die offizielle Image-Ressource von Docker, über die Sie auf mehr als 100.000 Container-Images zugreifen können, die von Software-Anbietern, Open-Source-Projekten und der Docker-Community geteilt werden. Sie können den Service auch nutzen, um Ihre privaten Images zu hosten und zu verwalten.
  • Registry-Services von Drittanbietern: Vollständig verwaltete Angebote, die als zentraler Zugriffspunkt auf Ihre eigenen Container-Images dienen und diese speichern, verwalten und sichern – ganz ohne die betrieblichen Herausforderungen einer eigenen lokalen Registry. Beispiele für Registry-Angebote von Drittanbietern, die Docker-Images unterstützen, sind Red Hat Quay, Amazon ECR, Azure Container Registry, Google Container Registry und das JFrog Container Registry.
  • Self-Hosted-Registries: Ein Registry-Modell, das von Unternehmen bevorzugt wird, die Container-Images aufgrund von Sicherheits-, Compliance- oder Latenzanforderungen lieber auf ihrer eigenen Infrastruktur vor Ort hosten möchten. Um Ihre eigene selbst gehostete Registry zu betreiben, müssen Sie einen Registry-Server einrichten. Alternativ können Sie auch Ihre private, remote und virtuelle Docker-Registry einrichten.

Container-Repositories

Container-Repositories sind die spezifischen physischen Orte, an denen Ihre Docker-Images gespeichert werden. Jedes Repository besteht aus einer Sammlung zusammengehöriger Images mit demselben Namen. Jedes der Images innerhalb eines Repositorys wird individuell durch einen anderen Tag referenziert und repräsentiert eine andere Version derselben Container-Bereitstellung. Auf Docker Hub ist mysql zum Beispiel der Name des Repositorys, das verschiedene Versionen des Docker-Images für das beliebte Open-Source-DBMS MySQL enthält.

Wie man ein Docker-Image erstellt

In diesem letzten Abschnitt werden wir die beiden unterschiedlichen Methoden zur Erstellung von Docker-Images etwas ausführlicher behandeln, damit Sie Ihr Wissen in die Praxis umsetzen können.

Interaktive Methode

User-added image

Vorteile: Schnellste und einfachste Möglichkeit, Docker-Images zu erstellen. Ideal zum Testen, zur Fehlerbehebung sowie zur Ermittlung von Abhängigkeiten und zur Validierung von Prozessen.

User-added image

Nachteile: Schwieriges Lebenszyklus-Management, das eine fehleranfällige manuelle Neukonfiguration von Live-Interaktionsprozessen erfordert. Es ist einfacher, nicht optimierte Images mit unnötigen Layern zu erstellen.

 

Im Folgenden finden Sie eine vereinfachte Anleitung zur interaktiven Erstellung eines Images:

  • Installieren Sie Docker und starten Sie den Docker-Engine.
  • Öffnen Sie eine Terminal-Session.
  • Verwenden Sie den folgenden Docker-Run-Befehl, um eine interaktive Shell-Session mit einem Container zu starten, der von dem durch image_name:tag_name angegebenen Image gestartet wird:

$ docker run -it image_name:tag_name bash

Wenn Sie den Tag-Namen weglassen, ruft Docker automatisch die aktuelle Image-Version, die durch den neuesten Tag gekennzeichnet ist, ab. Wenn Docker das Image lokal nicht findet, wird alles, was zum Erstellen des Containers benötigt wird, aus dem entsprechenden Repository auf Docker Hub heruntergeladen.

In unserem Beispiel starten wir eine Container-Umgebung, die auf der neuesten Version von Ubuntu basiert:

$ docker run -it ubuntu bash

  • Konfigurieren Sie nun Ihre Container-Umgebung, indem Sie z. B. alle benötigten Frameworks, Abhängigkeiten, Bibliotheken, Updates und den Anwendungscode installieren. Das folgende einfache Beispiel fügt einen NGINX-Server hinzu:

# apt-get update && apt-get install -y nginx

Als Nächstes müssen Sie den Namen oder die ID Ihrer laufenden Container-Instanz kennen.

  • Öffnen Sie eine weitere Bash-Shell und geben Sie den folgenden Befehl ein, um aktive Container-Prozesse aufzulisten:

$ docker ps

Der folgende Beispiel-Output zeigt unseren laufenden Container mit der ID e61e8081866dund dem Namen keen_gauss:

CONTAINER ID    IMAGE    COMMAND    CREATED          STATUS        PORTS    NAMES
e61e8081866d       ubuntu      “bash”         2 minutes ago     Up 2 minutes         keen_gauss

Dieser Name wird vom Docker-Daemon zufällig generiert. Sie können Ihrem Container aber auch eine aussagekräftigere Bezeichnung geben, indem Sie ihm mit dem Name-Operator im Docker-Run-Befehl einen eigenen Namen zuweisen.

  • Speichern Sie Ihr Image mit dem Docker-Commit-Befehl, wobei Sie entweder die ID oder den Namen des Containers, aus dem Sie es erstellen möchten, angeben:

$ docker commit keen_gauss ubuntu_testbed

Im obigen Beispiel haben wir den Namen unseres Containers angegeben und das daraus resultierende Image ubuntu_testbed genannt.

  • Verwenden Sie nun den Befehl Docker-Images, um das soeben erstellte Image anzuzeigen:

$ docker images

Sie sollten nun Ihr neues Image in den Ergebnissen sehen.

REPOSITORY     TAG        IMAGE ID          CREATED            SIZE
ubuntu                 latest      775349758637    5 minutes ago      64.2MB

  • Kehren Sie schlussendlich zu Ihrer interaktiven Container-Shell zurück und geben Sie exit ein, um sie zu beenden.

# exit

Dockerfile-Methode

Vorteile: Saubere, kompakte und wiederholbare recipe-basierte Images. Einfacheres Management des Lebenszyklus und einfachere Integration in Continuous-Integration-(CI) und Continuous-Delivery-(CD)Prozesse. Klarer, selbsterklärender Ablauf der Arbeitsschritte bis zum Erstellen des Images.

User-added image

Nachteile: Für Anfänger schwieriger und zeitaufwändiger bei einer grundlegenden Neuerstellung.

 

Die Dockerfile-Methode ist empfehlenswert für konkrete Container-Bereitstellung auf Enterprise-Level. Es ist eine systematischere, flexiblere und effizientere Methode zur Erstellung von Docker-Images und der Schlüssel zu kompakten, zuverlässigen und sicheren Container-Umgebungen.

Kurz gesagt ist die Dockerfile-Methode ein dreistufiger Prozess, bei dem Sie das Dockerfile erstellen und die Befehle hinzufügen, die Sie für das Erstellen des Images benötigen.

Die folgende Tabelle zeigt die Dockerfile-Anweisungen, die Sie am ehesten verwenden werden:

Befehl

Zweck

FROM

Um das Parent-Image anzugeben.

WORKDIR

Zum Festlegen des Arbeitsverzeichnisses für alle nachfolgenden Befehle im Dockerfile.

RUN

Zur Installation aller Anwendungen und Pakete, die für Ihren Container erforderlich sind.

COPY

Um Dateien oder Verzeichnisse von einem bestimmten Speicherort zu kopieren.

ADD

Wie COPY, kann aber auch mit Remote-URLs umgehen und komprimierte Dateien entpacken.

ENTRYPOINT

Befehl, der jedes Mal ausgeführt wird, wenn der Container gestartet wird. Falls nicht angegeben, ist der Default-Befehl /bin/sh -c.

CMD

Argumente, die an den Entrypoint übergeben werden. Wenn ENTRYPOINT nicht festgelegt ist (defaults to/bin/sh -c), werden die CMD-Befehle vom Container ausgeführt.

EXPOSE

Legt fest, über welchen Port auf die Container-Anwendung zugegriffen wird.

LABEL

Um Metadaten zum Image hinzuzufügen.

Beispiel eines Dockerfile

# Use the official Ubuntu 18.04 as base
FROM ubuntu:18.04
# Install nginx and curl
RUN apt-get update &&
apt-get upgrade -y &&
apt-get install -y nginx curl &&
rm -rf /var/lib/apt/lists/*

Ein Beispiel für ein Dockerfile zur Erstellung eines Images, das auf dem offiziellen Ubuntu 18.04 mit der Installation von Nginx basiert.

Als nächstes werden wir ein .dockerignore-File einrichten, um alle Dateien aufzulisten, die sonst während des Docker-Build-Prozesses erstellt werden würden und die Sie aus dem endgültigen Build ausschließen möchten.

.dockerignore-Files spielen eine wichtige Rolle bei der Erstellung von kompakteren, schneller laufenden Containern, indem sie verhindern, dass sensible oder unnötige Dateien und Verzeichnisse in Ihre Image-Builds gelangen. Ihre .dockerignore-File sollte sich im Root-Directory (dem sogenannten “Build-Context”), befinden, aus dem Sie Ihr Image erstellen möchten. Das ist entweder Ihr aktuelles Arbeitsverzeichnis oder der Pfad, den Sie unter dem Docker-Build-Befehl (siehe unten) angeben.

Der Docker-Build-Context

Verwenden Sie nun den Befehl Docker build, um Ihr Docker-Image zu erstellen. Benutzen Sie das -t flag, um einen Image-Namen und -Tag festzulegen:

$ docker build -t my-nginx:0.1 .

Im obigen Beispiel haben wir das Image aus demselben Verzeichnis wie das Dockerfile und den Kontext erstellt, da das Argument den Docker-Daemon einfach anweist, das Image aus den Dateien und Ordnern im aktuellen Arbeitsverzeichnis zu erstellen.

Wie wir bei der interaktiven Methode gesehen haben, können Sie schließlich den Docker-Images-Befehl verwenden, um das soeben erstellte Image anzuzeigen.

$ docker images

REPOSITORY     TAG IMAGE ID        CREATED SIZE

my-nginx       0.1 f95ae2e1344b    10 seconds ago 138MB

ubuntu         18.04 ccc6e87d482b  12 days ago 64.2MB

Auch hier sollten Sie Ihr neues Image in den Ergebnissen sehen.

Erfahren Sie mehr über Docker!