© istockphoto.com/tapilipa
Teil 2: Implementierung der einzelnen Container auf Basis der festgelegten Architektur

Aus der Architektur entsteht die Lösung


Dass Docker heutzutage als ernst zu nehmende Virtualisierungslösung eingesetzt werden kann, hat sich bereits herumgesprochen. Deshalb beschäftigte sich der erste Teil dieser Serie grundlegend mit der Technologie unter der Haube von Docker und der Möglichkeit, sie als leichtgewichtige Hostinglösung für eigene Microservices zu nutzen. Im nun folgenden zweiten Teil der Artikelserie beschreibe ich die Vorgehensweise zum Aufbau einer kompletten Webseite inklusive RESTful-API und Datenbank auf Basis der beschriebenen Architektur und ihrer Realisation mittels Docker Compose und den benötigten Docker-Containern.

Im ersten Teil der Serie haben wir Docker [1] in der Version 1.7.1 und Docker Compose [2] in der Version 1.3.1 installiert, die dank des rapiden Wachstums dieser Technologien nun bereits „veraltet“ sind. Aus diesem Grund bauen wir im zweiten Teil der Serie auf Docker 1.8.3 und Docker Compose 1.4.2 auf. Dasselbe gilt für io.js [3], dessen Entwicklung gestoppt und wieder in den Node.js-4.x-Zweig überführt wurde – ein Grund, wieder auf Node.js [4] zu bauen.

Die Architektur

Bevor wir uns an die Implementierung der Lösung mittels Docker Compose machen, müssen wir die geplante Architektur nochmals betrachten, um eine Übersicht der benötigten Docker-Images zu bekommen (Abb. 1).

sambale_docker_1.tif_fmt1.jpgAbb. 1: Webseitenarchitektur auf Basis von Docker

Für die Umsetzung der Webseite inklusive Reverse-Proxy, REST-API und Datenbank benötigen wir laut Architektur vier Docker-Container, die teilweise eine Verbindung untereinander benötigen. Das Ziel ist, dass nur der nginx-Reverse-Proxy-Container aus dem Internet erreichbar sein soll (zwei-/dreistellige Portnummer); alle weiteren Container werden intern nur über Containerlinks verknüpft (vierstellige Portnummer) und bekommen somit keine direkte Verbindung nach außen.

Wir starten mit Docker Compose

Das Management von Images und Containern mit Docker und Docker Compose umfasst drei Komponenten:

  • Dockerfile: Das Dockerfile wird für jedes zu erstellende Image benötigt und beschreibt dessen Inhalt. Hier wird unter anderem spezifiziert, welche Applikationen installiert werden, welche Dateien kopiert werden müssen und welcher Prozess beim Starten des Containers gestartet werden soll. Im Prinzip ist diese Datei mit einem Shell- oder Bash-Skript vergleichbar.

  • Docker-compose.yml: Die Grundlage für Docker Compose bildet die docker-compose.yml-Datei. Sie beinhaltet die Konfiguration aller von Docker Compose orchestrierten Docker-Images und beschreibt unter anderem, welche Volumes gemountet, welche Ports genutzt und welche Container miteinander verknüpft werden sollen.

  • Docker-compose up: Um die Container unserer Docker-Architektur zu bauen und zu starten, muss dieser Befehl ausgeführt werden. Er geht durch alle festgelegten Verzeichnisse und nutzt deren Dockerfile, um das Image zu bauen und die Container zu starten.

Alle Dateien, die wir nachfolgend erstellen werden, sind in meinem GitHub Repository [5] zu finden. Im ersten Teil der Serie haben wir bereits auf unserem Docker-Host ein Verzeichnis angelegt (/opt/docker), in dem alle unsere genutzten Docker-Dateien gespeichert werden. In einem größeren Docker Deployment müssen diese Dateien allerdings nicht explizit auf einem Server residieren, sondern sind eventuell im Netzwerk oder auf verschiedene Cloud-Dienstleister verteilt; sie können dann mittels Docker Machine dennoch zentral orchestriert werden. Aufgrund der Simplizität richten wir allerdings alles auf einer Maschine ein und verzichten auf ein verteiltes Deployment.

Die Architektur als Baum

Wenn wir die vorherige Architekturbeschreibung anschauen, so können wir sie auch in einer Baumstruktur abbilden und erkennen damit auch eine Möglichkeit, in welcher Verzeichnisstruktur die benötigten Informationen auf dem Server abgelegt werden können.

  • Ubuntu-Server (Docker-Base-Image)

    • name:

      • ubuntu-base

    • links:

      • keine

    • volumes:

      • keine

    • ports:

      • keine

      • nginx-Reverse-Proxy

    • name:

  • nginx-reverse-proxy

    • links:

      • nginx-Webseite

      • Node.js-REST-API

    • volumes:

      • Logdateien (/opt/docker/logs)

    • ports:

      • 80

      • 443 (SSL ignorieren wir in diesem Tutorial)

  • nginx-Webseite

    • name:

      • meinewebseite

    • links:

      • keine

    • volumes:

      • Webseitendateien (/opt/docker/meinewebseite/html)

      • Logdateien (/opt/docker/logs)

    • ports:

      • 8081

  • Node.js-REST-API

    • name:

      • meinewebseiteapi

    • links:

      • MongoDB-Datenbank

    • volumes:

      • Node.js-Applikationsdateien (/opt/docker/meinewebseiteapi/app)

      • Logdateien (/opt/docker/logs)

    • ports:

      • 3001

  • MongoDB-Datenbank

    • name:

      • mongodbdatabase

    • links:

      • keine

    • volumes:

      • MongoDB-Datenbankdateien (/opt/docker/mongodbdatabase/db)

      • Logdateien (/opt/docker/logs)

    • ports:

      • 3333

Aus dieser Struktur resultiert folgende Basisverzeichnisstruktur auf unserem Docker-Host-System, die wir im darauffolgenden Schritt erstellen müssen:

/opt/docker/ ├── logs ├──meinewebseite ├── meinewebseiteapi ├── mongodbdatabase ├── nginx-reverse-proxy └── ubuntu-base

In jedem Ordner benötigen wir nun nur die Dateien, die für das jeweilige Docker-Image benötigt werden, um bereits auf Dateisystemebene eine strikte Trennung der Services zu gewährleisten. Im Root-Verzeichnis der Unterordner befindet sich demnach immer ein Dockerfile.

Wichtig: Bitte prüfen Sie nach einem Upload auf den Server immer, ob die richtigen Dateisystemrechte gesetzt sind. Dafür können Sie ganz einfach mit folgenden Befehlen sorgen:

sudo chown -R johndoe:docker /opt/docker/ sudo chmod -R g+rwx /opt/docker/

Hierzu habe ich bereits ein kleines Skript angelegt, das Docker Compose startet und vorher die Rechte korrekt setzt, siehe runDockerWebseite.sh im Root-Verzeichnis des Docker-Projekts auf GitHub.

Erstellen der Docker-Compose-Datei

Die Grundstruktur ist geschaffen. Damit Docker Compose nun auch alle Images kennt, müssen diese mittels einer docker-compose.yml-Datei beschrieben werden. Sie basiert vollständig auf den gleichen Werten, die wir bereits in unserer Baumstruktur beschrieben haben und muss einfach nur noch ins YAML-Format (YAML ist ein rekursives Akronym für „Y...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang