12. Februar 2022

Wie funktionieren Docker Container?

Container stehen bei Digitalisierungsstrategien mit Fokus auf IT-Architekturen schon seit einigen Jahren weit oben auf der Agenda. Insbesondere seit der Veröffentlichung der Docker Container Engine als Open Source 2013 gewannen Container an Popularität und Bedeutung. Dies geschah Hand in Hand mit einer Entwicklung in der Programmierung, weg von monolithischen Applikationen hin zu sogenannten Microservices.

Ähnlich wie VMs sind Container eine Art Behälter für Anwendungen, durch den diese Plattform-unabhängig laufen können. Während VMs jedoch eine ganze Computer-Umgebung inklusive Betriebssystem abbilden, enthalten die Container lediglich die zur Ausführung der Anwendung benötigten Abhängigkeiten. Dies ermöglicht eine leichtgewichtigere Form der Virtualisierung. Die wohl bekannteste Container-Technologie ist Docker, weswegen der Begriff "Docker Container" in aller Munde ist.

Was sind Docker Container?

Docker Container stellen abgekapselte Einheiten dar, die unabhängig voneinander ausgeführt werden können, egal wo sie sich gerade befinden. Wie der Name schon vermuten lässt, haben Docker Container einiges mit Frachtcontainern gemeinsam. Wie diese sind auch Docker Container in einem standardisierten Format und sehr portabel. Jeder Container enthält eine oder manchmal mehrere Applikationen, mit allen benötigten Abhängigkeiten zusammen verpackt. Nun sieht der Container von innen immer identisch aus und die enthaltene Anwendung funktioniert, unabhängig von der Umgebung. Genau wie der Frachtcontainer, der in seiner standardisierten Form auf jedes Schiff und in jeden Hafen passt.

Was ist der Unterschied zwischen Virtual Machines und Docker Containern?

Container werden im Vergleich mit virtuellen Maschinen gerne als leichtgewichtigere Form der Virtualisierung beschrieben. Im Unterschied zu VMs wird bei Containern nicht die Hardware emuliert, sondern das Betriebssystem. Dadurch benötigt ein einzelner Container deutlich weniger Ressourcen als eine VM.

Im Detail laufen VMs direkt auf einem physischen Server, der mit Hilfe eines sogenannten Hypervisors wie z.B. VMware ESXi virtualisiert wird. Für jede VM muss dabei auf der virtuellen Hardware ein eigenes Betriebssystem mit dazugehörigen Hintergrundprozessen gestartet werden. Die Virtualisierung bei Containern erfolgt auf einer höheren Ebene, ohne einen Hypervisor. Hier sorgt das installierte Betriebssystem mit der Container Engine für die Virtualisierung. Dadurch lassen sich viele Container ohne großen Ressource-Overhead auf demselben Server betreiben.

Was sind die Vorteile von Docker Containern?

Container sind sowohl in der Entwicklung als auch im produktiven Betrieb von Anwendungen sehr beliebt und bieten viele Vorteile.

Zunächst sind Docker Container im Vergleich zu VMs deutlich effizienter und ressourcensparender: Sie benötigen weniger CPU und Arbeitsspeicher. Dies ist von Vorteil für Entwickler, welche eine Anwendung im Container schnell und einfach lokal ausführen und testen können. Ebenso profitiert der produktive Betrieb von reduzierter Nutzung der Ressourcen und das Unternehmen durch Kostenersparnis.

Ein weiterer Vorteil ist ihre Portabilität. Als geschlossene Anwendungspakete sind sie auf den unterschiedlichsten Systemen ausführbar. Somit lassen sie sich nicht nur für die Offline-Entwicklung nutzen, sondern funktionieren auch genauso problemlos auf produktiven Servern, unabhängig von der gewählten Infrastruktur bzw. Cloud Plattform. Daraus resultiert eine höhere Geschwindigkeit und Konsistenz in der Entwicklung, beim Debugging und Testen und auch im finalen produktiven Betrieb. Passé sind die Diskussionen zwischen Entwicklung und Operations à la "bei mir lokal hat es aber noch funktioniert".

Container sind hochskalierbar. Werden zusätzliche Instanzen einer Anwendung benötigt, weil z.B. der Traffic auf einer Webseite durch eine gute Marketingkampagne steigt, lassen sich einfach weitere starten und auch wieder stoppen. Innerhalb von kürzester Zeit lassen sich hunderte Container hoch- oder runterfahren. Natürlich muss die Anwendung im Container diese Skalierbarkeit unterstützen. Die Verwaltung dieser großen Anzahl an Containern kann durch Orchestrierungs-Lösungen erleichtert werden.

Was ist Container-Orchestrierung mit Kubernetes?

Zum effizienten Managen von einer großen Anzahl von Containern bedarf es einer sogenannten Container Orchestrierungs-Lösung. Die wohl bekannteste und populärste Software ist Kubernetes.

Mit Kubernetes lassen sich hunderte von Containern koordiniert auf mehreren parallelen Servern betreiben. Kubernetes Lösungen stellen Netzwerk- und Speicher-Funktionalität bereit und koordinieren die verschiedenen Container. Sie sorgen u.a. für das Starten und Stoppen, die optimale Platzierung auf verfügbaren Servern (sogenannten Worker Nodes) und auch sofern nötig die automatisierte Skalierung von sowohl Containern als auch der Worker Nodes.


Bei Claranet setzen wir für das Container Management ebenfalls Kubernetes ein und unterstützen Kubernetes sowohl in unserem eigenen Rechenzentrum, als auch bei den großen Cloud Providern mit GKE (Google Kubernetes Engine), AKS (Azure Kubernetes Service) und Amazon EKS (Elastic Kubernetes Service). Wer sich eingehender mit dem Thema auseinandersetzen möchte, findet Informationen zu Chancen und Risiken sowie Beispielszenarien in unserem Whitepaper "Kubernetes im Unternehmen".

Whitepaper "Kubernetes im Unternehmen"


Was sind Container Images?

Nachdem die Vorteile der Container-Technologie auf der Hand liegen, stellt sich nun die Frage, wie Container gebaut und  ausgeführt werden. Die Basis für den Betrieb von Containern bilden sogenannte Images. Hierbei handelt es sich gewissermaßen um Templates für die Container, mit allen Abhängigkeiten, die zum Betrieb benötigt werden. Sie sind „immutable“, das heißt ein einmal erstelltes Image lässt sich nicht mehr verändern. Dadurch ist garantiert, dass es in jeder Umgebung konsistent und gleich deployed wird. Wird ein Container Image von einer Container Engine wie Docker ausgeführt, hat man einen laufenden Container.

Im Inneren setzt sich ein Image aus aufeinander aufbauenden Schichten, sogenannten „Layern“ zusammen. Die erste Schicht ist das „Base Image“, z.B. ein bestimmtes für Container optimiertes Image des Ubuntu Betriebssystems. Darauf aufbauend werden dann mit jeder Veränderung weitere Schichten hinzugefügt, beispielsweise durch Hinzufügen von benötigten Abhängigkeiten und zum Schluss dem Binary, einer im Container später auszuführenden Anwendung.

Diese Architektur hat den Vorteil, dass sich mehrere Images auf einem Server ein und dasselbe Layer im Speicher teilen können sofern sie auf demselben „Base Image“ aufbauen. Dies spart Speicherplatz und beschleunigt den Download neuer Images.

Verfügbar gemacht werden Images über eine Registry, die sie speichert, verwaltet und bereitstellt. Eine der ersten und bekanntesten öffentlichen Registries ist Docker Hub, mittlerweile gibt es aber viele Alternativen. Möchte man offizielle Images eines Software Anbieters verwenden sollte man sich erkundigen, wo deren Images bereitgestellt werden.

Wird im eigenen Unternehmen viel mit Containern gearbeitet bietet es sich an eine eigene Registry zu hosten oder hosten zu lassen. Bekannte Open-Source Registries sind zum Beispiel Harbor oder Gitlab.

Was ist ein Dockerfile?

Wie weiter oben bereits erwähnt sind Images statisch. Aber wie passt man dann ein Image an, erstellt ein neues und führt dieses schlussendlich aus?

Der einfachste Weg, um ein neues Docker Image zu erstellen, ist über die Verwendung eines sogenannten „Dockerfile“. Dabei handelt es sich um eine Datei, welche als Bauanleitung für ein Image funktioniert. Zeile für Zeile werden Anweisungen gegeben, welche dann jeweils ein neues Layer im zukünftigen Image bilden.

Der Start eines Dockerfiles ist üblicherweise der Verweis auf ein Base-Image als Basis des neuen zu bauenden Images. In weiteren Anweisungen könnte dann unter anderem Dateien hinzugefügt, Netzwerkfunktionalität wie verfügbare Ports eingerichtet werden und Anwendungen und Bibliotheken installiert werden. Der letzte Schritt im Dockerfile ist üblicherweise die Definition eines Befehles, der sogenannte Entrypoint, der beim Start des Images standardmäßig ausgeführt werden soll. Mit dem Befehl `docker build` wird auf Basis dieses Dockerfiles dann ein neues Image gebaut, welches lokal gespeichert wird und direkt verwendet oder in einer Registry hochgeladen werden kann.

Ein fiktives Dockerfile für einen selbst programmierten Microservice in NodeJS könnte beispielsweise zunächst als Base Image eine Ubuntu Variante definieren. Im nächsten Schritt würde dann die Installation von NodeJS und weiterer benötigter Abhängigkeiten definiert. Anschließend würde man die Javascript Dateien für das Programm hinzufügen lassen und den benötigten Port freigeben. Zuletzt würde man als Entrypoint des Images den Startbefehl für den Microservice definieren. Mit nur wenigen Zeilen hat man so eine eigene Anwendung erfolgreich containerisiert.

Was ist zu beachten?

Zu guter Letzt hier noch ein paar Tipps und Tricks:

  • Idealerweise sollte nur ein Service bzw. Prozess pro Container implementiert werden. Ausnahmen von der Regelung machen dann Sinn, wenn Applikationen eng miteinander verwoben bzw. voneinander abhängig sind. Beispielsweise kann es bei PHP sinnvoll sein nginx und php-fpm im selben Container zu haben.
  • Es sollten keine Nutzdaten, also zu persistierende Daten im Container bzw. im Container Image gespeichert werden. Auf Grund der bereits erwähnten Unveränderbarkeit von Container Images verschwinden beim Beenden bzw. beim Neu-Deployment von Containern auch alle Daten, die innerhalb der Laufzeit erzeugt wurden. Für Nutzungsdaten lassen sich externe Volumen einbinden, sowohl um einem Container schon beim Start mit benötigten Daten zu versorgen als auch um neue Daten über die Laufzeit des Containers hinaus zu erhalten. Dasselbe Volumen kann auch bei neuen Deployments des Containers (z.B. mit einem aktualisierten Image) erneut eingebunden werden.
  • Am meisten profitieren Sie vom Betrieb von Anwendungen mit Docker, wenn Sie diese gezielt für den Betrieb mit Containern und Container-Orchestrierung konzipieren. Eine Microservice Architektur ist häufig empfehlenswert.
  • Die Entwicklung und der Betrieb von Anwendungen mit Docker funktioniert hervorragend in Kombination mit der Umsetzung von DevOps Prinzipien und dem Einsatz von Cloud Nativem Tooling. Die Nutzung von CI (Continous Integration) und CD (Continous Deployment) durch Gitlab Pipelines und ArgoCD ist beispielsweise ein empfehlenswerter Ansatz. Mit den genannten Tools in petto und der Berücksichtigung einiger Do‘s and Don’ts erhält man eine sehr moderne, dynamische und hochskalierende Umgebung.

Die Managed Container Services von Claranet bieten maßgeschneiderte Lösungen für die Verwaltung und den Betrieb von containerisierten Applikationen.