Zum Inhalt springen

Docker Compose

Ein docker run mit Port, drei Volumes und acht Umgebungsvariablen ist eine Zeile, die niemand mehr lesen will. Und eine richtige Anwendung besteht selten aus einem Container: Nextcloud braucht eine Datenbank, ein Blog braucht Webserver plus Datenbank plus Cache. Docker Compose beschreibt alle Container einer Anwendung in einer YAML-Datei und startet, stoppt und aktualisiert sie mit einem Befehl. Die Datei liegt im Projektordner und gehört in Git, damit sie dokumentiert und wiederholbar ist.

Compose ist seit Version 2 Teil von Docker (docker compose, ohne Bindestrich). Das Plugin hast du auf der vorherigen Seite mitinstalliert:

Terminal-Fenster
docker compose version

Ein kleiner Stack mit Webserver und Datenbank, um die Elemente zu zeigen:

compose.yaml
services:
web:
image: nginx:1.27
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
depends_on:
- db
restart: unless-stopped
db:
image: mariadb:11.4
environment:
MARIADB_ROOT_PASSWORD: geheim
volumes:
- dbdaten:/var/lib/mysql
restart: unless-stopped
volumes:
dbdaten:
Schlüssel Bedeutung
services Ein Eintrag pro Container. Der Name (web, db) ist gleichzeitig der Hostname im internen Netz: web erreicht die Datenbank unter db.
image Image und Tag, wie bei docker run.
ports Port-Mapping Host:Container, in Anführungszeichen, weil YAML 8080:80 sonst als Zeitangabe lesen könnte.
volumes Bind-Mounts (beginnen mit ./ oder /) oder Named Volumes, die unten unter volumes: deklariert werden.
environment Umgebungsvariablen für die Konfiguration des Containers. Was ein Image versteht, steht in seiner Beschreibung auf Docker Hub.
depends_on Startreihenfolge. web startet erst, wenn db gestartet ist.
restart unless-stopped startet den Container nach einem Reboot automatisch neu, ausser du hast ihn selbst gestoppt.

YAML ist einrückungsempfindlich: immer zwei Leerzeichen, nie Tabulatoren. docker compose config liest die Datei und zeigt sie aufgelöst an, das ist dein Syntax-Check.

Alle Befehle laufen im Ordner mit der compose.yaml:

Befehl Zweck
docker compose up -d Images laden, Netz und Volumes anlegen, alle Container starten
docker compose ps Status des Stacks
docker compose logs -f Logs aller Container mitlesen, logs -f db nur eines
docker compose exec db bash Befehl in einem laufenden Container
docker compose pull Neue Images laden, ohne etwas zu starten
docker compose down Container und Netz entfernen. Volumes bleiben.
docker compose down -v Dasselbe inklusive Volumes. Daten sind danach weg.

Nextcloud ist eine eigene Cloud für Dateien, Kalender und Kontakte. Das offizielle Image braucht eine Datenbank, also werden es zwei Container. Passwörter gehören nicht in die compose.yaml, sondern in eine Datei .env im selben Ordner. Compose liest sie automatisch und setzt ${VARIABLE} ein.

  1. Projektordner anlegen:
    Terminal-Fenster
    mkdir -p ~/nextcloud && cd ~/nextcloud
  2. Die compose.yaml. Der Healthcheck sorgt dafür, dass Nextcloud erst startet, wenn MariaDB wirklich Verbindungen annimmt:
    compose.yaml
    services:
    db:
    image: mariadb:11.4
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
    volumes:
    - db:/var/lib/mysql
    environment:
    MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    MARIADB_DATABASE: nextcloud
    MARIADB_USER: nextcloud
    MARIADB_PASSWORD: ${DB_PASSWORD}
    healthcheck:
    test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
    interval: 10s
    timeout: 5s
    retries: 5
    app:
    image: nextcloud:stable
    restart: unless-stopped
    ports:
    - "8080:80"
    depends_on:
    db:
    condition: service_healthy
    volumes:
    - nextcloud:/var/www/html
    environment:
    MYSQL_HOST: db
    MYSQL_DATABASE: nextcloud
    MYSQL_USER: nextcloud
    MYSQL_PASSWORD: ${DB_PASSWORD}
    NEXTCLOUD_ADMIN_USER: ${NC_ADMIN_USER}
    NEXTCLOUD_ADMIN_PASSWORD: ${NC_ADMIN_PASSWORD}
    NEXTCLOUD_TRUSTED_DOMAINS: ${NC_TRUSTED_DOMAINS}
    volumes:
    db:
    nextcloud:
  3. Die .env mit den Geheimnissen. Passwörter erzeugst du mit openssl rand -hex 16, bei NC_TRUSTED_DOMAINS trägst du die IP deiner VM ein, sonst lehnt Nextcloud den Zugriff ab:
    .env
    DB_ROOT_PASSWORD=f2b1...
    DB_PASSWORD=9c4e...
    NC_ADMIN_USER=vorname
    NC_ADMIN_PASSWORD=7a0d...
    NC_TRUSTED_DOMAINS=10.0.0.42
  4. Prüfen, dass die Variablen eingesetzt werden, dann starten:
    Terminal-Fenster
    docker compose config | grep -i password
    docker compose up -d
    docker compose ps
    docker compose logs -f app
    Der erste Start dauert ein bis zwei Minuten, weil Nextcloud die Datenbank einrichtet. Sobald im Log Initializing finished steht, öffnest du http://IP-DEINER-VM:8080 und meldest dich mit dem Benutzer aus der .env an.
  • Ordnernextcloud/
    • compose.yaml
    • .env Passwörter, nicht in Git
    • .env.example Vorlage mit Platzhaltern, in Git
    • .gitignore

Neue Versionen der Images kommen regelmässig. Der Ablauf ist immer derselbe:

Terminal-Fenster
docker compose pull
docker compose up -d
docker image prune

up -d ersetzt nur die Container, deren Image sich geändert hat. Die Daten liegen in den Volumes und bleiben erhalten. image prune räumt die alten Images weg. Bei Nextcloud gilt zusätzlich: Nur eine Hauptversion auf einmal, darum der Tag stable statt latest.

Was in Modul 10 für Verzeichnisse galt, gilt hier für die Volumes: Ohne Backup ist der Stack nur so sicher wie die Disk der VM. Zwei Dinge sind zu sichern, die Datenbank und die Dateien.

Terminal-Fenster
# Datenbank als SQL-Dump, lesbar und unabhängig von der MariaDB-Version
docker compose exec db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" nextcloud' > nextcloud-$(date +%F).sql
# Dateien: Stack anhalten, Volume mit einem Hilfscontainer packen, weiterlaufen lassen
docker compose stop
docker run --rm -v nextcloud_nextcloud:/daten:ro -v "$PWD":/backup ubuntu tar czf /backup/nextcloud-dateien-$(date +%F).tgz -C /daten .
docker compose start

Der Name des Volumes setzt sich aus Projektordner und Volume-Namen zusammen, docker volume ls zeigt ihn dir. Die beiden Dateien kopierst du anschliessend mit rsync oder scp auf einen anderen Rechner, genau wie in Modul 10.

Lösung anzeigen

Die compose.yaml entspricht dem Listing oben, sie liegt auch unter scripts/linux/11-container-projekt/compose.yaml im Repository, zusammen mit einer .env.example.

Terminal-Fenster
cd ~/nextcloud
script ~/lernplattform/labs/linux/11-container-projekt/compose.txt
docker compose ps
docker compose logs --tail 20 app
docker volume ls
docker compose exec db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" nextcloud' > nextcloud-dump.sql
ls -lh nextcloud-dump.sql
# down entfernt Container und Netz, die Volumes und damit alle Dateien bleiben.
# down -v entfernt auch die Volumes, die Dateien und die Datenbank sind weg.
exit
cp compose.yaml .env.example ~/lernplattform/labs/linux/11-container-projekt/

Selbstcheck · 5 Fragen

1. Wie erreicht der Container app die Datenbank?
2. Was passiert bei `docker compose down`?
3. Warum stehen Passwörter in einer .env und nicht in der compose.yaml?
4. Wie aktualisierst du den Stack auf neue Images?
5. Welche Aussagen zu Volumes stimmen? (mehrere Antworten möglich)