Eine anfängerfreundliche Einführung in Container, VMs und Docker

Wenn Sie Programmierer oder Technikfreak sind, haben Sie wahrscheinlich zumindest von Docker gehört: einem hilfreichen Tool zum Verpacken, Versenden und Ausführen von Anwendungen in „Containern“. Es ist schwer, dies nicht zu tun, bei all der Aufmerksamkeit, die es heutzutage bekommt - von Entwicklern und Systemadministratoren gleichermaßen. Sogar die großen Hunde wie Google, VMware und Amazon bauen Dienste auf, um dies zu unterstützen.

Unabhängig davon, ob Sie einen unmittelbaren Anwendungsfall für Docker im Auge haben oder nicht, denke ich immer noch, dass es wichtig ist, einige der grundlegenden Konzepte zu verstehen, was ein „Container“ ist und wie er mit einer virtuellen Maschine (VM) verglichen wird. Während das Internet voll von hervorragenden Anleitungen für Docker ist, konnte ich nicht viele anfängerfreundliche konzeptionelle Anleitungen finden, insbesondere nicht, woraus ein Container besteht. Hoffentlich löst dieser Beitrag das Problem :)

Beginnen wir damit, zu verstehen, was VMs und Container überhaupt sind.

Was sind "Container" und "VMs"?

Container und VMs haben ähnliche Ziele: eine Anwendung und ihre Abhängigkeiten in einer eigenständigen Einheit zu isolieren, die überall ausgeführt werden kann.

Darüber hinaus machen Container und VMs keine physische Hardware mehr erforderlich, wodurch die Rechenressourcen sowohl hinsichtlich des Energieverbrauchs als auch der Kosteneffizienz effizienter genutzt werden können.

Der Hauptunterschied zwischen Containern und VMs liegt in ihrem architektonischen Ansatz. Lass uns genauer hinschauen.

Virtuelle Maschinen

Eine VM ist im Wesentlichen eine Emulation eines realen Computers, der Programme wie ein realer Computer ausführt. VMs werden mithilfe eines „Hypervisors“ auf einem physischen Computer ausgeführt . Ein Hypervisor läuft wiederum entweder auf einem Host-Computer oder auf „Bare-Metal“ .

Packen wir den Jargon aus:

Ein Hypervisor ist eine Software, Firmware oder Hardware, auf der VMs ausgeführt werden. Die Hypervisoren selbst laufen auf physischen Computern, die als "Host-Computer" bezeichnet werden . Der Hostcomputer stellt den VMs Ressourcen zur Verfügung, einschließlich RAM und CPU. Diese Ressourcen werden auf VMs aufgeteilt und können nach Belieben verteilt werden. Wenn auf einer VM eine ressourcenintensivere Anwendung ausgeführt wird, können Sie dieser mehr Ressourcen zuweisen als den anderen VMs, die auf demselben Hostcomputer ausgeführt werden.

Die VM, die auf dem Hostcomputer ausgeführt wird (wiederum unter Verwendung eines Hypervisors), wird häufig auch als "Gastcomputer" bezeichnet. Dieser Gastcomputer enthält sowohl die Anwendung als auch alles, was zum Ausführen dieser Anwendung erforderlich ist (z. B. Systembinärdateien und Bibliotheken). Es verfügt außerdem über einen eigenen eigenen virtualisierten Hardwarestapel, einschließlich virtualisierter Netzwerkadapter, Speicher und CPU. Dies bedeutet, dass es auch über ein eigenes vollwertiges Gastbetriebssystem verfügt. Von innen verhält sich der Gastcomputer wie eine eigene Einheit mit eigenen dedizierten Ressourcen. Von außen wissen wir, dass es sich um eine VM handelt, die vom Host-Computer bereitgestellte Ressourcen gemeinsam nutzt.

Wie oben erwähnt, kann ein Gastcomputer entweder auf einem gehosteten Hypervisor oder einem Bare-Metal-Hypervisor ausgeführt werden . Es gibt einige wichtige Unterschiede zwischen ihnen.

Zunächst wird ein gehosteter Virtualisierungshypervisor auf dem Betriebssystem des Hostcomputers ausgeführt. Auf einem Computer unter OSX kann beispielsweise eine VM (z. B. VirtualBox oder VMware Workstation 8) auf diesem Betriebssystem installiert sein. Die VM hat keinen direkten Zugriff auf Hardware, daher muss sie das Host-Betriebssystem (in unserem Fall das OSX des Mac) durchlaufen.

Der Vorteil eines gehosteten Hypervisors besteht darin, dass die zugrunde liegende Hardware weniger wichtig ist. Das Betriebssystem des Hosts ist für die Hardwaretreiber anstelle des Hypervisors selbst verantwortlich und wird daher als "Hardwarekompatibler" eingestuft. Andererseits verursacht diese zusätzliche Schicht zwischen der Hardware und dem Hypervisor mehr Ressourcenaufwand, was die Leistung der VM verringert.

Eine Bare-Metal-Hypervisor-Umgebung behebt das Leistungsproblem, indem sie auf der Hardware des Host-Computers installiert und von dieser ausgeführt wird. Da es direkt mit der zugrunde liegenden Hardware verbunden ist, muss kein Host-Betriebssystem ausgeführt werden. In diesem Fall wird als erstes der Hypervisor auf dem Server eines Hostcomputers als Betriebssystem installiert. Im Gegensatz zum gehosteten Hypervisor verfügt ein Bare-Metal-Hypervisor über eigene Gerätetreiber und interagiert mit jeder Komponente direkt für E / A-, Verarbeitungs- oder betriebssystemspezifische Aufgaben. Dies führt zu einer besseren Leistung, Skalierbarkeit und Stabilität. Der Nachteil hierbei ist, dass die Hardwarekompatibilität begrenzt ist, da im Hypervisor nur so viele Gerätetreiber integriert sein können.

Nach all dem Gerede über Hypervisoren fragen Sie sich vielleicht, warum wir diese zusätzliche „Hypervisor“ -Schicht zwischen der VM und dem Host-Computer überhaupt benötigen .

Da die VM über ein eigenes virtuelles Betriebssystem verfügt, spielt der Hypervisor eine wesentliche Rolle bei der Bereitstellung einer Plattform für die Verwaltung und Ausführung dieses Gastbetriebssystems für die VMs. Auf diese Weise können Host-Computer ihre Ressourcen auf die virtuellen Maschinen verteilen, die als Gäste auf ihnen ausgeführt werden.

Wie Sie im Diagramm sehen können, packen VMs die virtuelle Hardware, einen Kernel (dh das Betriebssystem) und den Benutzerbereich für jede neue VM zusammen.

Container

Im Gegensatz zu einer VM, die Hardwarevirtualisierung bereitstellt, bietet ein Container eine Virtualisierung auf Betriebssystemebene, indem der „Benutzerbereich“ abstrahiert wird. Sie werden sehen, was ich meine, wenn wir den Begriff Container auspacken .

Container sehen in jeder Hinsicht wie eine VM aus. Zum Beispiel haben sie privaten Speicherplatz für die Verarbeitung, können Befehle als root ausführen, haben eine private Netzwerkschnittstelle und IP-Adresse, erlauben benutzerdefinierte Routen und iptable-Regeln, können Dateisysteme mounten und so weiter.

Der einzige große Unterschied zwischen Containern und VMs besteht darin, dass Container den Kernel des Hostsystems mit anderen Containern * teilen *.

Dieses Diagramm zeigt Ihnen, dass Container nur den Benutzerbereich und nicht den Kernel oder die virtuelle Hardware wie eine VM zusammenfassen. Jeder Container erhält einen eigenen isolierten Benutzerbereich, damit mehrere Container auf einem einzelnen Hostcomputer ausgeführt werden können. Wir können sehen, dass die gesamte Architektur auf Betriebssystemebene von Containern gemeinsam genutzt wird. Die einzigen Teile, die von Grund auf neu erstellt werden, sind die Bins und Libs. Das macht Container so leicht.

Wo kommt Docker ins Spiel?

Docker ist ein Open-Source-Projekt, das auf Linux-Containern basiert. Es verwendet Linux-Kernel-Funktionen wie Namespaces und Kontrollgruppen, um Container auf einem Betriebssystem zu erstellen.

Container sind alles andere als neu; Google verwendet seit Jahren eine eigene Containertechnologie. Andere Linux-Containertechnologien umfassen Solaris Zones, BSD-Jails und LXC, die es schon seit vielen Jahren gibt.

Warum gewinnt Docker plötzlich an Fahrt?

1. Benutzerfreundlichkeit: Docker hat es jedem - Entwicklern, Systemadministratoren, Architekten und anderen - viel einfacher gemacht, Container zu nutzen, um schnell tragbare Anwendungen zu erstellen und zu testen. Es ermöglicht jedem, eine Anwendung auf seinem Laptop zu verpacken, die wiederum unverändert in jeder öffentlichen Cloud, privaten Cloud oder sogar Bare Metal ausgeführt werden kann. Das Mantra lautet: "Einmal bauen, überall laufen."

2. Geschwindigkeit: Docker-Container sind sehr leicht und schnell. Da Container nur Sandbox-Umgebungen sind, die auf dem Kernel ausgeführt werden, beanspruchen sie weniger Ressourcen. Sie können einen Docker-Container in Sekunden erstellen und ausführen, verglichen mit VMs, die möglicherweise länger dauern, da sie jedes Mal ein vollständiges virtuelles Betriebssystem starten müssen.

3. Docker Hub: Docker-Benutzer profitieren auch von dem immer umfangreicheren Ökosystem von Docker Hub, das Sie sich als „App Store für Docker-Images“ vorstellen können. Docker Hub verfügt über Zehntausende von öffentlichen Bildern, die von der Community erstellt wurden und sofort zur Verfügung stehen. Es ist unglaublich einfach, nach Bildern zu suchen, die Ihren Anforderungen entsprechen. Sie können heruntergezogen und mit nur geringen bis keinen Änderungen verwendet werden.

4. Modularität und Skalierbarkeit: Mit Docker können Sie die Funktionalität Ihrer Anwendung auf einfache Weise in einzelne Container aufteilen. Beispielsweise könnte Ihre Postgres-Datenbank in einem Container und Ihr Redis-Server in einem anderen ausgeführt werden, während sich Ihre Node.js-App in einem anderen befindet. Mit Docker ist es einfacher geworden, diese Container miteinander zu verknüpfen, um Ihre Anwendung zu erstellen, sodass Komponenten in Zukunft problemlos unabhängig skaliert oder aktualisiert werden können.

Zu guter Letzt, wer liebt den Docker-Wal nicht? ;)

Grundlegende Docker-Konzepte

Nachdem wir das Gesamtbild verstanden haben, gehen wir Stück für Stück die grundlegenden Teile von Docker durch:

Docker Engine

Die Docker-Engine ist die Ebene, auf der Docker ausgeführt wird. Es ist eine einfache Laufzeit und ein Tool, das Container, Images, Builds und mehr verwaltet. Es läuft nativ auf Linux-Systemen und besteht aus:

1. Ein Docker-Daemon, der auf dem Host-Computer ausgeführt wird.

2. Ein Docker-Client, der dann mit dem Docker-Daemon kommuniziert, um Befehle auszuführen.

3. Eine REST-API für die Remote-Interaktion mit dem Docker Daemon.

Docker Client

Mit dem Docker-Client kommunizieren Sie als Endbenutzer von Docker. Stellen Sie sich das als Benutzeroberfläche für Docker vor. Zum Beispiel, wenn Sie ...

Sie kommunizieren mit dem Docker-Client, der dann Ihre Anweisungen an den Docker-Daemon übermittelt.

Docker Daemon

Der Docker-Daemon führt tatsächlich Befehle aus, die an den Docker-Client gesendet werden - wie das Erstellen, Ausführen und Verteilen Ihrer Container. Der Docker-Daemon wird auf dem Host-Computer ausgeführt, aber als Benutzer kommunizieren Sie niemals direkt mit dem Daemon. Der Docker-Client kann auch auf dem Host-Computer ausgeführt werden, ist jedoch nicht erforderlich. Es kann auf einem anderen Computer ausgeführt werden und mit dem Docker-Daemon kommunizieren, der auf dem Hostcomputer ausgeführt wird.

Dockerfile

In einer Docker-Datei schreiben Sie die Anweisungen zum Erstellen eines Docker-Images. Diese Anweisungen können sein:

  • RUN apt-get y install some-package : um ein Softwarepaket zu installieren
  • EXPOSE 8000: Zum Freilegen eines Ports
  • ENV ANT_HOME / usr / local / apache-ant zum Übergeben einer Umgebungsvariablen

und so weiter. Sobald Sie Ihre Docker-Datei eingerichtet haben, können Sie mit dem Docker-Build- Befehl ein Image daraus erstellen. Hier ist ein Beispiel für eine Docker-Datei:

Docker Image

Bilder sind schreibgeschützte Vorlagen, die Sie aus einer Reihe von Anweisungen erstellen, die in Ihrer Docker-Datei geschrieben sind. Bilder definieren sowohl, wie Ihre gepackte Anwendung aussehen soll, als auch ihre Abhängigkeiten * und * welche Prozesse beim Start ausgeführt werden sollen.

Das Docker-Image wird mithilfe einer Docker-Datei erstellt. Jede Anweisung in der Docker-Datei fügt dem Bild eine neue „Ebene“ hinzu, wobei Ebenen einen Teil des Bilddateisystems darstellen, der die darunter liegende Ebene entweder ergänzt oder ersetzt. Ebenen sind der Schlüssel zu Dockers leichter und dennoch leistungsstarker Struktur. Docker verwendet dazu ein Union-Dateisystem:

Union-Dateisysteme

Docker verwendet Union File Systems, um ein Image zu erstellen. Sie können sich ein Union-Dateisystem als ein stapelbares Dateisystem vorstellen, dh Dateien und Verzeichnisse separater Dateisysteme (sogenannte Zweige) können transparent überlagert werden, um ein einziges Dateisystem zu bilden.

Der Inhalt von Verzeichnissen, die innerhalb der überlagerten Zweige denselben Pfad haben, wird als ein einziges zusammengeführtes Verzeichnis betrachtet, sodass keine separaten Kopien jeder Ebene erstellt werden müssen. Stattdessen können sie alle Zeiger auf dieselbe Ressource erhalten. Wenn bestimmte Ebenen geändert werden müssen, wird eine Kopie erstellt und eine lokale Kopie geändert, wobei das Original unverändert bleibt. Auf diese Weise können Dateisysteme beschreibbar erscheinen, ohne dass Schreibvorgänge zulässig sind. (Mit anderen Worten, ein "Copy-on-Write" -System.)

Schichtsysteme bieten zwei Hauptvorteile:

1. Ohne Duplizierung: Mithilfe von Ebenen können Sie vermeiden, dass jedes Mal, wenn Sie ein Image zum Erstellen und Ausführen eines neuen Containers verwenden, ein vollständiger Satz von Dateien dupliziert wird. Dadurch wird die Instanziierung von Docker-Containern sehr schnell und kostengünstig.

2. Ebenentrennung: Das Ändern ist viel schneller. Wenn Sie ein Bild ändern, gibt Docker die Aktualisierungen nur an die Ebene weiter, die geändert wurde.

Bände

Volumes sind der "Daten" -Teil eines Containers, der beim Erstellen eines Containers initialisiert wird. Mit Volumes können Sie die Daten eines Containers beibehalten und freigeben. Datenvolumes sind vom Standard-Union-Dateisystem getrennt und existieren als normale Verzeichnisse und Dateien auf dem Host-Dateisystem. Selbst wenn Sie Ihren Container zerstören, aktualisieren oder neu erstellen, bleiben die Datenmengen unberührt. Wenn Sie ein Volume aktualisieren möchten, nehmen Sie Änderungen direkt daran vor. (Als zusätzlichen Bonus können Datenmengen von mehreren Containern gemeinsam genutzt und wiederverwendet werden, was ziemlich ordentlich ist.)

Docker-Container

Ein Docker-Container, wie oben beschrieben, verpackt die Software einer Anwendung in eine unsichtbare Box mit allem, was die Anwendung zum Ausführen benötigt. Dazu gehören das Betriebssystem, der Anwendungscode, die Laufzeit, Systemtools, Systembibliotheken usw. Docker-Container werden aus Docker-Images erstellt. Da Bilder schreibgeschützt sind, fügt Docker dem schreibgeschützten Dateisystem des Bildes ein Lese- / Schreibdateisystem hinzu, um einen Container zu erstellen.

Darüber hinaus erstellt Docker beim Erstellen des Containers eine Netzwerkschnittstelle, damit der Container mit dem lokalen Host kommunizieren kann, eine verfügbare IP-Adresse an den Container anfügt und den Prozess ausführt, den Sie zum Ausführen Ihrer Anwendung beim Definieren des Images angegeben haben.

Sobald Sie einen Container erfolgreich erstellt haben, können Sie ihn in jeder Umgebung ausführen, ohne Änderungen vornehmen zu müssen.

Doppelklicken Sie auf "Container".

Puh! Das sind viele bewegliche Teile. Eine Sache, die mich immer neugierig gemacht hat, war, wie ein Container tatsächlich implementiert wird, zumal es keine abstrakte Infrastrukturgrenze um einen Container gibt. Nach vielem Lesen macht alles Sinn, also hier ist mein Versuch, es Ihnen zu erklären! :) :)

Der Begriff „Container“ ist eigentlich nur ein abstraktes Konzept, um zu beschreiben, wie einige verschiedene Funktionen zusammenarbeiten, um einen „Container“ zu visualisieren. Lassen Sie uns sie ganz schnell durchgehen:

1) Namespaces

Namespaces bieten Containern eine eigene Ansicht des zugrunde liegenden Linux-Systems, wodurch die Sichtbarkeit und der Zugriff des Containers eingeschränkt werden. Wenn Sie einen Container ausführen, erstellt Docker Namespaces, die der jeweilige Container verwendet.

Es gibt verschiedene Arten von Namespaces in einem Kernel, die Docker verwendet, zum Beispiel:

ein. NET: Stellt einen Container mit einer eigenen Ansicht des Netzwerkstapels des Systems bereit (z. B. eigene Netzwerkgeräte, IP-Adressen, IP-Routing-Tabellen, Verzeichnis / proc / net, Portnummern usw.).

b. PID: PID steht für Process ID. Wenn Sie jemals ps aux in der Befehlszeile ausgeführt haben, um zu überprüfen, welche Prozesse auf Ihrem System ausgeführt werden, wird eine Spalte mit dem Namen "PID" angezeigt. Der PID-Namespace bietet Containern eine eigene Bereichsansicht von Prozessen, die sie anzeigen und mit denen sie interagieren können, einschließlich eines unabhängigen Init (PID 1), der der „Vorfahr aller Prozesse“ ist.

c. MNT: Gibt einem Container eine eigene Ansicht der "Halterungen" auf dem System. Prozesse in verschiedenen Mount-Namespaces haben also unterschiedliche Ansichten der Dateisystemhierarchie.

d. UTS: UTS steht für UNIX Timesharing System. Es ermöglicht einem Prozess, Systemkennungen (z. B. Hostname, Domänenname usw.) zu identifizieren. Mit UTS können Container ihren eigenen Hostnamen und NIS-Domänennamen haben, die unabhängig von anderen Containern und dem Hostsystem sind.

e. IPC: IPC steht für InterProcess Communication. Der IPC-Namespace ist dafür verantwortlich, IPC-Ressourcen zwischen Prozessen zu isolieren, die in jedem Container ausgeführt werden.

f. USER: Dieser Namespace wird verwendet, um Benutzer in jedem Container zu isolieren. Es ermöglicht Containern eine andere Ansicht der Bereiche uid (Benutzer-ID) und gid (Gruppen-ID) als das Host-System. Infolgedessen können die UID und GID eines Prozesses innerhalb und außerhalb eines Benutzernamensraums unterschiedlich sein. Dadurch kann ein Prozess auch einen nicht privilegierten Benutzer außerhalb eines Containers haben, ohne die Root-Berechtigungen innerhalb eines Containers zu beeinträchtigen.

Docker verwendet diese Namespaces zusammen, um einen Container zu isolieren und mit der Erstellung zu beginnen. Die nächste Funktion heißt Kontrollgruppen.

2) Kontrollgruppen

Kontrollgruppen (auch als cgroups bezeichnet) sind eine Linux-Kernelfunktion, die die Ressourcennutzung (CPU, Speicher, Festplatten-E / A, Netzwerk usw.) einer Reihe von Prozessen isoliert, priorisiert und berücksichtigt. In diesem Sinne stellt eine cgroup sicher, dass Docker-Container nur die benötigten Ressourcen verwenden - und legt bei Bedarf Grenzen für die Ressourcen fest, die ein Container * verwenden * kann. Cgroups stellen außerdem sicher, dass ein einzelner Container keine dieser Ressourcen erschöpft und das gesamte System herunterfährt.

Schließlich ist Union File Systems eine weitere Funktion, die Docker verwendet:

3) Isoliertes Union-Dateisystem:

Oben im Abschnitt Docker-Bilder beschrieben :)

Dies ist wirklich alles, was ein Docker-Container zu bieten hat (natürlich steckt der Teufel in den Implementierungsdetails - wie zum Beispiel die Verwaltung der Interaktionen zwischen den verschiedenen Komponenten).

Die Zukunft von Docker: Docker und VMs werden nebeneinander existieren

Während Docker sicherlich viel Dampf gewinnt, glaube ich nicht, dass es eine echte Bedrohung für VMs werden wird. Container werden weiter an Boden gewinnen, aber es gibt viele Anwendungsfälle, in denen VMs noch besser geeignet sind.

Wenn Sie beispielsweise mehrere Anwendungen auf mehreren Servern ausführen müssen, ist es wahrscheinlich sinnvoll, VMs zu verwenden. Wenn Sie jedoch viele * Kopien * einer einzelnen Anwendung ausführen müssen, bietet Docker einige überzeugende Vorteile.

Während Container es Ihnen ermöglichen, Ihre Anwendung in funktionalere diskrete Teile zu unterteilen, um eine Trennung der Probleme zu erreichen, bedeutet dies auch, dass eine wachsende Anzahl von Teilen verwaltet werden muss, was unhandlich werden kann.

Sicherheit war auch bei Docker-Containern ein Problem - da Container denselben Kernel verwenden, ist die Barriere zwischen Containern dünner. Während eine vollständige VM nur Hypercalls an den Host-Hypervisor senden kann, kann ein Docker-Container Syscalls an den Host-Kernel senden, wodurch eine größere Angriffsfläche entsteht. Wenn Sicherheit besonders wichtig ist, wählen Entwickler wahrscheinlich VMs aus, die durch abstrahierte Hardware isoliert sind, was es sehr viel schwieriger macht, sich gegenseitig zu stören.

Natürlich werden sich Probleme wie Sicherheit und Verwaltung mit Sicherheit weiterentwickeln, wenn Container in der Produktion mehr Aufmerksamkeit erhalten und von den Benutzern weiter geprüft werden. Im Moment ist die Debatte über Container vs. VMs wirklich am besten für Entwickler, die sie jeden Tag leben und atmen!

Fazit

Ich hoffe, Sie verfügen jetzt über das Wissen, das Sie benötigen, um mehr über Docker zu erfahren und es vielleicht eines Tages sogar in einem Projekt zu verwenden.

Schreiben Sie mir wie immer eine Zeile in den Kommentaren, wenn ich Fehler gemacht habe oder trotzdem hilfreich sein kann! :) :)