Alle Dienste, die der Server bereitstellt, sollen in ausführbare, in sich geschlossene Module verpackt werden, um das Deployment zu vereinfachen und reproduzierbar zu machen.
Zu allererst denkt man dabei vermutlich an eine klassische virtuelle Maschine, in der ein vollständiges Betriebssystem inkl. betreffendem Dienst läuft. Man unterscheidet dabei verschiedene Virtualisierungstechnologien: Hardwareemulation, Hardwarevirtualisierung, Paravirtualisierung und Betriebssystemvirtualisierung.
Bei der Hardwareemulation werden sämtliche Hardwarekomponenten emuliert. Das Gastbetriebssystem kann also unverändert bleiben. Die Emulation ist jedoch aufwändig und führt zu deutlichen Performance-Einbußen. Ein Vertreter dieser Sparte ist Windows VirtualPC.
Bei der Hardwarevirtualisierung werden bis auf die CPU die meisten Hardwarekomponenten emuliert. Einige CPU-Instruktionen werden abgefangen und angepasst. Dies führt dazu, dass ein Gastbetriebssystem nur mit der CPU arbeiten kann, die auch tatsächlich auf dem Hostsystem installiert ist. Dafür ist die Performance um ein Vielfaches besser. Gastbetriebssysteme können ohne Veränderung in einer solchen Umgebung laufen. Vertreter dieser Kategorie sind zum Beispiel vmware, Microsofts Hyper-V, Oracles VirtualBox und das XEN Projekt (mit HVM).
Bei der Paravirtualisierung geht man noch einen Schritt weiter und emuliert auch keine Hardware mehr. Stattdessen stellt der Host dem Gast definierte Softwareschnittstellen zur Verfügung, mit denen er interagieren kann. Eine Anpassung des Gastbetriebssystems ist damit unumgänglich. Die Performance ist höher als bei der Hardwarevirtualisierung.
Bei der Betriebssystemvirtualisierung löst sich die Isolation zwischen Host und Gast noch weiter auf, da das Gastbetriebssystem den selben Kernel benutzt wie der Host. Damit kann der Gast auch nur das gleiche Betriebssystem benutzen wie der Host (Linux auf Linux). Unterschiedliche Distributionen sind allerdings möglich. Diese Art der Virtualisierung ist sehr leichtgewichtig, da die Interaktion mit dem Kernel nicht mehr durch mehrere Abstraktionsschichten laufen muss. Gastbetriebssysteme können innerhalb von Sekunden gestartet und gestoppt werden, da der eigentliche Bootvorgang des Kernels entfällt. Vertreter dieser Kategorie sind zum Beispiel Linux Containers, OpenVZ/Virtuozzo und Docker.
Aus Kostengründen wird der Server, auf dem das System später laufen soll, sicherlich ein VPS (Virtual Private Server), der im Rechenzentrum bei einem größeren Anbieter läuft. Diese Server sind wie der Name schon sagt, selbst virtualisiert. Auf diesen virtuellen Servern sind Virtualisierungslösungen, die ihrerseits die Hardware wieder virtualisieren oft zwar möglich, werden aber vom Anbieter unterbunden und nur gegen Aufpreis freigeschaltet. Wirklich performant ist das nicht. Es kommt also nur eine Betriebssystemvirtualisierung – auch als Container bekannt – in Frage.
In die nähere Wahl kamen Linux Containers und Docker.
Linux Containers (LXC)
Kurz zusammengefasst kann man sagen, dass Linux Containers (LXC) ein Verfahren zur Virtualisierung auf Betriebssystemebene ist, während LXD die sehr komplexe Bedienung von LXC mit Tools und einer REST-API komfortabel nutzbar macht.
LXC/LXD kapselt in einem Container eine vollständige Linux-Distribution, die längerfristig betrieben und auch wiederholt upgedatet werden kann. In diesem Sinne könnte man einen solchen Container am ehesten als eine besonders leichtgewichtige virtuelle Maschine verstehen.
Für die reproduzierbare Einrichtung eines LXD Containers können Standardlösungen für automatisierte Installation – wie z. B. RedHats kickstart – verwendet werden. Ein LXD Container startet normalerweise wie ein reales Linux auch mit dem Init-Prozess (derzeit sicherlich am häufigsten systemd) und fährt – wie ein reales System auch – wieder geordnet herunter.
Die Infrastruktur, die rund um LXD existiert, ist eher dünn, was vermutlich auch daran liegt, dass das LXD Projekt noch sehr jung ist. Es wurde im November 2014 gestartet. Es gibt Image-Server, von denen man Betriebssystem-Images laden kann, um darauf dann die für die gewünschten Dienste benötigten Pakete zu installieren.
Docker
Während LXC langlebige Container vorsieht, verfolgt Docker geradezu ein Wegwerf-Konzept. Docker-Container werden erzeugt, gestartet und nach dem Shutdown wieder gelöscht. Ein Update eines laufenden Docker-Containers ist eher unüblich. Stattdessen aktualisiert man das Image, von dem der Container erzeugt wird. Das Docker-Konzept sieht vor, dass in einem Container nur ein Prozess läuft, um eine bestmögliche Isolation der Prozesse und damit verbunden die größtmögliche Sicherheit zu erreichen. Schaut man sich allerdings einmal bei Docker Hub, dem Repository für Docker-Images um, so fällt schnell auf, dass in sehr vielen Containern mehr als nur ein Prozess läuft. Das Argument der Isolation der Prozesse zieht also manchmal auch in die entgegengesetzte Richtung und führt eher dazu, dass Dienste, die sehr eng zusammen arbeiten, sich auch einen Container teilen dürfen. Im Gegensatz zu den Image Repositories, die man bei LXD findet und in denen in erster Linie Images mit einer Basisinstallation verschiedener Linux-Distributionen liegen, gibt es im Docker Hub mehr als 100.000 fertig konfigurierte Images mit den unterschiedlichsten Diensten für verschiedene Einsatzszenarien.
Der Docker Hub stellt neben den verschiedenen offiziellen Images der bekannten Distributionen und Softwarehersteller auch automatisierte Image-Builds zur Verfügung. Die automatisierten Builds verfügen über eine Ankopplung an ein Github-Repository mit der Bauanleitung (dem Dockerfile) des Images sowie den dafür benötigten Ressourcen und werden neu ausgelöst, wenn Änderungen in das Repository gepusht werden. Dieser Automatismus schafft ein gewisses Vertrauen in die Images, da der Erstellungsprozess transparent ist und der gesamte Quellcode auf Github eingesehen werden kann. Man bekommt hier zwar ein fertiges Image, aber dennoch keine Black Box – solange man der Docker-Infrastruktur vertraut.
Bei der Evaluierung von Docker musste ich allerdings feststellen, dass Docker und systemd nicht sehr gut miteinander spielen, was bei LXD überhaupt kein Problem ist. Pakete, die bei der Installation ein laufendes systemd voraussetzen, lassen sich dann häufig nicht oder nicht vollständig installieren. Aber wo Licht ist, ist wohl auch Schatten…
Entscheidung
Die Vorteile von Docker sind zahlreicher als die Nachteile, so dass ich wohl mit Docker arbeiten werde.