Compose er­leich­tert die Ska­lie­rung und Be­reit­stel­lung von An­wen­dun­gen in Docker, indem es die Ver­wal­tung von Con­tai­nern au­to­ma­ti­siert. In diesem Tutorial werfen wir einen de­tail­lier­ten Blick auf die Ein­rich­tung und Nutzung von Docker Compose, damit Sie es in Ihrer eigenen Pro­duk­ti­ons­um­ge­bung anwenden können.

Was ist Docker Compose?

Docker Compose dient dem Ma­nage­ment von An­wen­dun­gen und erhöht die Effizienz bei der Ent­wick­lung von Con­tai­nern. Kon­fi­gu­ra­tio­nen werden in einer einzigen YAML-Datei fest­ge­legt, wodurch Ap­pli­ka­tio­nen einfach zu erstellen und zu skalieren sind. Docker Compose wird häufig verwendet, um eine lokale Umgebung ein­zu­rich­ten. Es kann aber auch Teil eines Con­ti­nuous In­te­gra­ti­on / Con­ti­nuous Delivery (CI/CD) Workflows sein. Ent­wick­ler und Ent­wick­le­rin­nen können eine spe­zi­fi­sche Version von Con­tai­nern für Tests oder für eine bestimmte Phase der Pipeline de­fi­nie­ren. Dies er­leich­tert die Iden­ti­fi­zie­rung von Problemen und die Behebung von Fehlern, bevor sie in die Pro­duk­ti­on gelangen.

Docker Compose: Das sind die Vor­aus­set­zun­gen

Für die Container-Or­ches­trie­rung benötigen Sie sowohl die Docker-Engine als auch Docker Compose. Sie müssen daher eine der folgenden Mög­lich­kei­ten auf Ihrem System ein­ge­rich­tet haben:

  • Docker Engine und Docker Compose: können als Stan­da­lo­ne Binaries in­stal­liert werden
  • Docker Desktop: Ent­wick­lungs­um­ge­bung mit gra­fi­scher Be­nut­zer­ober­flä­che, die die Docker-Engine und Docker Compose bereits be­inhal­tet
Tipp

Wie Sie Docker Compose auf ver­schie­de­nen Be­triebs­sys­te­men in­stal­lie­ren, können Sie in unseren Tutorials nachlesen:

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

Im Folgenden de­mons­trie­ren wir die Konzepte von Docker Compose mit einer einfachen Python-Web-Ap­pli­ka­ti­on, 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 in­stal­lie­ren, da diese als Docker Images be­reit­ge­stellt werden.

Schritt 1: Pro­jekt­da­tei­en erstellen

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

$ mkdir composedemo
shell

Wechseln Sie daraufhin in das Ver­zeich­nis.

$ 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 Stan­dard­port „6379“. Des Weiteren legen wir fest, dass die Funktion get_hit_count() mehrere Versuche un­ter­neh­men soll, sich mit dem Dienst zu verbinden. Dies ist emp­feh­lens­wert, da es sein kann, dass Redis beim Start der Anwendung noch nicht verfügbar ist oder es im Laufe der Aus­füh­rung zu Ver­bin­dungs­pro­ble­men kommt.

Legen Sie noch die Datei re­qui­re­ments.txt mit den Ab­hän­gig­kei­ten an:

flask
redis
plaintext

Schritt 2: Do­cker­file ein­rich­ten

Das Do­cker­file wird für das Docker Image benutzt. Hierin werden alle Ab­hän­gig­kei­ten 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 an­ge­wie­sen, das Python 3.7 Image zu verwenden. Zudem haben wir die Um­ge­bungs­va­ria­blen für das Flask-Kommando fest­ge­legt. Mit apk add in­stal­lie­ren wir gcc und andere Ab­hän­gig­kei­ten. EXPOSE gibt an, dass der Container Port 5000 über­wa­chen soll. Mit COPY wird der Inhalt des aktuellen Ordners in das Ar­beits­ver­zeich­nis /code kopiert. Als Stan­dard­be­fehl für den Container wählen wir flask run.

Über­prü­fen Sie, dass das Do­cker­file ohne Da­tei­endung ge­spei­chert wurde, da manche Editoren au­to­ma­tisch das Suffix .txt anhängen.

Schritt 3: YAML-Datei anlegen

In docker-compose.yml kon­fi­gu­rie­ren 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 Do­cker­file 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 of­fi­zi­el­len Docker Hub bezogen.

Schritt 4: Die Anwendung mit Compose ausführen

Starten Sie die Ap­pli­ka­ti­on von Ihrem Pro­jekt­ord­ner 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:

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

Ak­tua­li­sie­ren Sie die Seite. Die Anzahl Ihrer Aufrufe sollte nun um 1 gestiegen sein.

Bild: 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 Ap­pli­ka­ti­on gestartet haben, Ctrl + C drücken.

Schritt 5: Ein Bind Mount hin­zu­fü­gen

Wenn Sie ein Bind Mount für den Web-Dienst hin­zu­fü­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 Pro­jekt­ord­ner an das Ver­zeich­nis /code innerhalb des Con­tai­ners an­ge­bun­den werden soll. Damit können Sie den Code ändern, ohne das Image neu erstellen zu müssen. Die Um­ge­bungs­va­ria­ble FLASK_DEBUG ordnet flask run dabei an, im Ent­wick­lungs­mo­dus aus­ge­führt zu werden.

Schritt 6: Ap­pli­ka­ti­on neu erstellen und ausführen

Geben Sie folgenden Befehl in das Terminal ein, um die Compose-Datei neu auf­zu­set­zen:

docker compose up
shell

Schritt 7: Die Anwendung ak­tua­li­sie­ren

Da Sie jetzt einen Bind Mount für Ihre Ap­pli­ka­ti­on verwenden, können Sie Ihren Code mo­di­fi­zie­ren und au­to­ma­tisch die Än­de­run­gen sehen, ohne das Image neu zu erstellen.

Schreiben Sie einen neuen Be­grü­ßungs­test in app.py.

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

Ak­tua­li­sie­ren Sie den Browser, um zu testen, ob die Än­de­run­gen über­nom­men wurden.

Bild: Docker-Compose-Anwendung: Geänderter Begrüßungstext
Der Be­grü­ßungs­text in der Python-Anwendung wurde angepasst.

Schritt 8: Weitere Kommandos

Die Option --help zeigt Ihnen eine Liste an ver­füg­ba­ren Kommandos für Docker Compose an:

docker compose --help
shell

Um Docker Compose im Hin­ter­grund laufen zu lassen, können Sie das Argument -d hin­zu­fü­gen:

docker compose up -d
shell

Mit down werden alle Container entfernt. Die Option --volumes löscht dabei auch die vom Redis-Container ver­wen­de­ten 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.

Zum Hauptmenü