Docker-Einführung, Teil 2 Images und Container unter Docker

Autor / Redakteur: Dipl. -Ing. Thomas Drilling / Stephan Augsten |

Irgendetwas muss Docker besser machen, als andere bekannte Prinzipien und Methoden der Containerisierung und Isolierung. Im zweiten Teil des Docker-Workshops beleuchten wir daher das Konzept der Images, insbesondere den Unterschied zwischen Images und Containern.

Anbieter zum Thema

Lokal nicht vorgehaltene Images bezieht der Docker-Daemon aus einem Online-Repository.
Lokal nicht vorgehaltene Images bezieht der Docker-Daemon aus einem Online-Repository.
(Bild: Drilling / Docker)

Ein besonders wichtiger Aspekt bei Containern sind die Images. So wird jeder Container aus einem eigenen Image mit eigenem Dateisystem heraus gestartet. Dazu packt der Build-Prozess eines Images alles, was die Applikation zur Laufzeit benötigt (Bibliotheken, Tools, Compiler, Config-Dateien etc.), in das Image hinein und startet daraus den Container. Es ist genau dieser Prozess, der Container besonders portabel macht.

Aber Achtung: Docker unterscheidet zwischen Containern und Images. Daher ist es wichtig, den Unterschied zwischen beiden Konstrukten genau zu kennen. Im Allgemeinen versteht man unter einem Image eine Art Archiv, das Dateien beinhaltet und als geschlossene Einheit betrachtet werden kann.

Zu jedem Docker-Image mit seinen Dateien gehört immer auch eine Beschreibungsdatei, das sogenannte Dockerfile oder auch „Manifest“. Dieses beinhaltet unter anderem spezielle Docker-Konfigurationsanweisungen, etwa zur Netzwerkkonfiguration, sowie eine Beschreibung, wie die einzelnen Image-Layer (dazu später mehr) aufeinander aufbauen. Letztendlich beschreibt die Datei also, wie ein Docker-Container auszusehen hat.

Jedes Docker-Abbild verwendet daher als Basis-Image meist ein Abbild für ein (Linux)-Betriebssystem wie CentOS oder Ubuntu, um den drauf aufbauenden Applikations-Layern die jeweils passende Laufzeitumgebung mitzugeben. Jedes Docker-Image ist – im Gegensatz zu einer Applikation mit ihren Abhängigkeiten vom Host-System – somit portabel; es lässt sich zwischen verschiedenen Systemen (physische/virtuelle Hosts, Cloud) hin und her transportieren oder auf einem Repository hosten.

Image-Hierarchie

Wurde aus einem Basis-Image ein Container initialisiert, kann der Nutzer jederzeit neue „Momentaufnahmen“ in Form von Images ableiten, die den aktuellen Zustand des Systems widerspiegeln. Dieser Vorgang heißt-Build-Prozess, wird durch das docker-build-Kommando gesteuert und kann wahlweise interaktiv bzw. manuell erfolgen oder automatisch, gesteuert durch ein Docker-Manifest-File.

Startet man beispielsweise mit einer CentOS-Basisinstallation und installiert dann etwa Python, ist die neue Version eine CentOS-Version mit Python. Somit ist der Container selbst quasi die „Laufzeit-Reinkarnation“ des aktuellen Images zum Zeitpunkt „t“.

Kleines Docker-Tutorial
Bildergalerie mit 7 Bildern

Nehmen wir an, es existiert hat ein Image einer Datenbank. Dieses ist dadurch entstanden, dass man auf Basis eines ursprünglichen CentOS-Images z. B. MariaDB installiert und aus dem laufenden Container das Datenbank-Image gebaut hat. Möchte man einen neuen Container erzeugen, der aus einem MariaDB-Cluster mit mehreren Instanzen besteht, nimmt man dieses neue Image als Grundlage und erzeugt auf dieser Basis die gewünschte Anzahl Instanzen.

Ähnlich gut funktioniert das z. B. für einen Apache Stack mit PHP. Auch hierzu erzeugt man einen Container aus einem Basis-Image, z. B. für Ubuntu, und installiert den Apache Stack. Aus diesem könnte man dann wieder PHP installieren und erzeugt aus diesem Container ein neues Image „Webserver mit PHP“, aus dem man dann später zu jedem Zeitpunkt weitere neuen Container initialisieren kann.

Bei Docker-Images gilt es, einige wichtige Merkmale im Hinterkopf zu behalten.
Bei Docker-Images gilt es, einige wichtige Merkmale im Hinterkopf zu behalten.
(Bild: Drilling / Docker)

Halten wir also folgende Eigenschaften von Images fest:

  • Docker Images sind Read-Only-Templates, um Container zu erzeugen.
  • Docker Images bestehen aus einem oder mehreren Dateisystem-Layern, von denen der jeweils obere auf dem unterliegenden aufsetzt.
  • Docker verwendet Union Files Systems (UFS) zum Bauen von Images (dazu im Verlauf mehr)
  • Jedes Update eines Images fügt einen neuen Layer hinzu, anstatt jedes Mal das gesamte Image neu zu bauen, wobei der oberste Layer (writeable Layer) quasi als Snapshot fungiert.
  • Images können über verschiedene Container geshared sein
  • Es gilt die Gleichung: Container = Image + writeable Layer

Da man zu jederzeit Momentaufnahmen eines Containers in Form von Images erzeugen kann, bedarf es für einen effizienten Umgang mit dem geschilderten Prozess einiger wichtiger Prinzipien. An erster Stelle steht hier die Versionierung, die zusätzlich zum eigentlichen Tag des Images mitgeführt wird.

Das Besondere an Docker-Images ist, dass beim Speichern eines Images immer nur die Änderungen gegenüber dem Basis-Image oder relativ zum vorherigen Image-Layer gespeichert werden. Im Hinterkopf sollte man dabei behalten, dass aus einem Image immer zuerst ein Container initialisiert werden muss, aus dem man wieder neue Images erzeugen kann.

Beim Beispiel mit dem Webserver gibt es demnach ein Image-Betriebssystem wie z. B. CentOS, etwa auf Basis der Version 7.5.1804. Auf Basis dieses Images kann man dann den Apache-Webserver installieren und das Ergebnis als Apache-Image speichern, welche sich dann noch entsprechend versionieren lässt. Auf Basis dieses Apache-Images kann man dann wieder PHP installieren.

Aus dem ursprünglichen x MB großen CentOS-Image ist nun ein Image mit einer Größe von x+y MB entstanden, wobei allerdings nur die Differenz von y tatsächlich gespeichert werden muss. Initialisiert Docker dann eine Instanz von PHP wird auch CentOS bzw. auch Apache mit initialisiert, wozu Docker dann das jeweilige andere Images als Basis des Dateisystems nutzt.

Docker Registry und Docker Hub

Mit „official“ gekennzeichneten Repositories enthalten verifizierte Images.
Mit „official“ gekennzeichneten Repositories enthalten verifizierte Images.
(Bild: Drilling / Docker)

„Zugang“ zu den betreffenden Images findet Docker über eine so genannte Docker-Registry. Eine solche kann man entweder lokal vorhalten oder man bezieht Images von der offiziellen Docker-Registry mit der Bezeichnung Docker-Hub.

Der Docker Hub unterteilt sich dann in verschiedene „öffentliche“ oder „private“ Repositories, die ihrerseits die Images bereithalten. Die mit „official“ gekennzeichneten Repositories enthalten ausdrücklich von Docker geprüfte Abbilder. Jeder Nutzer kann aber jederzeit eigene Repositories anlegen.

Lokal nicht vorgehaltene Images bezieht der Docker-Daemon aus einem Online-Repository.
Lokal nicht vorgehaltene Images bezieht der Docker-Daemon aus einem Online-Repository.
(Bild: Drilling / Docker)

Immer dann, wenn ein von Docker benötigtes Image lokal auf dem Docker-Host nicht vorliegt, bezieht der Docker-Daemon das betreffende Image automatisch via „docker pull“ aus einem Online-Repository, per Default dem offiziellen Docker-Repository. Demzufolge benötigt jeder Nutzer zwingend ein Konto auf dem Docker-Hub, um mit Docker arbeiten zu können.

Da aus jedem Image immer ein Container entstehen muss, kann es sein, dass (beispielsweise bei der automatisierten initialen Bereitstellung des Apache-Webservers) verschiedene „Intermediate-Container“ für einzelne Schritte entstehen, welche zumindest kurzfristig auch Images waren. Gibt der Nutzer dabei keine eigene Versionsnummer an, generiert Docker eine solche selbst, repräsentiert durch die Hexadezimal-Abfolge hinter dem Doppelpunkt des Image-Namens. Die neuste Version eines Images erhält immer den Tag „latest“.

Führt man sich den geschichteten Aufbau eines Containers bestehend dem Base-Layer und ggf. mehreren Ebenen weiterer Images vor Augen, von denen jedes für die Bereitstellung z. B. einer bestimmten Software verantwortlich ist, residiert am oberen Ende dieser Architektur immer der so genannte „writeable Container“, der für die Abstraktion der nicht-persistenten Struktur von Containern verantwortlich ist.

Jede Änderung an einem Container zur Laufzeit etwa das Installieren zusätzlicher Software findet immer nur auf Basis dieses oberen writeable Containers statt. Beendet der Nutzer einen Container ohne zwischenzeitlich ein neues Image gebaut zu haben, verliert er sämtliche Änderungen und fällt auf den Stand des Basis-Images zurück, da der writeable Container hier quasi wie ein Snapshot funktioniert.

Kleines Docker-Tutorial
Bildergalerie mit 7 Bildern

(ID:45410368)