Docker und Google Compute Engine

Die 10-Minuten-Systemumgebung

Wie die Erfahrung zeigt, ist das Aufsetzen von Systemumgebungen in Projekten häufig ein enorm zeitintensives Unterfangen. Es führt nicht selten zu langwierigen Projektvorlaufzeiten und bremst die sonst so agilen Projekten aus. Aber auch im späteren Projektverlauf kann es zum Hindernis werden, wenn beispielsweise kurzfristig eine Umgebung für die Abnahme eines neuen Features beim Fachbereich benötigt wird. Hier kann das Virtualisierungswerkzeug Docker in Verbindung mit Cloud Services Abhilfe schaffen.

Docker und die Cloud – das Dynamische Duo

Mit dem Einzug Agiler Methoden und Prozesse hat sich das Prinzip der kontinuierlichen Integration (Continuous Integration) als “Best Practice ” in vielen Entwicklungsteams etabliert. Durch den Einsatz entsprechender Werkzeuge wie Jenkins oder Bamboo können so Fehler und Probleme früh erkannt und mit geringerem Aufwand als zu einem späteren Zeitpunkt im Entwicklungsprozess behoben werden.

Diese Automatisierung der Software-Fertigungsstrecke wird mit dem durch das gleichnamige Buch von Jez Humble populär gewordenen Continuous Delivery-Ansatz bis hin zum Betrieb der Applikation ausgedehnt. Martin Fowler bringt den zentralen dahinterstehenden Gedanken in seiner Definition des Begriffes wie folgt auf den Punkt:

You can perform push-button deployments of any version of the software to any environment on demand.

Das Ziel dabei ist eine deutliche Reduktion der Deploymentrisiken sowie eine Verkürzung der Feedbackschleifen für die Produktentwicklung.

Die Verbreitung von Continuous Delivery verlief jedoch bisher eher zögerlich, galten doch die Aufwände für die Einführung der hierfür erforderlichen Configuration Management Systeme wie Chef oder Puppet aufgrund ihrer Komplexität als hoch. Das Bild änderte sich jedoch als im März 2013 die erste Version von Docker erschien, das sich durch die folgenden Eigenschaften auszeichnete:

  • Flache Lernkurve
    Anders als bei den zuvor genannten Werkzeugen kommt Docker mit einer extrem reduzierten DSL aus. Diese lehnt sich zudem an bekannte Prinzipien, wie man sie von Shellskripten und dem Debian/Ubuntu-Paketmanagement kennt, und erfordert auch keine zusätzliche Einarbeitung in eine neue Programmiersprache.
  • Minimale Requirements
    Außer einem aktuellen Kernel (>= 3.10) gibt es nur wenige benötigte Bibliotheken, um Docker einsetzen zu können.
  • Image Repository
    Mit Dockerhub steht ein riesiger Fundus fertiger Images zur Verfügung, die sich mit einem Kommandozeilenbefehl laden und starten lassen.

Zusammen mit den mittlerweile einfach und günstig verfügbaren Cloud Services verschiedener Anbieter eröffnet sich so ein effizienter und schneller Weg, Systemumgebungen aufzusetzen.

Die ersten Schritte

Am Beispiel einer typischen Continuous Integration Umgebung für Java Projekte möchte ich demonstrieren, wie dieser Ansatz funktioniert.

Installation
Falls die Programme docker-compose und docker-machine noch nicht auf Ihrem Client installiert sein sollten, können Sie diese einfach über curl-Aufrufe herunterladen.

Zum aktuellen Zeitpunkt existiert leider keine native Windows-Version von docker-compose.

Den Anfang macht das erst Ende Februar als Beta-Version erschienene Kommandozeilenwerkzeug docker-machine, mit dem sich auf einfache Art und Weise eine Docker Engine auf verschiedenen Hostsystemen erzeugen läßt, angefangen von einer lokalen Virtualbox bis hin zu Instanzen diverser Cloud-Anbieter.

Mit Hilfe dieses Programms erzeugen wir nun eine neue Instanz auf der Google Compute Engine und installieren auf dieser die Docker Engine, welche die Umgebung für die später zu installierenden Service-Container bildet.

1 Kommando zum Erzeugen einer neuen Docker-Instanz
2 Auswahl des Instanztyps. Neben diversen Treibern für Cloud-Dienste kann auch eine lokale Virtualbox verwendet werden.
3 Größe der Festplatte
4 Maschinentyp (Google spezifisch)
5 Zone, in der die Instanz laufen soll
6 Projektname in der GCE-Umgebung
7 Name, unter dem Docker diese Instanz verwalten soll.

Direkt nach dem Absetzen dieses Befehls erscheint im zuvor geöffneten Browser ein Dialog, über den man sich bei Google anmelden und die von docker-machine angefragten Rechte bestätigen muss. Abschließend wird dann ein Authentication Token angezeigt, den man per Copy & Paste in die Eingabeaufforderung des Terminals übernimmt. Nach Abschluss der restlichen, automatisch ablaufenden Einrichtungsschritte kann man sich mit docker-machine ls die angelegte Instanz anzeigen lassen.

Damit nun alle folgenden docker-Befehle an diese Instanz gesendet werden, muss man mit $(docker-machine env dev) die notwendigen Umgebungsvariablen setzen. Nach diesen wenigen Schritten können wir nun schon direkt beginnen, Applikationen in Form von Docker-Containern auf der neuen Instanz zu installieren. Um beispielsweise das CI-System Jenkins zu starten, genügt der folgende Befehl.

Die folgenden Schritte werden dabei implizit ausgeführt:

  1. Download der aktuellsten Version des Images “jenkins” aus dem Dockerhub Repository.
  2. Erzeugen eines Containers mit dem Namen “myjenkins”, bei dem der Port 8080 durchgereicht wird.
  3. Start des Containers als Hintergrund Prozess

Der Dienst ist anschließend unter http://<IP der Cloudinstanz>:8080 verfügbar und das Team kann loslegen.

Auf diesem Weg lassen sich nun alle weiteren benötigten Dienste starten. Das folgende Diagramm zeigt den generellen Aufbau der Umgebung.

System-Umgebung mit Docker in der Cloud
System-Umgebung mit Docker in der Cloud

Service-Orchestrierung

Für unser Beispiel benötigen wir jedoch mehrere Container, die, wie das folgende Diagramm zeigt, miteinander verbunden sind.

 Java Entwicklungsumgebung
Java Entwicklungsumgebung

Um nun nicht alle hierfür notwendigen Dockerbefehle wie im ersten Beispiel über einzelne Kommandos ausführen zu müssen, greifen wir auf das Orchestrierungswerkzeuges docker-compose zurück.

Dafür definieren wir die Container unserer Umgebung in einer einfachen Textdatei im YAML-Format wie folgt:

1 Name des Dienstes der die Grundlage des generierten Containernamens bildet
2 Docker Image
3 Umgebungsvariablen, die im Container gesetzt werden sollen. In diesem Fall werden sie zur Deklaration des Datenbankaccounts genutzt.
4 Mapping des im Image definierten auf den extern erreichbaren Port des Containers
5 Container-Link: Der so verknüpfte Container (sonardb) steht innerhalb des Containers (sonarqube) unter dem angegebenen Hostname (db) zur Verfügung

Um auf der Instanz die so definierten Dienste in der richtigen Reihenfolge mit dieser Konfiguration zu starten, genügt der folgende Befehl:

Auch hier werden die gleichen Schritte wie zuvor bei dem docker run-Befehl durchlaufen.

Ein Blick mit docker ps zeigt uns, dass alle Container wie gewünscht bereit stehen.

Fazit

Wie gezeigt kann durch die Kombination von Clouddiensten und der Virtualisierungsplattform Docker in kürzester Zeit eine neue Systemumgebung erstellt werden. Die folgenden Vorteile ergeben sich bei diesem Verfahren:

  • Reproduzierbarkeit
    Gemäß dem Motto “Infrastructure as Code and Infrastucture is Code” wird die gesamte Umgebung durch eine ausführbare Datei beschrieben. Damit ist es möglich, dieselbe Umgebung jederzeit erneut aufzusetzen. Zusätzlich kann die Konfigurationsdatei zur Dokumentation des Systems verwendet werden.
  • Unabhängigkeit
    Das Entwicklerteam kann weitestgehend unabhängig von organisatorischen Rahmenbedingungen wie System- und Prozessvorgaben die benötigte Umgebung erzeugen. Mühselige Systemanpassungen aufgrund restriktiver Softwarerichtlinien entfallen und langwierige Abstimmungen mit anderen Organisationseinheiten werden reduziert.
  • Versionierung
    In der Softwareentwicklung schon lange selbstverständlich stellt die Versionierung der Infrastruktur eher die Ausnahme dar. Dank der dateibasierten Konfiguration können definierte Entwicklungsstände der Systemkonfiguration gemeinsam mit dem Quellcode verwaltet werden. Dadurch erhält man die Möglichkeit, neue Infrastrukturen zeitgleich mit dem Code zu entwickeln und zu testen, nötigenfalls Rollbacks durchzuführen und die Entwicklung vollständig und transparent zu dokumentieren.

Für alle, die jetzt Appetit bekommen haben, Docker auszuprobieren, findet sich im Anhang ein kurzer Überblick zu Docker und den wichtigsten Befehlen.

Anhang

Docker im Überblick

Docker funktioniert vereinfacht ausgedrückt wie eine Micro Virtual Machine, in der nur ein einziger Prozess läuft. Die Container benötigen dafür kein eigenes OS sondern nutzen einen von anderen Prozessen isolierten Zuganz zum Kernel. Hierzu erweitert Docker die LXC-Funktionalität des Linux-Kernels; nähere Informationen dazu finden sich in dem entsprechenden Abschnitt der Docker FAQ.

Die wichtigsten Komponenten dieser Plattform sind:

  • Images
    Beinhalten alle Dateien und Verzeichnisse, die später im Container zur Verfügung stehen sollen und geben vor, welches Programm ausgeführt werden soll. Darüber hinaus legen sie die Schnittstellen mit der Umwelt fest (Netzwerk, Dateisystem und Umgebungsvariablen).
  • Container
    Sind die Laufzeitumgebungen und basieren jeweils auf einem Image. Sie definieren, wie die Imageschnittstellen mit der Umgebung verbunden werden sollen.
  • Docker Engine
    Kontrolliert und steuert die Container und kann durch den Client mit den docker- und docker-compose-Befehlen gesteuert werden.
  • Host
    Ist die Umgebung, in der die Docker Engine und ihre Container laufen.
Tabelle 1. Die wichtigsten Docker-Befehle
Befehl Bedeutung

docker ps -a

Listet laufende und beendete Container der Docker Engine auf

docker search <Name>

sucht nach Images im Dockerhub Repository

docker run -d --name <Container> -p <Host>:<Container> <Image>

Erzeugt und startet einen Container mit Portmapping als Hintergrundprozess

docker stop <Container>

Stoppt einen Container

docker start <Container>

Startet einen Container

docker rm <Container>

Löscht einen Container

docker images

Listet die in der Docker Engine bereits geladenen Images

docker rmi <Image>

Löscht ein Image

docker inspect <Container>

Zeigt die Konfiguration eines Containers

docker exec -it <Container> /bin/bash

erzeugt eine interaktive Bash in einem laufenden Container

docker logs -f <Container>

gibt fortlaufend das Log des Containers aus

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *