Website-Suche

So installieren und verwenden Sie Docker Compose auf Ubuntu


Einführung

Docker vereinfacht den Prozess der Verwaltung von Anwendungsprozessen in Containern. Obwohl Container in gewisser Weise virtuellen Maschinen ähneln, sind sie leichter und ressourcenschonender. Dies ermöglicht es Entwicklern, eine Anwendungsumgebung in mehrere isolierte Dienste aufzuteilen.

Für Anwendungen, die von mehreren Diensten abhängen, kann es schnell unübersichtlich werden, alle Container zu orchestrieren, damit sie gemeinsam starten, kommunizieren und heruntergefahren werden. Docker Compose ist ein Werkzeug, das es ermöglicht, Multi-Container-Anwendungsumgebungen basierend auf Definitionen in einer YAML-Datei auszuführen. Es verwendet Dienstdefinitionen, um vollständig anpassbare Umgebungen mit mehreren Containern zu erstellen, die Netzwerke und Datenvolumen teilen können.

Dieser Leitfaden zeigt Ihnen, wie Sie Docker Compose auf einem Ubuntu-Server installieren und einen einfachen Container ausführen. Danach lernen Sie, eine Multi-Service-Umgebung mit einer WordPress-Anwendung und einer MySQL-Datenbank zu erstellen. Wir behandeln auch fortgeschrittene Themen, einschließlich der Skalierung von Services, der Definition benutzerdefinierter Netzwerke und der Verwendung modularer Include-Direktiven. Schließlich bietet dieser Artikel eine Migrationsanleitung von dem älteren docker-compose (v1) zur modernen docker compose (v2) sowie einen ausführlichen Abschnitt zur Fehlerbehebung bei häufigen Problemen wie Portkonflikten und Berechtigungsfehlern.

Wichtige Erkenntnisse:

  • Docker Compose ist ein Tool zum Definieren und Ausführen von Multi-Container-Anwendungen, bei dem eine einzige YAML-Datei verwendet wird, um Dienste, Netzwerke und Volumes zu konfigurieren.
  • Docker Compose wird auf Ubuntu installiert, indem das offizielle Repository von Docker hinzugefügt und apt verwendet wird, um das Paket docker-compose-plugin zu installieren.
  • Der moderne Befehl ist docker compose (mit einem Leerzeichen). Dies ersetzt das veraltete Tool docker-compose (mit einem Bindestrich) der Version 1.
  • Verwenden Sie docker compose up -d, um eine Anwendung im Hintergrund zu starten, und docker compose down, um alle ihre Container und Netzwerke zu stoppen und zu entfernen.
  • Die depends_on-Direktive hilft dabei, die Startreihenfolge von Diensten zu steuern, zum Beispiel sicherzustellen, dass ein Datenbank-Container vor einem Webanwendungs-Container gestartet wird.
  • Die häufigsten Probleme sind „Permission Denied“ (gelöst, indem man seinen Benutzer zur docker-Gruppe hinzufügt), Portkonflikte (gelöst durch Ändern des Host-Ports in der YAML-Datei) und YAML-Syntaxfehler (gelöst durch Korrigieren der Einrückung).
  • Sie können mehrere Instanzen eines Dienstes mit dem Befehl docker compose up --scale <service_name>=<number> ausführen.
  • Die include-Direktive ermöglicht es Ihnen, eine große docker-compose.yml-Datei in kleinere, besser handhabbare Konfigurationsdateien aufzuteilen.

Voraussetzungen

Um diesem Artikel zu folgen, benötigen Sie:

  • Zugang zu einer lokalen Ubuntu-Maschine oder einem Entwicklungsserver als Nicht-Root-Benutzer mit Sudo-Rechten. Wenn Sie einen Remote-Server verwenden, wird empfohlen, eine aktive Firewall zu installieren. Um diese einzurichten, lesen Sie bitte unseren Leitfaden zur Ersteinrichtung eines Ubuntu-Servers.
  • Docker auf Ihrem Server oder lokalen Rechner installiert, gemäß Schritten 1 und 2 von „Wie man Docker auf Ubuntu installiert – Schritt-für-Schritt-Anleitung“.

Hinweis: Ab Docker Compose v2 hat Docker den Übergang zur Verwendung des compose CLI-Plugin-Befehls vollzogen und entfernt sich vom ursprünglichen docker-compose, wie in unserer Anleitung How to Install Docker Compose on Ubuntu (Step-by-Step Guide) dokumentiert. Während sich die Installation unterscheidet, besteht die eigentliche Nutzung im Allgemeinen darin, den Bindestrich aus docker-compose-Aufrufen zu entfernen, sodass docker compose verwendet wird. Für vollständige Kompatibilitätsdetails konsultieren Sie bitte die offizielle Docker-Dokumentation zur Befehlskompatibilität zwischen dem neuen compose und dem alten docker-compose.

Schritt 1 — Installation von Docker Compose

Es gibt zwei Möglichkeiten, Docker Compose auf Ubuntu zu installieren:

  • Über das Repository installieren
  • Manuell installieren

Wir werden in diesem Abschnitt beide Möglichkeiten besprechen.

Installation von Docker Compose über das apt-Repository

Zuerst richten wir das Docker-apt-Repository ein.

# Add Docker's official GPG key:

sudo apt-get update

sudo apt-get install ca-certificates curl

sudo install -m 0755 -d /etc/apt/keyrings

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc

sudo chmod a+r /etc/apt/keyrings/docker.asc



# Add the repository to Apt sources:

echo \

  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \

  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \

  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update

Jetzt können Sie Docker Compose mit folgendem Befehl installieren:

sudo apt install docker-compose-plugin

Docker Compose ist nun erfolgreich auf Ihrem System installiert. Um zu überprüfen, ob die Installation erfolgreich war, können Sie Folgendes ausführen:

docker compose version

Du wirst eine ähnliche Ausgabe wie diese sehen:

Docker Compose version v2.3.3

Docker Compose manuell installieren

Um sicherzustellen, dass Sie die aktuellste stabile Version von Docker Compose erhalten, laden Sie diese Software von ihrem offiziellen Github-Repository herunter.

Überprüfen Sie zunächst die neueste verfügbare Version auf ihrer Release-Seite. Zum Zeitpunkt des Schreibens ist die aktuellste stabile Version v2.40.2.

Verwenden Sie den folgenden Befehl, um herunterzuladen:

mkdir -p ~/.docker/cli-plugins/

curl -SL https://github.com/docker/compose/releases/download/v2.40.2/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose

Als Nächstes setzen Sie die richtigen Berechtigungen, damit der Befehl docker compose ausführbar ist:

chmod +x ~/.docker/cli-plugins/docker-compose

Im nächsten Abschnitt sehen Sie, wie Sie eine docker-compose.yml-Datei einrichten und mit diesem Tool eine containerisierte Umgebung starten und betreiben.

Schritt 2 — Einrichten einer docker-compose.yml-Datei

Um zu demonstrieren, wie man eine docker-compose.yml-Datei einrichtet und mit Docker Compose arbeitet, erstellen Sie eine Webserver-Umgebung mithilfe des offiziellen Nginx-Images von Docker Hub, dem öffentlichen Docker-Registry. Diese containerisierte Umgebung wird eine einzelne statische HTML-Datei bereitstellen.

Beginnen Sie damit, ein neues Verzeichnis in Ihrem Heimatordner zu erstellen, und wechseln Sie dann dorthin:

mkdir ~/compose-demo

cd ~/compose-demo

Richten Sie in diesem Verzeichnis einen Anwendungsordner ein, der als Dokumentstamm für Ihre Nginx-Umgebung dient:

mkdir app

Erstellen Sie mit Ihrem bevorzugten Texteditor eine neue index.html-Datei im app-Ordner:

nano app/index.html

Fügen Sie den folgenden Inhalt in diese Datei ein:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Docker Compose Demo</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kognise/water.css@latest/dist/dark.min.css">
</head>
<body>

    <h1>This is a Docker Compose Demo Page.</h1>
    <p>This content is being served by an Nginx container.</p>

</body>
</html>

Speichern Sie die Datei und schließen Sie sie, wenn Sie fertig sind. Wenn Sie nano verwenden, können Sie das tun, indem Sie CTRL+X, dann Y und ENTER eingeben, um zu bestätigen.

Erstellen Sie als Nächstes die Datei docker-compose.yml:

nano docker-compose.yml

Fügen Sie den folgenden Inhalt in Ihre docker-compose.yml-Datei ein:

services:
  web:
    image: nginx:alpine
    ports:
      - "8000:80"
    volumes:
      - ./app:/usr/share/nginx/html

In modernem Docker Compose ist das version-Feld optional und wird oft weggelassen, da Compose die Konfigurationsversion automatisch erkennen kann. Das obige Beispiel enthält kein version-Feld, was für die meisten neuen Projekte der empfohlene Ansatz ist. Sie müssen version nur für die Kompatibilität mit älteren Versionen angeben.

Dann haben Sie den services-Block, in dem Sie die Dienste einrichten, die zu dieser Umgebung gehören. In Ihrem Fall haben Sie einen einzelnen Dienst namens web. Dieser Dienst verwendet das nginx:alpine-Image und richtet eine Portweiterleitung mit der ports-Anweisung ein. Alle Anfragen auf Port 8000 der Host-Maschine (dem System, von dem aus Sie Docker Compose ausführen) werden an den web-Container auf Port 80 weitergeleitet, wo Nginx läuft.

Die volumes-Direktive erstellt ein gemeinsames Volume zwischen dem Host-Rechner und dem Container. Dadurch wird der lokale app-Ordner mit dem Container geteilt, und das Volume befindet sich im Container unter /usr/share/nginx/html, wodurch das standardmäßige Document Root von Nginx überschrieben wird.

Speichern und schließen Sie die Datei.

Sie haben eine Demoseite und eine docker-compose.yml-Datei eingerichtet, um eine containerisierte Webserver-Umgebung zu erstellen, die diese bereitstellt. Im nächsten Schritt werden Sie diese Umgebung mit Docker Compose starten.

Schritt 3 — Ausführen von Docker Compose

Mit der vorhandenen docker-compose.yml-Datei können Sie nun Docker Compose ausführen, um Ihre Umgebung zu starten. Der folgende Befehl lädt die erforderlichen Docker-Images herunter, erstellt einen Container für den web-Dienst und führt die containerisierte Umgebung im Hintergrundmodus aus:

docker compose up -d

Docker Compose sucht zunächst nach dem definierten Image auf Ihrem lokalen System, und wenn es das Image nicht finden kann, wird es das Image von Docker Hub herunterladen. Sie werden eine Ausgabe wie diese sehen:

Creating network "compose-demo_default" with the default driver
Pulling web (nginx:alpine)...
alpine: Pulling from library/nginx
cbdbe7a5bc2a: Pull complete
10c113fb0c77: Pull complete
9ba64393807b: Pull complete
c829a9c40ab2: Pull complete
61d685417b2f: Pull complete
Digest: sha256:57254039c6313fe8c53f1acbf15657ec9616a813397b74b063e32443427c5502
Status: Downloaded newer image for nginx:alpine
Creating compose-demo_web_1 ... done

Hinweis: Wenn Sie beim Ausführen von docker compose up auf einen „Permission denied“-Fehler stoßen, bedeutet dies in der Regel, dass Ihr Benutzer ohne Root-Rechte keine Berechtigung hat, auf den Socket des Docker-Daemons zuzugreifen.

Standardmäßig bindet sich der Docker-Daemon an einen Unix-Socket (/var/run/docker.sock), der dem root-Benutzer gehört. Um dies zu beheben, müssen Sie Ihren Nicht-Root-Benutzer zur docker-Gruppe hinzufügen, die während der Docker-Installation erstellt wird.

Führen Sie den folgenden Befehl aus, um Ihren Benutzer zur docker-Gruppe hinzuzufügen:

sudo usermod -aG docker ${USER}

Nachdem Sie diesen Befehl ausgeführt haben, müssen Sie sich ab- und wieder anmelden, damit die Gruppenänderungen wirksam werden. Sie können die Änderungen auch für die aktuelle Terminal-Sitzung aktivieren, indem Sie Folgendes eingeben:

newgrp docker

Dieser Befehl sollte alle Berechtigungsfehler im Zusammenhang mit dem Docker-Socket beheben. Für eine vollständige Anleitung lesen Sie bitte Schritt 2 von Wie man Docker auf Ubuntu installiert – Schritt-für-Schritt-Anleitung.

Ihre Umgebung läuft jetzt im Hintergrund. Um zu überprüfen, dass der Container aktiv ist, können Sie Folgendes ausführen:

docker compose ps

Dieser Befehl zeigt Ihnen Informationen über die laufenden Container und deren Zustand sowie alle derzeit eingerichteten Port-Weiterleitungen an:

       Name                     Command               State          Ports        
----------------------------------------------------------------------------------
compose-demo_web_1   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:8000->80/tcp

Sie können nun auf die Demo-Anwendung zugreifen, indem Sie Ihren Browser entweder auf localhost:8000 richten, wenn Sie diese Demo auf Ihrem lokalen Rechner ausführen, oder auf Ihre_Server_Domain_oder_IP:8000, wenn Sie diese Demo auf einem entfernten Server ausführen.

Du wirst eine Seite wie diese sehen:

Das in der docker-compose.yml-Datei eingerichtete gemeinsame Volume hält die Dateien Ihres app-Ordners mit dem Dokumentenstamm des Containers synchron. Wenn Sie Änderungen an der index.html-Datei vornehmen, werden diese automatisch vom Container übernommen und somit beim Neuladen der Seite in Ihrem Browser angezeigt.

Im nächsten Schritt sehen Sie, wie Sie Ihre containerisierte Umgebung mit Docker-Compose-Befehlen verwalten.

Schritt 4 — Vertraut werden mit Docker-Compose-Befehlen

Sie haben gesehen, wie man eine docker-compose.yml-Datei einrichtet und die Umgebung mit docker compose up startet. Sie werden nun sehen, wie man Docker Compose-Befehle verwendet, um Ihre containerisierte Umgebung zu verwalten und mit ihr zu interagieren.

Um die von Ihrem Nginx-Container erzeugten Protokolle zu überprüfen, können Sie den Befehl logs verwenden:

docker compose logs

Du wirst eine ähnliche Ausgabe sehen:

Attaching to compose-demo_web_1
web_1  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
web_1  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
web_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
web_1  | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
web_1  | 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
web_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
web_1  | /docker-entrypoint.sh: Configuration complete; ready for start up
web_1  | 172.22.0.1 - - [02/Jun/2020:10:47:13 +0000] "GET / HTTP/1.1" 200 353 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" "-"

Wenn Sie die Ausführung der Umgebung pausieren möchten, ohne den aktuellen Zustand Ihrer Container zu ändern, können Sie Folgendes verwenden:

docker compose pause
Pausing compose-demo_web_1 ... done

Um die Ausführung nach dem Einlegen einer Pause fortzusetzen:

docker compose unpause
Unpausing compose-demo_web_1 ... done

Der stop-Befehl beendet die Ausführung des Containers, zerstört jedoch keine Daten, die mit Ihren Containern verbunden sind:

docker compose stop
Stopping compose-demo_web_1 ... done

Wenn Sie die mit dieser containerisierten Umgebung verbundenen Container, Netzwerke und Volumes entfernen möchten, verwenden Sie den Befehl down:

docker compose down
Removing compose-demo_web_1 ... done
Removing network compose-demo_default

Beachten Sie, dass dies das Basis-Image, das Docker Compose zum Starten Ihrer Umgebung verwendet (in Ihrem Fall nginx:alpine), nicht entfernt. Auf diese Weise wird der Prozess beim nächsten Start Ihrer Umgebung mit docker compose up viel schneller sein, da das Image bereits auf Ihrem System vorhanden ist.

Falls Sie auch das Basisbild von Ihrem System entfernen möchten, können Sie Folgendes verwenden:

docker image rm nginx:alpine
Untagged: nginx:alpine
Untagged: nginx@sha256:b89a6ccbda39576ad23fd079978c967cecc6b170db6e7ff8a769bf2259a71912
Deleted: sha256:7d0cdcc60a96a5124763fddf5d534d058ad7d0d8d4c3b8be2aefedf4267d0270
Deleted: sha256:05a0eaca15d731e0029a7604ef54f0dda3b736d4e987e6ac87b91ac7aac03ab1
Deleted: sha256:c6bbc4bdac396583641cb44cd35126b2c195be8fe1ac5e6c577c14752bbe9157
Deleted: sha256:35789b1e1a362b0da8392ca7d5759ef08b9a6b7141cc1521570f984dc7905eb6
Deleted: sha256:a3efaa65ec344c882fe5d543a392a54c4ceacd1efd91662d06964211b1be4c08
Deleted: sha256:3e207b409db364b595ba862cdc12be96dcdad8e36c59a03b7b3b61c946a5741a

Hinweis: Bitte beachten Sie unseren Leitfaden zur Installation von Docker auf Ubuntu – Schritt-für-Schritt-Anleitung für eine ausführlichere Übersicht zu Docker-Befehlen.

Schritt 5 — Erstellen einer Multi-Service-Anwendung

Die wahre Stärke von Docker Compose liegt darin, mehrere zusammenarbeitende Dienste zu verwalten. Das Nginx-Beispiel war ein einzelner Dienst. Lassen Sie uns eine praktischere, mehrteilige Anwendung erstellen: eine WordPress-Website, die mit einer MySQL-Datenbank verbunden ist.

Dieses Setup umfasst zwei Dienste: wordpress (führt die Anwendung aus) und db (führt die Datenbank aus). Wir werden auch Docker-Volumes verwenden, um sicherzustellen, dass die Daten der Datenbank erhalten bleiben, selbst wenn der Container entfernt wird.

Lass uns ein neues Verzeichnis für diese Anwendung erstellen:

mkdir -p ~/compose-demo/wordpressapp

cd ~/compose-demo/wordpressapp

Für dieses Beispiel benötigen wir keine lokalen Dateien, da die Bilder alle erforderliche Software enthalten werden.

Erstellen Sie eine neue docker-compose.yml-Datei:

nano docker-compose.yml

Fügen Sie die folgende Konfiguration ein. Diese Datei ist komplexer, daher werden wir jeden Teil untersuchen.

services:
  db:
    image: mysql:8.0
    container_name: mysql_db
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: <^your_root_password_here<^>
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress_user
      MYSQL_PASSWORD: <^your_wordpress_password_here<^>
    restart: unless-stopped

  wordpress:
    image: wordpress:latest
    container_name: wordpress_app
    ports:
      - "8001:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress_user
      WORDPRESS_DB_PASSWORD: <^your_wordpress_password_here<^>
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wp_content:/var/www/html/wp-content
    depends_on:
      - db
    restart: unless-stopped

volumes:
  db_data:

Hinweis: Wir haben die Werte für das Passwort hier zu Illustrationszwecken fest codiert. Bei der Nutzung in einer realen Umgebung sollten Sie unbedingt Umgebungsvariablen in einer .env-Datei verwenden, um die Preisgabe Ihrer Zugangsdaten zu vermeiden.

Speichern Sie die Datei und schließen Sie sie. Denken Sie daran, die Platzhalter <^...^> durch starke, sichere Passwörter zu ersetzen.

Lassen Sie uns die neuen Richtlinien in dieser Datei durchgehen:

  • services: Dieser Block definiert immer noch unsere Container. Wir haben jetzt zwei: db und wordpress.
  • image: Wir verwenden mysql:8.0 für die Datenbank und das wordpress:latest-Image für die Anwendung.
  • container_name: Damit wird ein bestimmter, für Menschen lesbarer Name für den Container festgelegt, der leichter zu referenzieren ist als die automatisch generierten.
  • environment: Dies ist eine Liste von Umgebungsvariablen, die an den Container übergeben werden. Das mysql-Image verwendet diese, um das Root-Passwort festzulegen und eine anfängliche Datenbank sowie einen Benutzer zu erstellen. Das wordpress-Image verwendet sie, um zu wissen, wie es eine Verbindung zu seiner Datenbank herstellen kann.
  • Volumes (Service-Ebene):

    • Für den db-Dienst wird db_data:/var/lib/mysql verwendet, um ein von Docker verwaltetes Volume mit dem Namen db_data auf das MySQL-Datenverzeichnis innerhalb des Containers zuzuordnen. So bleiben Ihre Daten sicher.
    • Für den wordpress-Dienst ordnet ./wp_content:/var/www/html/wp-content ein lokales Verzeichnis (wp_content) dem WordPress-Content-Verzeichnis zu. Dadurch können Sie Themes und Plugins direkt von Ihrem Host-Rechner aus bearbeiten.
  • depends_on: Dies teilt Compose mit, dass der db-Dienst vor dem Start des wordpress-Dienstes gestartet werden soll. Das ist wichtig, da WordPress fehlschlägt, wenn es seine Datenbank beim Start nicht finden kann.
  • volumes (oberste Ebene): Dieser Block definiert die benannten Volumes. db_data: erstellt ein von Docker verwaltetes Volume, was die bevorzugte Methode zur Handhabung persistenter Daten ist.

Bringen Sie nun diese Multi-Service-Anwendung hoch:

docker compose up -d

Compose wird sowohl die mysql- als auch die wordpress-Images herunterladen und dann die Container erstellen, wobei der db-Dienst zuerst gestartet wird.

Creating network "compose-demo_default" with the default driver
Creating volume "compose-demo_db_data" with default driver
Pulling db (mysql:8.0)...
...
Pulling wordpress (wordpress:latest)...
...
Creating mysql_db        ... done
Creating wordpress_app ... done

Sie können nun auf Ihre neue WordPress-Website zugreifen, indem Sie in Ihrem Browser zu localhost:8001 oder <^your_server_domain_or_IP<^>:8001 navigieren. Sie sollten den WordPress-Installationsbildschirm sehen. Für ein detaillierteres Beispiel schauen Sie sich unseren Artikel über die Installation von WordPress mit Docker Compose an.

Schritt 6 — Verwendung von Docker Compose für die KI/ML-Entwicklung

Über Webanwendungen hinaus ist Docker Compose ein äußerst nützliches Werkzeug zur Erstellung reproduzierbarer Datenwissenschafts- und Machine-Learning-(AI/ML)-Umgebungen. AI/ML-Projekte sind bekannt für ihre komplexen Abhängigkeiten, einschließlich spezifischer Python-Versionen, Bibliotheken wie TensorFlow oder PyTorch sowie systemweiter Treiber wie das NVIDIA CUDA Toolkit. Docker Compose erfasst diese gesamte Umgebung in Konfigurationsdateien und löst das Problem „auf meinem Rechner funktioniert es“, was für reproduzierbare Forschung entscheidend ist.

In diesem Beispiel erstellen Sie eine Multi-Service-AI/ML-Umgebung, die aus Folgendem besteht:

  • JupyterLab: Ein Container für interaktive Entwicklung, erstellt aus einem benutzerdefinierten Dockerfile.
  • PostgreSQL: Ein Datenbank-Container zur Speicherung von Experimentergebnissen und Metadaten.
  • GPU-Zugriff: Der JupyterLab-Container wird so konfiguriert, dass er auf die NVIDIA-GPU des Host-Computers zugreifen kann, was eine gängige Voraussetzung für das Training von Modellen ist.

Voraussetzung: Für dieses Beispiel wird eine NVIDIA-GPU auf Ihrem Host-Rechner und das NVIDIA Container Toolkit benötigt. Ohne diese wird der Container beim Anfordern von GPU-Ressourcen nicht gestartet.

Dateistruktur

Erstellen Sie zunächst ein Verzeichnis für Ihr Projekt. Darin erstellen Sie eine docker-compose.yml-Datei, ein jupyter-Verzeichnis, eine Dockerfile für Jupyter und eine requirements.txt-Datei. Die Struktur sollte ungefähr wie folgt aussehen:

ai-project/
├── docker-compose.yml
└── jupyter/
    ├── Dockerfile
    └── requirements.txt

Erstellen der Komponenten-Dateien

1. Die requirements.txt-Datei

Diese Datei listet die Python-Pakete für Ihre Data-Science-Umgebung auf.

nano jupyter/requirements.txt

Fügen Sie die benötigten Pakete hinzu. Für dieses Beispiel werden wir Bibliotheken für Datenmanipulation, Datenbankverbindung und ein Deep-Learning-Framework einbeziehen.

pandas
scikit-learn
tensorflow
jupyterlab
psycopg2-binary

Speichern und schließen Sie die Datei.

2. Die Dockerfile

Diese Datei definiert Ihren benutzerdefinierten JupyterLab-Dienst. Sie verwendet ein offizielles Jupyter-Image als Basis und installiert die Pakete aus requirements.txt.

nano jupyter/Dockerfile

Fügen Sie den folgenden Inhalt ein:

# Start from a base image that includes Jupyter and scientific libraries
FROM jupyter/scipy-notebook:latest

# Copy our local requirements file into the container
COPY requirements.txt /tmp/requirements.txt

# Install the Python packages
RUN pip install --no-cache-dir -r /tmp/requirements.txt

Diese Datei weist Docker an, jupyter/scipy-notebook als Ausgangspunkt zu verwenden, Ihre requirements.txt in den Container zu kopieren und anschließend pip zu verwenden, um die Pakete zu installieren.

Die Umgebung mit docker-compose.yml definieren

Erstellen Sie nun die Hauptdatei docker-compose.yml. Diese Datei wird sowohl den db-Dienst als auch Ihren benutzerdefinierten jupyter-Dienst orchestrieren.

nano docker-compose.yml

Fügen Sie die folgende Konfiguration ein und ersetzen Sie die Platzhalter <^...^> durch Ihre eigenen sicheren Zugangsdaten.

services:
  db:
    image: postgres:15-alpine
    container_name: ai_postgres_db
    environment:
      POSTGRES_USER: <^your_db_user^>
      POSTGRES_PASSWORD: <^your_db_pass^>
      POSTGRES_DB: experiments
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U <^your_db_user^> -d experiments"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    networks:
      - ai_net

  jupyter:
    build: ./jupyter
    container_name: ai_jupyter_lab
    ports:
      - "8888:8888"
    volumes:
      - ./notebooks:/home/jovyan/work
    environment:
      - POSTGRES_HOST=db
      - POSTGRES_USER=<^your_db_user^>
      - POSTGRES_PASSWORD=<^your_db_pass^>
      - POSTGRES_DB=experiments
    restart: unless-stopped
    networks:
      - ai_net
    depends_on:
      db:
        condition: service_healthy
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

volumes:
  postgres_data:
    name: ai_project_data

networks:
  ai_net:
    driver: bridge

Diese Konfigurationsdatei führt mehrere wichtige Konzepte ein:

  • build: ./jupyter: Dies teilt Docker Compose mit, ein benutzerdefiniertes Image für den jupyter-Dienst zu erstellen. Es sucht nach einer Dockerfile im angegebenen ./jupyter-Verzeichnis.
  • volumes: - ./notebooks:/home/jovyan/work: Dadurch wird ein lokales Verzeichnis namens notebooks in den Container eingebunden. So wird sichergestellt, dass alle von Ihnen erstellten Jupyter-Notebooks direkt auf Ihrem Host-Rechner gespeichert werden und auch nach Entfernen des Containers erhalten bleiben.
  • healthcheck: Wie im Abschnitt zur Fehlerbehebung zu sehen ist, überprüft dieser Check, dass der db-Dienst nicht nur läuft, sondern bereit ist, Verbindungen anzunehmen, bevor andere Dienste starten.
  • depends_on: ... condition: service_healthy: Dies teilt dem jupyter-Dienst mit, dass er warten soll, bis der Healthcheck des db-Dienstes bestanden ist, bevor er startet.
  • deploy.resources.reservations.devices: Dies ist der Block, der den Zugriff auf die GPU anfordert.

    • driver: nvidia: Gibt den zu verwendenden Host-Treiber an.
    • count: 1: Fordert eine GPU an.
    • capabilities: [gpu]: Stellt sicher, dass der Container die notwendigen Funktionen besitzt, um die GPU zu verwenden.

Den KI/ML-Umgebung betreiben

Mit Ihren Dateien an ihrem Platz sind Sie bereit, die Dienste zu erstellen und auszuführen.

  1. Führen Sie aus Ihrem ai-project-Verzeichnis den Befehl docker compose up aus. Sie müssen beim ersten Mal das --build-Flag hinzufügen, um Compose anzuweisen, Ihr benutzerdefiniertes jupyter-Image zu erstellen.

    docker compose up -d --build
  2. Compose wird zuerst das jupyter-Image erstellen (was einige Minuten dauern kann, da TensorFlow heruntergeladen wird), dann das postgres-Image ziehen und schließlich beide Container starten.

    [+] Building 5.8s (9/9) FINISHED
     => [internal] load build definition from Dockerfile
    ...
    [+] Running 3/3
     ✔ Network ai-project_ai_net        Created
     ✔ Container ai_postgres_db         Started
     ✔ Container ai_jupyter_lab         Started
  3. Sie können jetzt auf die JupyterLab-Oberfläche zugreifen, indem Sie in Ihrem Browser zu http://localhost:8888 (oder <^Ihre_Server_IP^>:8888) navigieren. Sie werden nach einem Token gefragt, das Sie aus den Container-Protokollen erhalten können:

    docker compose logs jupyter

    Suchen Sie nach einer Zeile, die ähnlich aussieht wie http://127.0.0.1:8888/lab?token=a1b2c3d4e5f6...

  4. Innerhalb eines Jupyter-Notebooks können Sie jetzt eine Verbindung zu Ihrer Datenbank über den Hostnamen db und die von Ihnen angegebenen Zugangsdaten herstellen. Ihre Umgebung hat außerdem Zugriff auf die GPU des Hosts für das Modelltraining.

Skalierung von Diensten und Verwendung benutzerdefinierter Netzwerke

Docker Compose beinhaltet Funktionen zum Skalieren von Diensten und zur Verwaltung der Netzwerke, über die sie kommunizieren.

Dienstskalierung mit Replikaten

Stellen Sie sich vor, Ihr Nginx-Webserver aus Schritt 2 bekommt zu viel Verkehr. Sie können den web-Dienst skalieren, um mehrere Container-Instanzen auszuführen. Docker Compose kann dies automatisch verwalten.

Es gibt zwei Hauptmöglichkeiten, einen Service zu skalieren.

1. Verwendung des replicas-Schlüssels (Bevorzugt in v2)

Sie können die gewünschte Anzahl von Instanzen direkt in Ihrer docker-compose.yml-Datei mit den Schlüsseln deploy und replicas festlegen. Diese Funktion war ursprünglich Teil von Docker Swarm, ist jetzt jedoch auch für Standard-Compose-Bereitstellungen verfügbar.

Ändern Sie Ihre Nginx-docker-compose.yml aus Schritt 2:

services:
  web:
    image: nginx:alpine
    ports:
      - "8000:80"
    volumes:
      - ./app:/usr/share/nginx/html
    deploy:
      replicas: 3

Wenn Sie docker compose up -d ausführen, erstellt Compose drei web-Container. Allerdings gibt es ein Problem: Alle drei werden versuchen, an den Host-Port 8000 zu binden. Dies führt beim zweiten und dritten Container zu einem Fehler „Port ist bereits zugewiesen“. Um dies in einer Produktionsumgebung zu lösen, würden Sie die ports-Zuordnung vom web-Dienst entfernen. Auf diese Weise sind die Web-Container nur innerhalb des Docker-Netzwerks zugänglich. Ein separater Load-Balancer-Dienst wäre dann der einzige mit einem öffentlichen Port. Er würde den Traffic an die drei Web-Replikate verteilen.

Ein Beispiel für eine Konfiguration würde so aussehen (dies ist ein fortgeschrittenes Beispiel):

services:
  web:
    image: nginx:alpine
    # No 'ports' mapping here.
    # The service is only accessible inside the 'web-net' network.
    volumes:
      - ./app:/usr/share/nginx/html
    deploy:
      replicas: 3
    networks:
      - web-net

  load_balancer:
    image: nginx:latest
    ports:
      - "80:80" # The load_balancer is the only service with a public port.
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf # A config file that load balances to 'web'.
    networks:
      - web-net
    depends_on:
      - web

networks:
  web-net:

In dieser Konfiguration hört der load_balancer auf Port 80 und leitet Anfragen intern an web_1, web_2 und web_3 weiter.

Dieser replicas-Schlüssel ist am nützlichsten, wenn er zusammen mit einem Reverse-Proxy (wie Traefik oder einer anderen Nginx-Instanz) verwendet wird, der Anfragen zwischen den Replikaten innerhalb des Docker-Netzwerks load-balancen kann, ohne dass jedes Replikat einen Port auf dem Host freigeben muss.

2. Verwendung des --scale-Flags

Eine gängige Methode zur Skalierung ist das --scale-Flag, ein Überbleibsel aus Compose v1. Dieses Flag wird zur Laufzeit angewendet und überschreibt jeden replicas-Schlüssel.

Sie müssen jedoch vorsichtig mit Portdefinitionen sein. Wenn Ihr Dienst eine feste Host-Port-Zuordnung definiert (z. B. "8000:80"), führt das Ausführen von docker compose up --scale zu einem Fehler für den zweiten und dritten Container, da alle versuchen, denselben Host-Port zu binden.

Um --scale für Dienste zu verwenden, die Ports freigeben, dürfen Sie keine feste Host-Port-Zuordnung verwenden.

  • Option 1: Auf zufällige Host-Ports zuordnen (Gut für die Entwicklung)

    Sie können Ihre docker-compose.yml so ändern, dass nur der Container-Port angegeben wird. Dies teilt Docker mit, den Port 80 in jedem Container auf einen zufälligen, verfügbaren Port auf Ihrem Host-Rechner zuzuordnen.

    services:
      web:
        image: nginx:alpine
        ports:
          - "80" # No fixed host port
        volumes:
          - ./app:/usr/share/nginx/html

    Wenn Sie nun den Skalierungsbefehl ausführen:

    docker compose up -d --scale web=3

    Führen Sie docker compose ps aus, um das Ergebnis zu sehen. Jeder Container wird auf einem anderen, zufällig zugewiesenen Host-Port laufen:

          Name                     Command               State          Ports        
    ----------------------------------------------------------------------------------
    compose-demo_web_1   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:49154->80/tcp
    compose-demo-web_2   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:49155->80/tcp
    compose-demo-web_3   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:49156->80/tcp
  • docker-compose.yml - Korrekt für --scale

  • Option 2: Verwenden Sie einen Reverse-Proxy (Gut für die Produktion)

    Die andere Lösung, wie im Abschnitt replicas erwähnt, besteht darin, die ports-Direktive vollständig aus dem web-Dienst zu entfernen. Sie würden dann einen separaten Load-Balancer-Container verwenden (der den einzigen öffentlichen Port hat), um den Datenverkehr zu den skalierten Replikaten innerhalb des Docker-Netzwerks zu verwalten und zu verteilen.

    Um alle drei Container zu stoppen und zu entfernen, bleibt der Befehl derselbe:

    docker compose down

Benutzerdefinierte Netzwerkkonfiguration

Standardmäßig erstellt Docker Compose ein einzelnes bridge-Netzwerk für Ihre Anwendung. Jeder Dienst in der Datei ist damit verbunden, wodurch der wordpress-Container den db-Container allein durch die Verwendung seines Dienstnamens (db) finden konnte.

Sie können jedoch eigene benutzerdefinierte Netzwerke für bessere Isolation und Kontrolle definieren.

Lassen Sie uns das WordPress-Beispiel so ändern, dass ein eigenes bridge-Netzwerk verwendet wird.

services:
  db:
    image: mysql:8.0
    ...
    networks:
      - app_net

  wordpress:
    image: wordpress:latest
    ...
    ports:
      - "8001:80"
    depends_on:
      - db
    networks:
      - app_net

volumes:
  db_data:

networks:
  app_net:
    driver: bridge

Das haben wir hinzugefügt:

  • networks (oberste Ebene): Dies definiert ein neues Netzwerk mit dem Namen app_net und gibt an, dass es den Standard-bridge-Treiber verwenden soll.
  • Netzwerke (Service-Ebene): Unter sowohl db als auch wordpress verbindet dieser Schlüssel sie mit unserem app_net-Netzwerk.

Wenn Sie einen dritten Dienst (wie ein Analysetool) hätten, den Sie nicht mit app_net verbinden, wäre er vollständig isoliert und könnte nicht mit den db- oder wordpress-Containern kommunizieren.

Für Multi-Host-Clustering mit Docker Swarm würden Sie den driver von bridge auf overlay ändern. Der bridge-Treiber dient der Kommunikation zwischen Containern auf einem einzigen Host, was der Standard für die meisten Docker-Compose-Anwendungsfälle ist.

Verwendung modularer Konfigurationsdateien

Wenn Ihre Anwendungen wachsen, kann Ihre docker-compose.yml-Datei groß und schwer zu verwalten werden. Docker Compose unterstützt eine include-Direktive, mit der Sie Ihre Konfiguration auf mehrere Dateien aufteilen können.

Stellen Sie sich vor, Sie möchten Ihre WordPress- und Datenbankdefinitionen trennen und vielleicht eine gemeinsame docker-compose.override.yml für entwicklungsspezifische Einstellungen haben (wie das Binden eines Ports an die Datenbank).

Ihre Verzeichnisstruktur könnte folgendermaßen aussehen:

compose-demo/
├── docker-compose.yml
├── docker-compose.db.yml
├── docker-compose.web.yml

Diese Datei wird nur den db-Dienst definieren.

services:
  db:
    image: mysql:8.0
    container_name: mysql_db
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: <^your_root_password_here<^>
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress_user
      MYSQL_PASSWORD: <^your_wordpress_password_here<^>
    restart: unless-stopped

volumes:
  db_data:

Diese Datei wird nur den wordpress-Dienst definieren.

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress_app
    ports:
      - "8001:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress_user
      WORDPRESS_DB_PASSWORD: <^your_wordpress_password_here<^>
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wp_content:/var/www/html/wp-content
    depends_on:
      - db
    restart: unless-stopped

Jetzt wird deine Haupt-docker-compose.yml-Datei sehr einfach. Sie verwendet einfach include, um die anderen Dateien einzubinden.

include:
  - docker-compose.db.yml
  - docker-compose.web.yml

Wenn Sie docker compose up -d ausführen, liest Compose alle drei Dateien, führt die Konfigurationen zusammen und startet die db- und wordpress-Dienste genau so, als wären sie in einer einzigen Datei definiert. Dieser Ansatz macht Ihre Konfiguration wesentlich modularer und wiederverwendbarer.

Hinweis: Die include:-Direktive erfordert Docker Compose v2.20 oder höher. Wenn Ihr System eine ältere Version verwendet, können Sie Dateien mit docker compose -f docker-compose.db.yml -f docker-compose.web.yml up kombinieren.

Migration von docker-compose (v1) zu docker compose (v2)

Der docker compose-Befehl, den Sie in Schritt 1 installiert haben, ist „Compose v2.“. Es handelt sich um ein auf Go basierendes Plugin, das direkt in die Docker-CLI integriert ist.

Die Originalversion, „Compose v1“, war ein separates Python-Tool, das mit docker-compose (mit Bindestrich) aufgerufen wurde. Ab Juli 2023 wird Compose v1 nicht mehr unterstützt und ist veraltet.

Wesentliche Änderungen und Abwärtskompatibilität

  • Der Befehl: Die offensichtlichste Änderung ist der Befehl. Der Bindestrich (docker-compose) ist jetzt ein Leerzeichen (docker compose).
  • Installation: v1 wurde mit pip installiert. v2 ist in Docker Desktop enthalten oder wird als CLI-Plugin installiert, wie Sie es in Schritt 1 getan haben.
  • YAML-Dateien: Ihre docker-compose.yml-Dateien sind nahezu 100 % abwärtskompatibel. Compose v2 unterstützt Dateien der Version 3.x vollständig. Sie müssen Ihre YAML-Dateien für die Migration nicht ändern, nur Ihre Befehle.
  • --project-name Flag: Das -p Flag funktioniert weiterhin, aber das vollständige Flag lautet jetzt --project-name anstelle von --project_name.

Befehls-Migrationshandbuch

Die meisten Befehle sind identisch, nur ohne den Bindestrich. Hier ist eine Tabelle, die gängige v1-Befehle mit ihren v2-Entsprechungen vergleicht.

docker-compose (v1) Befehldocker compose (v2) BefehlNotizen
docker-compose up -d
docker compose up -d
Keine Änderung der Syntax.
docker-compose down
docker compose down
Keine Änderung der Syntax.
docker-compose ps
docker compose ps
Keine Änderung der Syntax.
docker-compose logs
docker compose logs
Keine Änderung der Syntax.
docker-compose stop
docker compose stop
Keine Änderung der Syntax.
docker-compose build
docker compose build
Keine Änderung der Syntax.
docker-compose exec web bash
docker compose exec web bash
Keine Änderung der Syntax.
docker-compose run web bash
docker compose run web bash
run erstellt einen neuen Container. exec führt in einem bestehenden Container aus.
docker-compose up --scale web=3
docker compose up --scale web=3
Das --scale-Flag wird in v2 weiterhin unterstützt.

Wie Sie sehen können, ist für den meisten Alltagsgebrauch die einzige Änderung docker-compose -> docker compose. Wenn Sie Skripte verwenden, können Sie diese einfach aktualisieren, indem Sie den Bindestrich entfernen.

Wenn Sie noch die alte docker-compose v1 installiert haben, können Sie sie entfernen, um Verwirrung zu vermeiden:

sudo pip3 uninstall docker-compose

Oder, wenn es mit apt installiert wurde:

sudo apt remove docker-compose

Fehlerbehebung bei häufigen Docker Compose-Problemen

Wenn Sie mit Docker Compose arbeiten, können Probleme im Zusammenhang mit Dateisyntax, Berechtigungen oder Konflikten zur Laufzeit von Containern auftreten. Die meisten Probleme lassen sich diagnostizieren und beheben, indem Sie systematisch Ihre Konfiguration, Berechtigungen und Containerprotokolle überprüfen.

Werfen wir einen Blick auf einige der häufigsten Fehler und ihre Lösungen.

Zugriff verweigert (Docker-Socket)

Dies ist einer der häufigsten Fehler bei neuen Docker-Nutzern. Sie führen docker compose up aus und sehen eine Fehlermeldung über den Docker-Daemon-Socket.

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
  • Problem: Ihr Nicht-Root-Benutzer hat keine Berechtigung, mit dem Docker-Daemon zu kommunizieren, der als root läuft.

  • Lösung: Sie müssen Ihren Benutzer zur docker-Gruppe hinzufügen, die während der Docker-Installation erstellt wurde.

    1. Fügen Sie Ihren Benutzer der docker-Gruppe hinzu:

      sudo usermod -aG docker ${USER}
    2. Damit die neue Gruppenmitgliedschaft wirksam wird, müssen Sie sich abmelden und wieder anmelden.

    3. Alternativ können Sie die Gruppenänderungen für Ihre aktuelle Terminalsitzung aktivieren, indem Sie Folgendes eingeben:

      newgrp docker

    Dies sollte alle Berechtigungsfehler im Zusammenhang mit dem Docker-Socket beheben.

YAML-Syntax- und Einrückungsfehler

Docker Compose kann nicht ausgeführt werden und meldet, dass Ihre docker-compose.yml-Datei ungültig ist.

ERROR: The Compose file './docker-compose.yml' is invalid because:
services.web.ports contains an invalid type, it should be a list

Oder :

mapping values are not allowed in this context at line 5
  • Problem: Die docker-compose.yml-Datei ist auf eine strikte YAML-Syntax angewiesen. Der häufigste Fehler ist eine falsche Einrückung. YAML verwendet Leerzeichen, keine Tabs, um die Struktur zu definieren.
  • Lösung: Überprüfen Sie sorgfältig die Einrückung Ihrer docker-compose.yml-Datei.

    • Der Standard sind zwei Leerzeichen pro Einrückungsebene.
    • Stellen Sie sicher, dass alle Schlüssel auf derselben Ebene (wie version, services, volumes) in der gleichen Spalte beginnen.
    • Stellen Sie sicher, dass alle Unter-Schlüssel (wie image, ports, volumes unter einem Dienst) zwei Leerzeichen mehr als ihr übergeordneter Dienst (z. B. web) eingerückt sind.
    • Verwenden Sie einen Code-Editor mit einem YAML-Linter, um Syntaxfehler automatisch hervorzuheben.

Portkonflikte

Du versuchst, deine Umgebung zu starten, aber der Befehl schlägt mit einer Fehlermeldung fehl, dass die Adresse bereits verwendet wird.

Error starting userland proxy: listen tcp 0.0.0.0:8000: bind: address already in use
  • Problem: Ein anderer Prozess auf Ihrem Host-Rechner lauscht bereits auf dem Port, den Sie zuzuordnen versuchen (in diesem Fall Port 8000). Dies ist oft ein anderer Docker-Container oder ein lokaler Entwicklungsserver.

  • Lösung: Sie haben zwei Möglichkeiten:

    1. Stoppen Sie den anderen Prozess. Sie können den Prozess, der den Port verwendet, mit diesem Befehl finden:

      sudo lsof -i :8000

      Wenn es ein anderer Docker-Container ist, stoppen Sie ihn mit docker stop <container_id>.

    2. Ändern Sie den Host-Port in Ihrer docker-compose.yml-Datei. Dies ist oft die einfachste Lösung. Ändern Sie die ports-Zuordnung von "8000:80" auf einen anderen Port, zum Beispiel "8001:80".

      ...
      ports:
        - "8001:80" # Changed from 8000
      ...
    3. docker-compose.yml

Dienst schlägt fehl mit Connection Refused (depends_on)

In einer Multi-Service-Anwendung (wie im Beispiel mit WordPress und MySQL) startet der wordpress-Container, aber in seinen Logs wird Connection refused oder MySQL server has gone away angezeigt, wenn versucht wird, eine Verbindung zum db-Dienst herzustellen.

  • Problem: Sie haben depends_on verwendet, aber diese Direktive wartet nur darauf, dass der db-Container gestartet wird. Sie wartet nicht darauf, dass die MySQL-Applikation innerhalb des Containers vollständig initialisiert ist und Verbindungen akzeptieren kann.

  • Lösung: Die Anwendung (in diesem Fall WordPress) muss so konfiguriert werden, dass sie ihre Verbindung erneut versucht. Die meisten modernen Images haben diese Wiederholungslogik bereits integriert. Für Images, die dies nicht tun, müssen Sie eine Healthcheck-Implementierung vornehmen.

    Sie können Ihrem db-Dienst eine healthcheck hinzufügen. Der depends_on-Eintrag des wordpress-Dienstes kann dann so konfiguriert werden, dass er auf eine „gesunde“ Datenbank wartet, nicht nur darauf, dass sie „gestartet“ ist.

Beispiel-Healthcheck für MySQL:

services:
  db:
    image: mysql:8.0
    ...
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p<^your_root_password_here<^>"]
      interval: 10s
      timeout: 5s
      retries: 5

  wordpress:
    image: wordpress:latest
    ...
    depends_on:
      db:
        condition: service_healthy # This now waits for the healthcheck
    ...

Fehler bei Volumes und Bind-Mounts

In den Protokollen Ihres Containers können Berechtigungsfehler auftreten, oder Sie stellen fest, dass das Datenverzeichnis Ihres Containers leer ist.

Datei-/Verzeichnisberechtigungen

  • Problem: Der Container läuft als ein bestimmter Benutzer (z. B. www-data mit der Benutzer-ID 33), aber das Host-Verzeichnis, das Sie eingebunden haben, gehört Ihrem Benutzer (z. B. ubuntu mit der Benutzer-ID 1000). Der Benutzer des Containers hat keine Berechtigung, in das Host-Verzeichnis zu schreiben.

  • Lösung: Ändern Sie den Besitz des Host-Verzeichnisses, damit er mit der Benutzer-ID im Container übereinstimmt. Sie können die Benutzer-ID des Containers herausfinden, indem Sie docker compose exec <service_name> id ausführen. Zum Beispiel, wenn die ID 33 ist (üblich für www-data):

    sudo chown -R 33:33 ./wp_content

Relative Pfadprobleme

  • Problem: Ihre docker-compose.yml verwendet einen relativen Pfad wie ./app, aber Ihre index.html-Datei wird nicht bereitgestellt.

  • Lösung: Docker Compose interpretiert relative Pfade aus dem Verzeichnis, in dem Sie den Befehl docker compose up ausführen. Führen Sie Compose-Befehle stets aus dem gleichen Verzeichnis aus, das Ihre docker-compose.yml-Datei enthält.

Netzwerk- und Diensterkennung

Die Protokolle Ihres Anwendungscontainers zeigen Host nicht gefunden oder Konnte Host nicht auflösen: db.

  • Problem: Dein wordpress-Container kann den db-Container im Netzwerk nicht finden.
  • Lösung: Standardmäßig erstellt Docker Compose ein Netzwerk und verbindet alle Dienste damit. Dienste können einander über ihre Dienst-Namen finden.

    1. Dienstnamen überprüfen: Stellen Sie sicher, dass der Hostname in der Konfiguration Ihrer Anwendung (z. B. die Umgebungsvariable WORDPRESS_DB_HOST) genau derselbe ist wie der Dienstname in Ihrer docker-compose.yml (z. B. db).

    2. Netzwerk überprüfen: Verwenden Sie docker compose ps, um den Namen Ihres Projekts zu finden (z. B. compose-demo). Anschließend überprüfen Sie das Standardnetzwerk:

      docker network inspect compose-demo_default

      Die JSON-Ausgabe listet alle Container auf, die an dieses Netzwerk angeschlossen sind. Wenn einer Ihrer Dienste fehlt, überprüfen Sie Ihre docker-compose.yml auf benutzerdefinierte networks-Konfigurationen, die ihn isolieren könnten.

Befehlsabweichung (v1 vs. v2)

Sie geben docker-compose up (mit einem Bindestrich) ein und sehen einen Fehler „Befehl nicht gefunden“.

docker-compose: command not found
  • Problem: Sie versuchen, den Befehl für Compose v1 zu verwenden, ein veraltetes Python-Tool. Diese Anleitung installiert Compose v2, ein Plugin, das direkt in die Docker-CLI integriert ist.
  • Lösung: Verwenden Sie den richtigen Befehl, indem Sie den Bindestrich (-) durch ein Leerzeichen ersetzen.
docker-compose (v1)docker compose (v2)
docker-compose updocker compose up
docker-compose downdocker compose down
docker-compose psdocker compose ps
docker-compose logsdocker compose logs

Verwenden Sie beim Befolgen dieser Anleitung immer docker compose (mit Leerzeichen).

Häufig gestellte Fragen

1. Wofür wird Docker Compose verwendet?

Docker Compose ist ein Tool zum Definieren und Ausführen von Multi-Container-Docker-Anwendungen.

Es verwendet eine einzelne YAML-Datei (standardmäßig docker-compose.yml), um alle Komponenten Ihrer Anwendung zu konfigurieren, die als Services bezeichnet werden. Diese Datei definiert auch die Netzwerke, die den Services die Kommunikation untereinander ermöglichen, sowie die Volumes, die für persistente Daten verwendet werden.

Mit dieser einzigen Datei können Sie Ihren gesamten Anwendungs-Stack mit einfachen Befehlen verwalten:

  • docker compose up startet und führt Ihre gesamte Anwendung aus, einschließlich aller angegebenen Container, Netzwerke und Volumes.
  • docker compose down stoppt und entfernt alle von Ihrer Anwendung erstellten Container, Netzwerke und Volumes.

Es ist besonders nützlich für die Verwaltung von Anwendungen, die mehrere Komponenten benötigen, wie beispielsweise eine Website, die einen Webserver (wie Nginx), ein Anwendungs-Backend (wie WordPress) und eine Datenbank (wie MySQL) benötigt.

2. Wie installiere ich Docker Compose auf Ubuntu?

Die empfohlene Methode ist, Docker Compose als Plugin für die Docker-CLI zu installieren. Dies erfolgt durch die Installation des docker-compose-plugin-Pakets aus dem offiziellen apt-Repository von Docker.

  1. Stellen Sie zunächst sicher, dass Sie der offiziellen Docker-Dokumentation gefolgt sind, um das apt-Repository von Docker auf Ihrem Ubuntu-System einzurichten.

  2. Aktualisiere deine Paketliste:

    sudo apt update
  3. Installieren Sie das Docker Compose-Plugin:

    sudo apt install docker-compose-plugin
  4. Überprüfen Sie die Installation, indem Sie die Version prüfen. Der Befehl verwendet ein Leerzeichen, keinen Bindestrich.

    docker compose version

3. Wie aktualisiere ich Docker Compose auf die neueste Version?

Da Docker Compose (v2) als Systempaket über apt installiert ist, können Sie es über den standardmäßigen Ubuntu-Software-Update-Prozess aktualisieren.

  1. Aktualisieren Sie Ihren lokalen Paketindex:

    sudo apt update
  2. Führen Sie ein systemweites Upgrade durch, das das Compose-Plugin einschließt:

    sudo apt upgrade

    Alternativ, wenn Sie nur das Plugin selbst aktualisieren möchten, können Sie Folgendes ausführen:

    sudo apt install --only-upgrade docker-compose-plugin

4. Kann Docker Compose in Produktionsumgebungen eingesetzt werden?

Ja, Docker Compose wird häufig in der Produktion verwendet, insbesondere für Anwendungen, die auf einem einzelnen Host laufen.

Es bietet eine einfache Möglichkeit, die Dienste, Netzwerke und Volumes Ihrer Anwendung zu definieren, bereitzustellen und deren Lebenszyklus zu verwalten. Für eine Einzelserverbereitstellung ist es eine sehr effektive und leicht zu verwaltende Lösung.

Für komplexere Szenarien, die die Koordination von Containern über mehrere Hosts (ein Cluster) erfordern, sind andere Tools üblicher. Dazu gehören Docker Swarm (das eine ähnliche Compose-Datei-Syntax verwendet) und Kubernetes (der Industriestandard für groß angelegte Container-Orchestrierung).

5. Was ist der Unterschied zwischen Docker und Docker Compose?

Diese Tabelle zeigt die wichtigsten Unterschiede zwischen der Docker CLI und der Docker Compose CLI auf.

Funktiondocker (Docker-Engine)docker compose (Compose-Plugin)
UmfangVerwaltet einzelne Docker-Objekte.Verwaltet eine vollständige Multi-Container-Anwendung als eine einzelne Einheit.
HauptverwendungImages erstellen (docker build), einzelne Container ausführen (docker run), Container verwalten (docker ps), Images, Volumes und Netzwerke.Orchestrierung mehrerer Dienste, die in einer docker-compose.yml-Datei definiert sind.
BefehleNiedrigstufige Befehle, die auf ein Objekt fokussiert sind. Beispiel: docker run -d -p 80:80 -v ./:/app nginxHochrangige Befehle für die gesamte Anwendung. Beispiel: docker compose up
AnalogieEin Baustein (ein einzelner Container).Der Plan und der Bauleiter für das gesamte Gebäude (die Anwendung).

Kurz gesagt, Sie verwenden docker, um mit einem einzelnen Container zu interagieren. Mit docker compose verwalten Sie Ihre gesamte Anwendungsumgebung (z. B. Web, App, DB) auf einmal.

6. Wie führe ich mehrere Container mit Docker Compose aus?

Sie betreiben mehrere Container, indem Sie sie in Ihrer docker-compose.yml-Datei als Services definieren.

  1. Erstellen Sie eine Datei mit dem Namen docker-compose.yml.

  2. Verwenden Sie in dieser Datei den Schlüssel services:, um jeden Container zu definieren, den Sie ausführen möchten.

    Hier ist ein praktisches Beispiel, das zwei Container definiert und ausführt: eine WordPress-Website und eine MySQL-Datenbank.

    services:
      db:
        # This is the first service (container)
        image: mysql:8.0
        environment:
          MYSQL_ROOT_PASSWORD: <^your_password_here<^>
          MYSQL_DATABASE: wordpress
        volumes:
          - db_data:/var/lib/mysql
    
      wordpress:
        # This is the second service (container)
        image: wordpress:latest
        ports:
          - "8001:80"
        environment:
          WORDPRESS_DB_HOST: db
          WORDPRESS_DB_PASSWORD: <^your_password_here<^>
        depends_on:
          - db
    
    volumes:
      db_data:
  3. docker-compose.yml

  4. Speichern Sie die Datei und öffnen Sie ein Terminal im selben Verzeichnis.

  5. Führen Sie einen einzigen Befehl aus, um beide Container zu starten:

    docker compose up -d

Docker Compose wird die Datei lesen, ein gemeinsames Netzwerk für die Dienste erstellen, sowohl die mysql- als auch die wordpress-Images herunterladen und für jeden Dienst einen Container starten.

7. Warum Docker Compose für die Entwicklung verwenden?

Docker Compose ist ein Standardwerkzeug für Entwicklungsumgebungen, da es mehrere häufige Probleme löst.

  • Konstante Umgebungen: Es stellt sicher, dass jeder Entwickler in einem Team genau die gleichen Dienste (Datenbank, Cache, Webserver) mit genau den gleichen Versionen und Konfigurationen nutzt. Dies wird in der docker-compose.yml-Datei definiert, die in die Versionskontrolle übernommen wird. Dadurch wird das Problem „bei mir funktioniert es“ beseitigt.

  • Einfache Handhabung: Es ersetzt komplexe Installationsskripte und lange docker run-Befehle. Ein Entwickler muss nur docker compose up ausführen, um den gesamten Anwendungsstack zu starten, und docker compose down, um ihn zu stoppen.

  • Service-Isolierung: Entwickler können an mehreren Projekten auf derselben Maschine arbeiten, ohne dass Abhängigkeitskonflikte auftreten. Projekt A kann PostgreSQL 9.6 verwenden und Projekt B PostgreSQL 14, da jede Datenbank in einem isolierten Container läuft, der von ihrer eigenen Compose-Datei verwaltet wird.

  • Einfache Integrationstests: Da Compose alle Abhängigkeiten einer Anwendung zusammen startet, schafft es eine ideale lokale Umgebung, um Integrationstests durchzuführen, die überprüfen, wie die Dienste miteinander interagieren.

Schlussfolgerung

In diesem Leitfaden haben Sie Docker Compose installiert und eine vollständige Multi-Container-Anwendung konfiguriert. Sie haben mit einer grundlegenden docker-compose.yml-Datei für einen Nginx-Webserver begonnen und sind zu einem komplexeren, realistischeren Stack übergegangen, der eine WordPress-Anwendung und eine MySQL-Datenbank umfasst. Sie haben gelernt, den gesamten Anwendungslebenszyklus zu verwalten, vom Erstellen und Ausführen von Diensten bis hin zum Stoppen und Entfernen dieser.

Sie sind nun mit den wichtigsten Konzepten zur effektiven Verwaltung von Anwendungen vertraut, einschließlich der Skalierung von Diensten, benutzerdefinierten Netzwerkkonfigurationen und der Aufteilung Ihrer Konfiguration in modulare Dateien mithilfe der include-Direktive. Wenn Sie dem Migrationsleitfaden und den Schritten zur Fehlerbehebung folgen, können Sie auch häufige Probleme wie Portkonflikte, „Zugriff verweigert“-Fehler und YAML-Syntaxfehler beheben. Die hier behandelten Fähigkeiten ermöglichen es Ihnen, konsistente, reproduzierbare Entwicklungsumgebungen zu erstellen und Single-Host-Anwendungen mit Zuversicht bereitzustellen.

Für eine vollständige Übersicht aller verfügbaren docker compose-Befehle werfen Sie einen Blick in die offizielle Dokumentation.

Für weitere Tutorials rund um Docker, schauen Sie sich die folgenden Artikel an:

  • Wie man Docker auf Ubuntu installiert – Schritt-für-Schritt-Anleitung
  • Wie man WordPress mit Docker Compose installiert

Danke, dass Sie mit der Linux-Console.net-Community lernen.