Compose: Docker-Container-Anwendungen orchestrieren

Compose erleichtert die Skalierung und Bereitstellung von Anwendungen in Docker, indem es die Verwaltung von Containern automatisiert. In diesem Tutorial werfen wir einen detaillierten Blick auf die Einrichtung und Nutzung von Docker Compose, damit Sie es in Ihrer eigenen Produktionsumgebung anwenden können.

Was ist Docker Compose?

Docker Compose dient dem Management von Anwendungen und erhöht die Effizienz bei der Entwicklung von Containern. Konfigurationen werden in einer einzigen YAML-Datei festgelegt, wodurch Applikationen einfach zu erstellen und zu skalieren sind. Docker Compose wird häufig verwendet, um eine lokale Umgebung einzurichten. Es kann aber auch Teil eines Continuous Integration / Continuous Delivery (CI/CD) Workflows sein. Entwickler und Entwicklerinnen können eine spezifische Version von Containern für Tests oder für eine bestimmte Phase der Pipeline definieren. Dies erleichtert die Identifizierung von Problemen und die Behebung von Fehlern, bevor sie in die Produktion gelangen.

Docker Compose: Das sind die Voraussetzungen

Für die Container-Orchestrierung benötigen Sie sowohl die Docker-Engine als auch Docker Compose. Sie müssen daher eine der folgenden Möglichkeiten auf Ihrem System eingerichtet haben:

  • Docker Engine und Docker Compose: können als Standalone Binaries installiert werden
  • Docker Desktop: Entwicklungsumgebung mit grafischer Benutzeroberfläche, die die Docker-Engine und Docker Compose bereits beinhaltet
Tipp

Wie Sie Docker Compose auf verschiedenen Betriebssystemen installieren, können Sie in unseren Tutorials nachlesen:

Schritt-für-Schritt-Anleitung: So nutzen Sie Docker Compose

Im Folgenden demonstrieren wir die Konzepte von Docker Compose mit einer einfachen Python-Web-Applikation, deren Aufrufe in einem Hit-Counter gezählt werden. Dazu verwenden wir das Python Flask Framework und die In-Memory-Datenbank Redis. Sie müssen weder Python noch Redis installieren, da diese als Docker Images bereitgestellt werden.

Schritt 1: Projektdateien erstellen

Öffnen Sie das Terminal und legen Sie einen neuen Ordner für das Projekt an.

$ mkdir composedemo
shell

Wechseln Sie daraufhin in das Verzeichnis.

$ cd composedemo
shell

Erstellen Sie in diesem Ordner die Datei app.py und fügen Sie ihr folgenden Code hinzu:

import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I was here {} times.\n'.format(count)
python

Wir verwenden als Hostname „Redis“ und den Standardport „6379“. Des Weiteren legen wir fest, dass die Funktion get_hit_count() mehrere Versuche unternehmen soll, sich mit dem Dienst zu verbinden. Dies ist empfehlenswert, da es sein kann, dass Redis beim Start der Anwendung noch nicht verfügbar ist oder es im Laufe der Ausführung zu Verbindungsproblemen kommt.

Legen Sie noch die Datei requirements.txt mit den Abhängigkeiten an:

flask
redis
plaintext

Schritt 2: Dockerfile einrichten

Das Dockerfile wird für das Docker Image benutzt. Hierin werden alle Abhängigkeiten angegeben, die die Python-Anwendung benötigt.

# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
shell

Docker wird damit angewiesen, das Python 3.7 Image zu verwenden. Zudem haben wir die Umgebungsvariablen für das Flask-Kommando festgelegt. Mit apk add installieren wir gcc und andere Abhängigkeiten. EXPOSE gibt an, dass der Container Port 5000 überwachen soll. Mit COPY wird der Inhalt des aktuellen Ordners in das Arbeitsverzeichnis /code kopiert. Als Standardbefehl für den Container wählen wir flask run.

Überprüfen Sie, dass das Dockerfile ohne Dateiendung gespeichert wurde, da manche Editoren automatisch das Suffix .txt anhängen.

Schritt 3: YAML-Datei anlegen

In docker-compose.yml konfigurieren wir die Dienste „redis“ und „web“.

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"
yaml

Der Web-Dienst benutzt das Image, das von dem Dockerfile erstellt wird. Es verknüpft den Container und den Host-Computer mit Port 8000, während der Flask-Webserver auf Port 5000 läuft. Das Redis-Image wird hingegen einfach aus dem offiziellen Docker Hub bezogen.

Schritt 4: Die Anwendung mit Compose ausführen

Starten Sie die Applikation von Ihrem Projektordner aus.

docker compose up
shell

Rufen Sie ‘http://localhost:8000’ in Ihrem Browser auf. Sie können auch ‘http://127.0.0.1:8000’ eingeben.

Ihnen sollte folgende Nachricht angezeigt werden:

Docker-Compose-Anwendung: Ausgabe der Anzahl der Besuche im Browser
Ihnen wird die Anzahl Ihrer Aufrufe im Browser angezeigt.

Aktualisieren Sie die Seite. Die Anzahl Ihrer Aufrufe sollte nun um 1 gestiegen sein.

Erneuter Aufruf der Docker-Compose-Anwendung
Die Anzahl der Besuche wurde um 1 angehoben.

Stoppen Sie die Anwendung mit:

$ docker compose down
shell

Sie können aber auch in dem Terminal, in dem Sie die Applikation gestartet haben, Ctrl + C drücken.

Schritt 5: Ein Bind Mount hinzufügen

Wenn Sie ein Bind Mount für den Web-Dienst hinzufügen möchten, können Sie dies in docker-compose.yml vornehmen.

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_DEBUG: "true"
  redis:
    image: "redis:alpine"
yaml

Unter Volumes geben wir an, dass der aktuelle Projektordner an das Verzeichnis /code innerhalb des Containers angebunden werden soll. Damit können Sie den Code ändern, ohne das Image neu erstellen zu müssen. Die Umgebungsvariable FLASK_DEBUG ordnet flask run dabei an, im Entwicklungsmodus ausgeführt zu werden.

Schritt 6: Applikation neu erstellen und ausführen

Geben Sie folgenden Befehl in das Terminal ein, um die Compose-Datei neu aufzusetzen:

docker compose up
shell

Schritt 7: Die Anwendung aktualisieren

Da Sie jetzt einen Bind Mount für Ihre Applikation verwenden, können Sie Ihren Code modifizieren und automatisch die Änderungen sehen, ohne das Image neu zu erstellen.

Schreiben Sie einen neuen Begrüßungstest in app.py.

return 'Hello from Docker! I was here {} times.\n'.format(count)
python

Aktualisieren Sie den Browser, um zu testen, ob die Änderungen übernommen wurden.

Docker-Compose-Anwendung: Geänderter Begrüßungstext
Der Begrüßungstext in der Python-Anwendung wurde angepasst.

Schritt 8: Weitere Kommandos

Die Option --help zeigt Ihnen eine Liste an verfügbaren Kommandos für Docker Compose an:

docker compose --help
shell

Um Docker Compose im Hintergrund laufen zu lassen, können Sie das Argument -d hinzufügen:

docker compose up -d
shell

Mit down werden alle Container entfernt. Die Option --volumes löscht dabei auch die vom Redis-Container verwendeten Volumes.

docker compose down --volumes
shell
Tipp

Für den Einstieg in Docker finden Sie in unserem Digital Guide ein Docker-Tutorial sowie eine Übersicht über die Docker-Befehle.