Einführung in Docker
Wenn Sie die "Cloud"-Trends verfolgt haben, haben Sie wahrscheinlich schon von Docker gehört. Dabei handelt es sich um eine Open-Source-Implementierung von LXC (Linux Containers), mit der eine Anwendung und ihre benötigten Abhängigkeiten in einen Container verpackt werden, der einfach bereitgestellt und ausgetauscht werden kann. Die Containerisierung in Docker wird durch Ressourcenisolierung (cgroups), Kernel-Namensräume (Isolierung der Sicht der Anwendung auf das Betriebssystem, Prozessbäume usw.) und ein union-fähiges Dateisystem (wie aufs - Einbinden mehrerer Verzeichnisse in ein einziges, das deren kombinierten Inhalt zu enthalten scheint) erreicht.


Durch die Verwendung von Containern entfällt der Aufwand für die Erstellung, Bereitstellung und Wartung vollständiger VMs für die Ausführung Ihrer Anwendungen. Außerdem bieten sie vollständig identische PROD-, Staging-, QA- und DEV-Umgebungen. In einigen Fällen können Sie sogar einen Container von einem Server auf einen anderen verschieben, was ideal ist, um eine schnelle Instanz Ihrer PROD-Umgebung auf einem separaten Server zu spinnen, um einen schnellen Test durchzuführen, ohne die eigentliche PROD-Umgebung zu beeinträchtigen.
Mit Docker können Sie eine Anwendung und alle benötigten Abhängigkeiten verpacken und sie auf einem beliebigen Server laufen lassen, so dass sie völlig betriebssystemunabhängig ist - sie muss lediglich über die libcontainer-Bibliothek mit dem Host-Linux-Kernel kommunizieren. Ein Beispiel dafür ist, dass Ihr Anwendungscontainer Debian-Pakete und -Abhängigkeiten ausführt, Ihre DB auf einem CentOS-Container läuft und Ihr Host auf SuSE Linux läuft.
Docker verwendet die Bibliothek libcontainer, um sich mit dem Linux-Kernel des Hosts zu verbinden und dessen Ressourcen auf vorhersehbare Weise zu nutzen.

Offizielle Definition von libcontainer durch Docker - libcontainer bietet eine native Go-Implementierung für die Erstellung von Containern mit Namespaces, cgroups, Capabilities und Dateisystem-Zugriffskontrollen. Es erlaubt Ihnen, den Lebenszyklus des Containers zu verwalten, indem Sie zusätzliche Operationen durchführen, nachdem der Container erstellt wurde.
Container @ Google - Google Search ist der weltweit größte Implementierer von Linux-Containern. Für den Betrieb der Google-Suche werden jede Sekunde etwa 7000 Container gestartet. Das entspricht 2 Milliarden pro Woche. Container sind einer der Gründe für die Geschwindigkeit und Zuverlässigkeit der Google-Suche weltweit.
Die Container-Orchestrierung ist ein sehr wichtiger Bestandteil der Docker- und DevOps-Welt. Es gibt viele Unternehmen, die Orchestrierungs-Frameworks anbieten - Kubernetes, Swarm, Mesos, CentOS fleet usw.
Kubernetes-Projekt - Kubernetes ist ein Container-Orchestrierungssystem, das ursprünglich von Google entwickelt und als Open-Source-Projekt veröffentlicht wurde (gespendet an die Cloud Native Computing Foundation). Es basiert auf der von Google verwendeten Lösung für die Automatisierung der Bereitstellung, des Betriebs und der Skalierung von containerisierten Anwendungen.
Die neueste Docker-Version - 1.12 - bietet eigene integrierte Container-Orchestrierungsfunktionen namens Swarm. Es funktioniert, indem ein Manager-Knoten ernannt und Aufgaben auf den anderen Knoten geplant werden. Diese wiederum übernehmen die Rolle von Workern, die Aufgaben vom Manager erhalten (z. B. die Ausführung von Ad-hoc-Containern bei Bedarf). Das Erstellen eines Schwarms ist ganz einfach:
docker swarm init
DOCKER-SPEZIFIKA
AUFS - Union FilesystemsUnion-Filesystems ist leichtgewichtig und schnell. Sie funktionieren durch das Erstellen von Schichten. Aufs bietet die folgenden Funktionen für Docker:
- Schnelle Startzeiten der Container;
- Effiziente Nutzung des Speichers;
- Effiziente Nutzung des Speichers.
Aufs ist ein Vereinheitlichungs-Dateisystem. Das heißt, es nimmt mehrere Verzeichnisse auf dem Linux-Host, stapelt sie übereinander und bietet eine einzige, einheitliche Ansicht.
Innerhalb von Docker bietet AUFS eine Bildschichtung. Jedes Docker-Abbild verweist auf eine Liste schreibgeschützter Schichten, die Dateisystemunterschiede darstellen. Die Schichten werden übereinander gestapelt, um eine Basis für das Root-Dateisystem eines Containers zu bilden. Der Docker-Storage-Treiber stapelt die Schichten und bietet eine einheitliche Sicht auf sie. Wenn Sie einen neuen Container erstellen, fügen Sie eine neue beschreibbare Schicht über dem zugrunde liegenden Stapel hinzu (Änderungen an Dateien, Ordnern und Löschungen innerhalb des Containers werden in dieser Schicht vorgenommen).

BILDER UND CONTAINER
Ein Docker-Image ist eine geordnete Sammlung von Root-Dateisystemänderungen und den entsprechenden Ausführungsparametern zur Verwendung in einer Container-Laufzeitumgebung.
Um ein Image zu erstellen, verwenden Sie eine Dockerdatei, die eine Reihe von Anweisungen enthält, die Docker mitteilen, wie das Image zu erstellen ist. Zum Beispiel:
- Holen Sie sich ein Basis-Image, z. B. Debian, CentOS, Unbutu usw.
- Installieren Sie alle Ihre Anwendungsabhängigkeiten mit yum oder apt-get.
- Kopieren Sie die Konfigurationsdateien oder nehmen Sie einige Änderungen daran vor.
- Entpacken Sie einige Zip-Dateien.
Anschließend erstellen Sie Ihr Docker-Image mithilfe der soeben erstellten Dockerdatei:
docker build -t user/repo_name:v2 .
Ein Docker-Container ist eine Laufzeitinstanz eines Docker-Images, um einen Docker-Container von Ihrem Image auszuführen:
docker run -d --name "test_container" –v /host/src/dir:/opt/dir -p="80:8080" user/repo_name:v2
(-d für detached ; -name für den Namen des Containers ; mount des Verzeichnisses /host/src/dir innerhalb des Containers als /opt/dir ; -p für die Zuweisung der Ports vom Host zum Container und schließlich das Image, von dem aus der Container gestartet werden soll)Die Startzeit des Containers ist normalerweise extrem schnell - durchschnittlich 500ms.
Ein Container besteht aus
- Ein Docker-Image
- Ausführungsumgebung
- Ein standardisierter Satz von Anweisungen
Der Hauptunterschied zwischen Containern und Images ist die oberste beschreibbare Schicht, die von einem Container hinzugefügt wird, wenn er von einem Image aus gestartet wird. Alle Änderungen (Hinzufügungen, Löschungen, Modifikationen) werden in der beschreibbaren Schicht gespeichert. Wenn der Container gelöscht wird, wird auch die beschreibbare Schicht gelöscht (das zugrunde liegende Image bleibt unverändert). Daher werden die Anwendungsdaten in der Regel in einem gemounteten Data-Volume des Hosts gespeichert.
IN DOCKER EINGEHÄNGTE DATENVOLUMEN
Die Datenvolumina sind so konzipiert, dass die Daten unabhängig vom Lebenszyklus des Containers beständig sind.
Durch die Verwendung eines gemounteten Datenvolumens wird ein speziell entwickeltes Verzeichnis innerhalb eines oder mehrerer Container erstellt, die vom UnionFS ausgeschlossen sind. Daten-Volumes sind beständig, auch wenn der Container entfernt wird. Sie können von mehreren Containern auf demselben Host gemeinsam genutzt werden.

Datenvolumina werden mit dem Flag -volume oder -v in einem Docker-Ausführungsbefehl erstellt. Zum Beispiel:
docker run –v /host/src/dir:/opt/dir
DEVOPS MIT DOCKER - ANWENDUNGSBEISPIEL
Unser Anwendungsbeispiel zielte darauf ab, einige Workflow-Probleme zu lösen und die folgenden DevOps-Prozesse zu verbessern:
- Sie müssen Anwendungsumgebungen, Abhängigkeiten und Software-Patches auf mehreren Rechnern separat verwalten. Verringerung der gelegentlichen Unterschiede zwischen Entwicklungs-, Test- und Produktionsumgebungen.
- Die Fähigkeit von QA-Teams, auf einer exakten Nachbildung der Produktionsumgebung zu testen (und sehr schnell neue Instanzen davon zu erstellen, wenn dies mehrfach geschehen muss).
- Versionskontrolle sowohl auf Anwendungs- als auch auf Umgebungskonfigurationsebene.
- Bessere Sicherheit - Durch die Isolierung der Anwendungen von den anderen Komponenten auf dem Host. Wir können mehrere Anwendungen mit ihren zugehörigen Datenbanken ausführen, ohne dass sie sich gegenseitig sehen. Verknüpfung der Anwendungen mit einer DB, ohne dass irgendwelche Ports auf dem Host-Rechner offengelegt werden müssen.
- Reduzierung der Kosten für die Ausführung mehrerer VMs für jede Anwendung.
- Die Möglichkeit, den Aufbau und die Bereitstellung des gesamten Anwendungsstapels vollständig zu automatisieren und so den erforderlichen Arbeitsaufwand zu reduzieren.
Der größte Teil unserer Umsetzung erfolgte mit den folgenden Tools:
- Docker
- GIT - für die Versionskontrolle unserer Dockerdateien und App/DB-Konfiguration
- Bamboo - Continuous Integration Tool - für die Erstellung und Bereitstellung von Docker-Images
- Vagrant - für die Bereitstellung lokaler Container-Instanzen von zuvor erstellten Images
- Docker Trusted Registry - für unsere eigene, lokal gehostete Registry von Docker-Images

Alle Dockerdateien wurden in Zusammenarbeit zwischen dem Entwicklungs- und dem Betriebsteam erstellt, um die Anforderungen an Umgebung, Anwendung und Betriebssystem zu berücksichtigen. Die Dockerdateien wurden mit Git für die Versionierung und die Zusammenarbeit zwischen den beiden Teams entwickelt.
Die kontinuierliche Integration wurde in Bamboo implementiert. Jeder Build-Plan führt ein Git-Checkout des Zweigs mit der Dockerdatei, den conf-Dateien und anderen Installationsskripten durch, erstellt das Docker-Image und stellt es in die private Registry (Docker Trusted Registry) ein.
Es gibt eine logische Trennung von Basis- und Anwendungs-Docker-Images für jede Anwendung, um den Wartungs- und Erstellungsaufwand für jede Komponente zu verringern. Das Basis-Image enthält wesentliche Umgebungskomponenten und wird einmalig erstellt, wenn Änderungen an der Umgebung selbst erforderlich sind (z. B. Änderung von Konfigurationsparametern, Version des Anwendungsservers usw.). Das Anwendungs-Image holt das Basis-Image, baut darauf die anwendungsspezifische Konfiguration und die Abhängigkeiten auf und schiebt das erstellte Image in die private Registry.
Der Bereitstellungsprozess wird im CI-Tool durchgeführt, indem einfach ein Docker-Run auf dem Zielhost mit der spezifischen Container-Laufzeitkonfiguration (wie Umgebungsvariablen, Datenvolumina, offene Ports, Verknüpfungen mit dem DB-Container usw.) ausgeführt wird. Während des Deployments führen wir einige zusätzliche Schritte durch, wie z. B. das Stoppen der aktuell laufenden App- und DB-Container und das Entfernen der Container und des zugehörigen Images. Nachdem das Deployment abgeschlossen ist und die Container laufen, wird eine automatische Konfiguration der DB-Replikation mit den anderen DB-Containern durchgeführt, auf denen dieselbe Anwendungsdatenbank läuft. Dieser Prozess ermöglichte die vollständige Automatisierung aller Umgebungen mit unterschiedlichen Build- und Bereitstellungsplänen für Produktion, Staging, QA und Entwicklung.
Mit Hilfe von Front-End-Webservern und mehreren Instanzen unserer PROD-Umgebungen waren wir in der Lage, während der Bereitstellung keine Ausfallzeiten zu haben.
Darüber hinaus wurde Vagrant lokal von den Entwicklungs- und QA-Teams eingesetzt, um die Erstellung und Vernichtung neuer Instanzen der Anwendungen zu automatisieren, wobei genau die gleichen Images wie in der Produktion/Staging verwendet wurden.

