Blog
Tiefes Eintauchen in Windows Server Containers und Docker - Teil 2 - Grundlegende Implementierung von Windows Server Containers

Mit der Einführung von Windows Server 2016 Technical Preview 3 im August 2015 aktivierte Microsoft die Container-Technologie auf der Windows-Plattform. Während Linux seit August 2008 über seine Container-Technologie verfügte, wurde eine solche Funktionalität auf Microsoft-Betriebssystemen zuvor nicht unterstützt. Dank des Erfolgs von Docker unter Linux beschloss Microsoft vor fast 3 Jahren, mit der Arbeit an einer Container-Implementierung für Windows zu beginnen. Seit September 2016 können wir mit einer öffentlich freigegebenen Version dieser neuen Container-Technologie in Windows Server 2016 und Windows 10 arbeiten. Aber was ist der Unterschied zwischen Containern und VMs? Und wie werden Windows-Container intern in der Windows-Architektur implementiert? In diesem Blogpost gehen wir auf die grundlegende Implementierung von Containern unter Windows ein.
Container vs. VMs
Viele Einführungen in Container beginnen mit dem Satz "Container sind leichtgewichtige VMs". Obwohl dies den Menschen helfen kann, ein konzeptionelles Verständnis davon zu bekommen, was Container sind, ist es wichtig zu beachten, dass diese Aussage zu 100% falsch ist und sehr verwirrend sein kann. Container sind etwas anderes als VMs und das ist der Grund, warum ich Container immer als "etwas anderes als VMs" einführe oder sogar sage, dass "Container KEINE VMs sind". Aber was ist dieser Unterschied? Und warum ist dieser Unterschied so wichtig?
Was Container und VMs gemeinsam haben
Container sind zwar KEINE VMs, aber sie haben drei wichtige Eigenschaften gemeinsam:
- Isolierte Umgebung: Wie bei VMs sorgen Container für ein Dateisystem, Umgebungsvariablen, eine Registrierung und Prozessisolierung zwischen Anwendungen. Das bedeutet, dass wie bei VMs jeder Container eine isolierte Umgebung für alle seine internen Anwendungen schafft. Bei der Bewegung versiegeln sowohl Container als auch VMs nicht nur die internen Anwendungen, sondern auch den Kontext um diese Anwendungen herum.
- Verschieben zwischen Hosts: Ein großer Vorteil bei der Arbeit mit VMs besteht darin, dass wir die VM-Snapshots über verschiedene Host-Hypervisoren verschieben können, ohne den Inhalt ändern zu müssen. Das Gleiche gilt für Container. Während VMs über verschiedene Host-Hypervisoren hinweg "verschoben" werden können, können Container über verschiedene Container-Hosts hinweg "verschoben" werden. Während beide Artefakte über verschiedene Hosts "verschoben" werden, bleibt der Inhalt der VM/des Containers genau so erhalten wie die Implementierung auf den vorherigen Hosts.
- Ressourcensteuerung: Ein weiteres gemeinsames Merkmal ist, dass die verfügbaren Ressourcen (CPU, RAM, Netzwerkbandbreite) sowohl eines Containers als auch einer VM auf einen bestimmten Wert begrenzt werden können. In beiden Fällen kann diese Ressourcensteuerung nur auf dem Container-Host oder Hypervisor eingestellt werden. Die Ressourcensteuerung stellt sicher, dass ein Container nur begrenzte Ressourcen erhält, um das Risiko zu minimieren, dass er die Leistung anderer Container, die auf demselben Host laufen, beeinträchtigt. Für einen Container kann beispielsweise festgelegt werden, dass er nicht mehr als 10 % der CPU nutzen darf.
Unterschiede zwischen Containern und VMs
Container und VMs haben zwar einige Eigenschaften gemeinsam, aber es gibt auch einige wichtige Unterschiede zwischen Containern und VMs.
- Stufe der Virtualisierung: Container sind eine neue Stufe der Virtualisierung. Betrachtet man die Geschichte der Virtualisierung, so begann sie mit Konzepten wie virtuellem Speicher und virtuellen Maschinen. Container sind die nächste Stufe dieses Virtualisierungstrends. Wo VMs ein Ergebnis der Hardwarevirtualisierung sind, sind Container ein Ergebnis der Betriebssystemvirtualisierung. Das bedeutet, dass die Hardwarevirtualisierung die VM glauben lässt, dass ihre Hardwareressourcen für diese Instanz bestimmt sind, während die Betriebssystemvirtualisierung den Container glauben lässt, dass die Betriebssysteminstanz für diesen Container bestimmt ist. Dieser Unterschied in der Virtualisierung ist wichtig zu beachten. Container haben zum Beispiel keinen eigenen Kernel-Modus. Aus diesem Grund können Container nicht als VMs angesehen werden und werden auch vom Betriebssystem nicht als VMs erkannt (Sie können es selbst mit dem PowerShell-Befehl Get-VM ausprobieren). Eine gute Analogie, um diesen Unterschied zu erklären, ist die von Häusern (VMs) und Wohngebäuden (Containern). Häuser (die VMs) sind vollständig in sich abgeschlossen und bieten Schutz vor ungebetenen Gästen. Sie verfügen außerdem über eine eigene Infrastruktur - Wasserleitungen, Heizung, Strom usw. Wohnungen (die Container) bieten ebenfalls Schutz vor ungebetenen Gästen, sind aber auf einer gemeinsamen Infrastruktur aufgebaut. Das Apartmenthaus (der Docker-Host) teilt sich die Sanitäranlagen, die Heizung, die Elektrik, usw. Auch wenn beide einige Eigenschaften gemeinsam haben, sind sie doch unterschiedliche Einheiten.
- Umgang mit dem Betriebssystem: Ein weiterer wichtiger Unterschied zwischen Containern und VMs ist die Art und Weise, wie beide Artefakte mit dem Kernel-Modus umgehen. Während VMs über ein vollständiges Betriebssystem (und einen eigenen Kernel-Modus) verfügen, teilen sich Container das "Betriebssystem (eigentlich den Kernel-Modus)" mit anderen Containern und dem Container-Host. Daher sollten sich Container an das Betriebssystem des Container-Hosts anpassen, während VMs sich das Betriebssystem (Version und Typ) aussuchen können, das ihnen gefällt. Während VMs in der Lage sind, ein Linux-Betriebssystem auf einem Windows-Hypervisor auszuführen, ist es mit der Container-Technologie nicht möglich, einen Linux-Container auf einem Windows-Container-Host auszuführen und umgekehrt.
- Wachstumsmodell: Container nutzen die zugrunde liegenden Ressourcen des Container-Hosts gemeinsam und erstellen ein Image, das genau dem entspricht, was Sie zum Ausführen Ihrer Anwendung benötigen. Sie beginnen mit den Grundlagen und fügen hinzu, was Sie brauchen. VMs werden in umgekehrter Richtung aufgebaut. Meistens beginnen wir mit einem vollständigen Betriebssystem und entfernen je nach Anwendung die Dinge, die wir nicht benötigen.
Windows Server-Container
Nachdem wir nun die Unterschiede zwischen VMs und Containern kennen, lassen Sie uns ein wenig tiefer in die zugrunde liegende Architektur von Windows Server Containern eintauchen. Um zu erklären, wie Container innerhalb des Windows-Betriebssystems implementiert sind, müssen Sie zwei wichtige Konzepte kennen: Benutzermodus und Kernelmodus. Beides sind verschiedene Modi, zwischen denen ein Prozessor ständig wechselt, je nachdem, welche Art von Code er ausführen muss.
Kernel-Modus
Der Kernel-Modus eines Betriebssystems wurde für Treiber implementiert, die uneingeschränkten Zugriff auf die zugrunde liegende Hardware haben müssen. Normale Programme (Benutzermodus) müssen die APIs des Betriebssystems nutzen, um auf Hardware oder Speicher zuzugreifen. Code, der im Kernel-Modus ausgeführt wird, hat direkten Zugriff auf diese Ressourcen und nutzt dieselben Speicherplätze/virtuellen Adressräume wie das Betriebssystem und andere Kernel-Treiber. Die Ausführung von Code in diesem Kernel-Modus ist daher sehr riskant, da Daten, die dem Betriebssystem oder einem anderen Treiber gehören, gefährdet werden könnten, wenn Ihr Kernel-Modus-Code versehentlich Daten an eine falsche virtuelle Adresse schreibt. Wenn ein Kernel-Modus-Treiber abstürzt, stürzt das gesamte Betriebssystem ab. Die Ausführung von Code innerhalb des Kernelbereichs sollte daher so wenig wie möglich erfolgen. Das ist genau der Grund, warum der Benutzermodus eingeführt wurde.
Benutzer-Modus
Im Benutzermodus läuft der Code immer in einem separaten Prozess (Benutzerbereich), der über eine eigene Gruppe von Speicherplätzen verfügt (privater virtueller Adressraum). Da der virtuelle Adressraum jeder Anwendung privat ist, kann eine Anwendung keine Daten verändern, die einer anderen Anwendung gehören. Jede Anwendung läuft isoliert, und wenn eine Anwendung abstürzt, ist der Absturz auf diese eine Anwendung beschränkt. Der virtuelle Adressraum einer Anwendung, die im Benutzermodus läuft, ist nicht nur privat, sondern auch begrenzt. Ein Prozessor, der im Benutzermodus läuft, kann nicht auf virtuelle Adressen zugreifen, die für das Betriebssystem reserviert sind. Durch die Begrenzung des virtuellen Adressraums einer Anwendung im Benutzermodus wird verhindert, dass die Anwendung wichtige Daten des Betriebssystems verändert und möglicherweise beschädigt.
Technische Implementierung von Windows-Containern
Aber was haben diese Prozessormodi mit Containern zu tun? Jeder Container ist lediglich ein Prozessor-"Benutzermodus" mit ein paar zusätzlichen Funktionen wie Namespace-Isolierung, Ressourcenverwaltung und dem Konzept eines Unionsdateisystems. Das bedeutet, dass Microsoft das Windows-Betriebssystem anpassen musste, damit es mehrere Benutzermodi unterstützen kann. Etwas, das sehr schwierig war, wenn man bedenkt, wie stark beide Modi in früheren Windows-Versionen integriert waren. Vor der Einführung von Windows Server 2016 bestand jedes Windows-Betriebssystem, das wir verwendeten, aus einem einzigen "User Mode" und einem "Kernel Mode". Seit der Einführung von Windows Server 2016 ist es möglich, mehrere Benutzermodi innerhalb desselben Betriebssystems laufen zu lassen. Das folgende Diagramm gibt einen Überblick über diese neue Architektur mit mehreren Benutzermodi. Wenn wir uns die Benutzermodi von Windows Server 2016 ansehen, können wir zwei verschiedene Typen identifizieren: den Host-Benutzermodus und die Container-Benutzermodi (grüne Blöcke im Diagramm). Der Host-Benutzermodus ist identisch mit dem normalen Benutzermodus, den wir aus früheren Versionen von Windows kennen. Ziel dieses Benutzermodus ist es, die wichtigsten Windows-Dienste und -Prozesse wie den Session Manager, den Event Manager und das Netzwerk zu hosten. Darüber hinaus erleichtert dieser Benutzermodus im Falle der Windows Server Core-Implementierung die Benutzerinteraktion über eine Benutzeroberfläche mit Windows Server 2016. Eine neue Funktion von Windows Server 2016 ist, dass dieser Host-Benutzermodus einige zusätzliche Container-Verwaltungstechnologien enthält, die sicherstellen, dass Container unter Windows funktionieren. Das Herzstück dieser Containertechnologie ist die Abstraktion der Computerdienste (orangefarbener Block), die die vom Kernel bereitgestellten Low-Level-Container-Funktionen über eine öffentliche API zugänglich macht. Tatsächlich enthalten diese Dienste nur Funktionen zum Starten von Windows-Containern, zur Verfolgung der Container während ihrer Ausführung und zur Verwaltung der für den Neustart erforderlichen Funktionen. Der Rest der Container-Verwaltungsfunktionen ist in der Docker-Engine implementiert, z.B. die Verfolgung aller Container, die Speicherung von Container-Images, Volumes usw. Diese Engine kommuniziert direkt mit den Container-APIs der Compute Services und nutzt dazu die von Microsoft angebotene "Go-Sprachbindung".
Der Unterschied zwischen Windows- und Linux-Containern
Obwohl die gleichen Docker-Client-Tools (Docker Compose, Docker Swarm) sowohl native Windows- als auch Linux-Container verwalten können, gibt es einige wichtige Unterschiede zwischen der Implementierung von Containern unter Windows und Linux.
System-Prozesse
Während Linux seine Funktionen auf der Kernel-Ebene über Syscalls offenlegt, hat Microsoft beschlossen, seine ausgehenden Funktionen im Kernel-Modus über DLLs zu steuern (dies ist auch der Grund, warum Microsoft seine Syscalls nicht wirklich dokumentiert hat). Obwohl diese Art der Abstraktion von Syscalls einige Vorteile hat, hat sie zu einem hoch integrierten Windows-Betriebssystem mit vielen Abhängigkeiten zwischen verschiedenen Win32-DLLs und der Erwartung vieler DLLs geführt, dass einige (un)direkt referenzierte Systemdienste laufen. Daher ist es in Windows-Containern nicht sehr realistisch, nur die Anwendungsprozesse laufen zu lassen, die wir in unserer Dockerdatei gestartet haben. In Windows-Containern werden Sie daher einen Haufen zusätzlicher Systemprozesse sehen, während in Linux-Containern nur die angegebenen Anwendungsprozesse laufen müssen. Um sicherzustellen, dass diese notwendigen Systemprozesse und Dienste im Windows-Container laufen, wird in jedem Container ein sogenannter smss-Prozess gestartet. Das Ziel dieses smss-Prozesses ist es, die notwendigen Systemprozesse und Dienste zu starten.
OS Architektur
Nicht nur bei der Offenlegung der Kernel-Ebene, sondern auch auf architektonischer Ebene gibt es einen wichtigen Unterschied in der Art und Weise, wie beide Betriebssysteme die Container-Funktionen für die Docker-Client-Tools bereitstellen. In der aktuellen Container-Implementierung von Windows Server 2016 ist eine so genannte Compute Services-Abstraktionsschicht implementiert, die die Low-Level-Container-Funktionen nach außen hin abstrahiert. Der Grund dafür ist, dass Microsoft die Low-Level-Container-APIs ändern kann, ohne die öffentlichen APIs ändern zu müssen, die von der Docker Engine oder anderen Container-Client-Tools aufgerufen werden. Für diese Compute Services APIs können Sie Ihre eigenen Container-Verwaltungstools programmieren, indem Sie die C#- oder GO-Sprachbindung verwenden, die unter DotNet Compute Virtualization und Github.com/Microsoft/hcsshim verfügbar sind.
Union File System?
Ein dritter wichtiger Unterschied zwischen den Container-Implementierungen von Linux und Windows ist die Art und Weise, wie beide Betriebssysteme mit der "Copy-on-Write"-Technologie von Docker umgehen. Da viele Windows-Anwendungen NTFS-Semantik erwarten, war es für das Microsoft-Team schwierig, eine vollständige Union File System-Implementierung unter Windows zu erstellen. Für Funktionen wie USN-Journale und Transaktionen würde dies beispielsweise eine völlig neue Implementierung erfordern. Die aktuelle Windows Server 2016 Container-Implementierung enthält daher kein echtes Union-Dateisystem. Stattdessen erstellt die aktuelle Implementierung eine neue virtuelle NTFS-Festplatte pro Container. Um diese virtuellen Laufwerke klein zu halten, sind die verschiedenen Dateisystemeinträge innerhalb dieser virtuellen NTFS-Laufwerke wesentliche Symlinks zu echten Dateien auf dem Dateisystem des Container-Hosts. Sobald Sie Dateien innerhalb eines Containers ändern, werden diese Dateien in einem virtuellen Blockdevice gespeichert. In dem Moment, in dem Sie die Änderungen festschreiben möchten, werden diese Änderungen aus dem virtuellen Blockdevice herausgezogen und im richtigen Dateisystem des Container-Hosts gespeichert.
Hyper-V Container
Ein letzter Unterschied zwischen der Linux- und der Windows-Container-Implementierung ist das Konzept der Hyper-V-Container. Über diese interessante Art von Containern werde ich im nächsten Blogpost dieser Serie berichten. Bleiben Sie dran...
Mehr aus dieser Serie
- Deep Dive into Windows Server Containers and Docker Part 1: Why Should We Care?
- Deep Dive into Windows Server Containers and Docker Part 2: Underlying Implementation of Windows Server Containers
- Deep Dive into Windows Server Containers and Docker Part 3: Underlying Implementation of Hyper-V Containers
Verfasst von
Cornell Knulst
Cornell works for Xpirit, Hilversum, The Netherlands, as a trainer/architect. He is specialized in the domain of Application Lifecycle Management and Continuous Delivery, with a special focus on Microsoft-based technologies.
Unsere Ideen
Weitere Blogs
Contact



