Skip to content

Lab 3: Komplexe Zusammenstellungen mit Docker-Compose

Bisher haben Sie Docker-Container mit docker run gestartet. Schon in den ersten Beispielen, in denen Volumes und Ports zum Einsatz kamen, wurden die Befehle lang und unübersichtlich.

Ein Befehl wie

docker run \
-p 80:80 \
-p 443:443 \
-v /path/to/file:/etc/file \
-v /config.conf:/etc/config.conf \
-e DATABASE='foo' \
-e DATABASE_HOST='bar' \
-e DATABASE_PASSWORD='secret' \
--name testserver nginx:latest

ist auf Dauer keine Lösung. Das Grundprinzip "Ein Prozess, ein Container" hat zur Folge, dass man für die meisten Anwendungen mehr als einen Container braucht. Zum Glück gibt es Docker-Compose – das ist der Weg, wie Sie zukünftig mit Docker arbeiten möchten.

Prüfen Sie, ob Docker-Compose installiert ist:

docker compose version

Grundlagen: YAML

Docker-Compose arbeitet mit YAML-Dateien. YAML ist eine Auszeichnungssprache für Objekte und in der Cloud-Native-Welt. YAML arbeitet mit Einrückungen zur Auszeichnung von Verschachtelungen:

auto:
  name: Golf
  hersteller:
    name: Volkswagen
    ort:
      name: Wolfsburg
      plz: 38440
  tags:
    - auto
    - kfz

2. WordPress in Containern

Ein gutes Beispiel ist ein WordPress-Blog. WordPress braucht:

  • einen Container mit dem Webserver (Apache)
  • einen Datenbankserver (MariaDB oder MySQL)
  • der Webserver muss mit seiner Datenbank sprechen können.
  • Port 80 des Containers muss auf der externen Netzwerkkarte lauschen

Legen Sie eine Datei mit dem Namen "docker-compose.yml" an. Das ist der Standardname, den Docker-Compose erwartet. Die folgende Zusammenstellung beschreibt eine simple WordPress-Zusammenstellung:

version: "3.8"

services:
  db:
    image: mysql:5.7
    volumes:
      - ./data/db/:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: secret123root
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: 12345wordpress54321

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "80:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: 12345wordpress54321
    working_dir: /var/www/html
    volumes:
      - ./data/wordpress:/var/www/html/wp-content

Wenn die Datei auf dem Server liegt, können Sie die Zusammenstellung starten:

docker compose up

Jetzt brauchen Sie etwas Geduld: Docker lädt die unhandlichen Images aus dem Hub herunter und fährt die Datenbank hoch. Das dauert, weil die Datenbank noch leer ist – MySQL richtet sich erstmal ein.

Wie bei docker run gibt es auch bei Docker-Compose einen detached-Modus. Ein fertiges Setup würden Sie mit starten mit:

docker compose up -d

Das Gegenteil von up lautet (logisch):

docker compose down

Und auch andere bekannte Befehle finden Sie wieder:

docker compose ps
docker compose exec -it <service> sh

2.2 Umgebungsvariablen

Die Konfiguration gehört nicht in die Compose-Datei! Sie sollten die Compose-Datei so flexibel wie möglich halten. Dann ist es leicht, eine Dev-, Staging- und Prod-Umgebung aus demselben File zu erzeugen.

Docker-Compose arbeitet dafür mit Ersetzungen:

wordpress:
  depends_on:
    - db
  image: "wordpress:${TAG}"
  ports:
    - "80:80"
  restart: always
  environment:
    WORDPRESS_DB_HOST: db:3306
    WORDPRESS_DB_USER: ${DB_USER}
    WORDPRESS_DB_PASSWORD: ${DB_PASS}
  working_dir: /var/www/html
  volumes:
    - ./data/wordpress:/var/www/html/wp-content

Diese Ersetzungen kommen aus einer Datei mit dem Namen .env, die sich neben dem Compose-File befinden muss:

TAG=latest
DB_USER=wordpress
DB_PASS=secret

2.2 Wenn es mal wieder länger dauert

Ein häufiges Problem: Ich weiß, dass meine Anwendung beim Stoppen länger braucht – weil ich zum Beispiel erst alle Daten aus dem Speicher sichere. Normalerweise fackelt Docker nicht lange und sendet schon 10 Sekunden nach einem SIGTERMdirekt den SIGKILL. Wenn ich meiner Anwendung die Zeit geben will, in Ruhe herunterzufahren, teile ich das im Compose-File mit:

slow_service:
  image: slow-image:slow
  stop_grace_period: 2m

3: Docker-Compose macht vieles einfacher:

  • Die Struktur wird schnell sichtbar
  • Mit depends_on bestimmen Sie (grob), welcher Container zuerst startet
  • Pfadangaben funktionieren relativ vom Pfad des Docker-Compose-Files

Infrastruktur ist Code

Um dem Ziel einen wesentlichen Schritt näher zu kommen, eine reproduzierbare Umgebung zu bauen, sollten Sie Ihre Docker-Compose-Files von Anfang an in eine Versionsverwaltung legen (Git). Und auch Dockerfiles von eigenen Images gehören in die Versionsverwaltung. Im nächsten Schritt wird dann automatisch gebaut (Continuous Integration).

Guter Stil ist es, eine vorbereitete `.env-example` bereitzulegen. Die kann ein Nutzer des Repos umbenennen (`mv .env-example .env`) und direkt starten.