Docker Compose
YAML
- textbasiertes Dateiformat
- zur Datenserialisierung
- rekursives Akronym: "YAML Ain't Markup Language"
Links
- Spezifikation unter yaml.org
- Validator unter Code Beautify - YAML Validator
- dockerdocs - Compose file reference
Syntax
# this is a comment
# key-value: with colon+space
key: value
# section
---
--- # lists: with hyphen+space
list:
- Casablanca
- North by Northwest
- The Man Who Wasn't There
- key1OfObjectInList: value # block in list
key2OfObjectInList: value2
key3OfObjectInList:
- item1
- item2: 90 # block in list
inlineList: [ milk, pumpkin pie, eggs, juice ]
--- # blocks / objects
# IMPORTANT: shifting must consist of two spaces! No tabs!
intendedBlock:
name: John Smith
age: 33
inlineBlock: { name: John Smith, age: 33 }
--- # text
text1: "This is a text"
text2: 'This is a text'
text3: This is a text # most used
text4: "This is a text with an escaped sequence\nand a second line"
multiLineText1: |
In this text, newlines are preserved.
This is a second line.
By default, indentation of the first line is ignored.
So he carefully sat on the ceiling
multiLineText2: >
In this text, newlines are not preserved.
Wrapped lines
will be folded into
a single paragraph.
But blank lines denote
paragraph breaks.
--- # numbers
integer: 123 # an integer
numberAsString: "123" # a string, disambiguated by quotes
float: 123.0 # a float
--- # booleans
booleanTrue: true
booleanFalse: false
--- # explicit data types (prefixed by !!)
explicitFloat: !!float 123
explicitStringOfInteger: !!str 123
explicitStringOfBoolean: !!str true
--- # binary
picture: !!binary |
R0lGODdhDQAIAIAAAAAAANn
Z2SwAAAAADQAIAAACF4SDGQ
ar3xxbJ9p0qa7R0YxwzaFME
1IAADs=
--- # anchor and reference to it
- step: &id001 # anchor
instrument: Lasik 2000
pulseEnergy: 5.4
- step: &id002
instrument: Lasik 2000
pulseEnergy: 5.0
- Instrument1: *id001 # refers to the first step (anchor &id001)
- Instrument2: *id002 # refers to the second step (anchor &id002)
Hinweis: Booleans werden in YAML 1.1 anders als in YAML 1.2.2 definiert. Siehe:
Grundlagen
- Definierung von Applikations-Umgebungen aus mehreren Containern
- Auswertung der Datei
docker-compose.yml
docker-compose.yml
- alle Konfigurationen für einzelne Container
Installation
Docker Compose sollte bereits mit Docker installiert sein. Wenn nicht, kann es mit dem folgenden Befehl installiert werden:
sudo apt install docker-compose-plugin
Überprüfung der Version:
docker compose version
docker-compose.yml
Referenz: Compose file reference
Grundlegender Aufbau
services:
dienstname1:
schlüsselwort1: einstellung1
schlüsselwort2: einstellung2
# ...
dienstname2:
schlüsselwort1: einstellung1
schlüsselwort2: einstellung2
# ...
volumes:
volume1:
driver: local
volume2:
driver: local
# ...
networks:
netzwerk1:
driver: bridge
netzwerk2:
driver: bridge
# ...
secrets:
secret1:
file: ./secret1.txt
secret2:
file: ./secret2.txt
# ...
Top-Level-Schlüsselwörter
Top-Level-Schlüsselwort | Bedeutung |
---|---|
services | Definition der Container (Services). Dienstnamen (Keys) für Container frei wählbar |
networks | Definition der Netzwerke |
volumes | Definition der benannten Volumes |
configs | Konfigurierung. Lässt Services ihr Verhalten anpassen, ohne das Docker image neu bilden zu müssen |
secrets | Definition der Passwortdateien |
services
Schlüsselwort | Bedeutung |
---|---|
image | Basisimage eines Services |
build | Verzeichnis mit Dockerfile, aus dem Image erstellt wird |
container_name | Name für Container |
restart | always , on-failure oder unless-stopped |
environment | Liste mit Umgebungsvariablen |
ports | Liste der Portweiterleitungen |
expose | Ports für Kommunikation zwischen Containern |
networks | Verweis auf ein im Top-Level-Schlüsselwort definiertes Netzwerk |
image
- Angabe des Basisimages
- wenn Basisimage im Docker Hub vorhanden ist, kann es direkt verwendet werden, sonst wird es heruntergeladen
services:
my-service:
image: ubuntu:latest
# ...
build
- wird ein Image benötigt, kann dieses aus
Dockerfile
erstellt werden - gibt Verzeichnis an, in dem sich das
Dockerfile
befindet - Beispiele:
.
,./path/to/dockerfile/
,/path/to/dockerfile/
services:
my-custom-app:
build: /path/to/dockerfile/
# ...
container_name
- Name des Containers
- analog
--name
beidocker run
- wird dies nicht angegeben, werden für Namen folgende Werte zusammengesetzt:
- Arbeitsverzeichnis
- Servicename
- Laufnummer
- Beispiel:
workdir-my-custom-app-1
- Name des Services ist nicht gleich Name des Containers
services:
my-custom-app:
container_name: my-container
# ...
restart
- Definierung der Restart-Policy für Container
Wert | Bedeutung |
---|---|
no | kein automatischer Neustart |
on-failure[:max-retries] | automatischer Neustart bei Fehler (Exit-Code ungleich 0), max-retries : maximale Versuche |
always | immer automatischer Neustart, insbesondere bei Reboot. Bei manuellem Stopp: Container-Neustart bei Dockerdaemon-Neustart |
unless-stopped | immer automatischer Neustart. Bei manuellem Stopp: kein Container-Neustart bei Dockerdaemon-Neustart |
services:
my-custom-app:
restart: unless-stopped
# ...
ports
- Portweiterleitungen
services:
my-custom-app:
image: myapp:latest
ports:
- 8080:3000
- "8081:4000"
# ...
expose
- Ports für Kommunikation zwischen Containern
- wenn Basisimage bereits Port exponiert, ist diese Angabe nicht notwendig
services:
network-example-service:
image: karthequian/helloworld:latest
expose:
- 80
networks
- Angabe eines unter dem Top-Level-Schlüsselwort
networks
definierten Netzwerks
services:
container:
image: karthequian/helloworld:latest
networks:
- my_network
# ...
# Top-Level-Schlüsselwort
networks:
my_network:
Normalerweise werden bei der Definition des Netzwerks keine weiteren Optionen angegeben. Docker kümmert sich dann selbst um die konkrete Definition.
Möchte man selbst die IP-Adresse(n) und den Gateway angeben, kann dies wie folgt gemacht werden:
services:
network-example-service:
image: karthequian/helloworld:latest
networks:
my_network:
ipv4_address: 192.168.0.10
# ...
another-service-in-the-same-network:
image: alpine:latest
networks:
my_network:
ipv4_address: 192.168.0.11
# ...
networks:
my_network:
ipam:
config:
- subnet: 192.168.0.0/24
gateway: 192.168.0.1
Weist man den Containern keine IP-Adressen hinzu, werden sie automatisch (per Docker-internem DHCP) zugewiesen.
volumes
- Angabe eines unter dem Top-Level-Schlüsselwort
volumes
definierten Volumes - Mounten eines Containervolumes auf Host
- benannte Volumes
- müssen im Top-Level-Schlüsselwort
volumes
angegeben werden - können von mehreren Containern gleichzeitig verwendet werden
- müssen im Top-Level-Schlüsselwort
- unbenannte Volumes und Volumes in eigenen Verzeichnissen
- müssen nicht im Top-Level-Volume aufgeführt werden
- es können auch einzelne Dateien gemountet werden
- Volume-Zusätze
:ro
: Read-Only
- Kurze Syntax:
VOLUME:CONTAINER_PATH[:ACCESS_MODE]
services:
volumes-example-service:
image: alpine:latest
volumes:
- my-named-global-volume:/my-volumes/named-global-volume
- /tmp:/my-volumes/host-volume
- /home:/my-volumes/readonly-host-volume:ro
# ...
another-volumes-example-service:
image: alpine:latest
volumes:
- my-named-global-volume:/another-path/the-same-named-global-volume
# ...
volumes:
my-named-global-volume:
depends_on
- Angabe der Abhängigkeiten zwischen den Containern
kurze Syntax:
services:
kafka:
image: wurstmeister/kafka:2.11-0.11.0.3
depends_on:
- zookeeper
# ...
zookeeper:
image: wurstmeister/zookeeper
# ...
lange Syntax:
restart
true
: Container wird neu gestartet, wenn der abhängige Container geupdated wirdfalse
condition
service_started
service_healthy
service_completed_successfluly
required
true
false
: Compose warnt einen nur, wenn abhängige Container nicht gestartet werden konnte oder unverfügbar ist
services:
my-container:
image: my-image
depends_on:
other-container:
restart: <true/false>
condition: service_started
# ...
Um auf einen Container zu warten, bis dieser bereit ist, kann der healthcheck
-Befehl beim anderen Container verwendet werden.
Bei depends_on
muss dabei dann condition: service_healthy
angegeben werden.
services:
wordpress:
# ...
depends_on:
db:
condition: service_healthy
# ...
db:
# ...
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 2s
timeout: 5s
retries: 5
start_period: 2s
# ...
# ...
environment
- Definierung statischer und dynamischer Umgebungsvariablen
- dynamischer Zugriff: mit
${ENV_VAR_NAME}
services:
database:
image: postgres:${POSTGRES_VERSION}
environment:
DB: mydb
USER: "${USER}"
Dies ist äquivalent zu:
services:
database:
image: postgres:${POSTGRES_VERSION}
environment:
- DB=mydb
- USER="${USER}"
Dynamische Variablen können dabei in einer .env
-Datei im selben Verzeichnis als Key-Value-Paare definiert werden.
POSTGRES_VERSION=alpine
USER=foo
Dateinamen:
.env
: Docker verwendet diese Datei automatisch- andere Namen: müssen explizit mit
env_file: <filename>
angegeben werden
secrets
- Angabe eines unter dem Top-Level-Schlüsselwort
secrets
definierten Secrets - Top-Level-Schlüsselwort
secrets
gibt an, wo sich die Passwortdatei befindet - Einträge bei Services referenzieren Top-Level-Definition
services:
db:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_PASSWORD_FILE: /run/secrets/db_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
secrets:
- db_root_password
- db_password
# ...
secrets:
db_password:
file: db_password.txt
db_root_password:
file: db_root_password.txt
Vorgehen
- Secret-Datei erstellen
secrets
-Eintrag indocker-compose.yml
definierenservices.<container>.secrets
-Einträge indocker-compose.yml
definieren/run/secrets/<secretname>
im Container verwenden
healthcheck
- Angabe eines Healthchecks/Gesundheitscheck
- andere Services/Container, welche von diesem Container abhängig sind, werden erst gestartet, wenn der Healthcheck/Test dieses Containers erfolgreich ist
joomla:
container_name: joomla
image: joomla
depends_on:
db:
condition: service_healthy
# networks, volumes, ports, environment
# ...
db:
# healthcheck: joomla will wait and check all 10 seconds if db is ready and up
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
Anwendung
Referenz: dockerdocs - CLI reference - docker compose
docker compose up
- Container-Umgebung erstellen
- Container-Umgebung wird nach
docker-compose.yml
im aktuellen Verzeichnis erstellt und gestartet - deshalb: zuerst in Verzeichnis wechseln, in der sich die
docker-compose.yml
-Datei befindet
docker compose up [OPTIONS] [SERVICE...]
Option | Beschreibung |
---|---|
-d | daemon , Applikation wird im Hintergrund gestartet |
--build | Images werden neu gebaut, bevor die Container gestartet werden |
Beispiel:
docker compose up -d --build
docker compose down
- Container-Umgebung stoppen
- stoppt Container-Umgebung nach
docker-compose.yml
im aktuellen Verzeichnis und löscht alle Container sowie Netzwerke
docker compose down [OPTIONS] [SERVICES]
Option | Beschreibung |
---|---|
-v | entfernt zusätzlich die Volumes |
Beispiel:
docker compose down
docker compose exec
- Ausführen eines Befehls in einem laufenden Container
docker compose exec [OPTIONS] SERVICE COMMAND [ARGS...]
Beispiel:
docker compose exec db mysqladmin ping -h localhost -uroot -p
docker compose exec -it wordpress sh
docker compose exec -it wordpress /bin/bash
docker compose logs
- Anzeigen der konsolidierten Logs aller Services
docker compose logs [OPTIONS] [SERVICE...]
Option | Beschreibung |
---|---|
-f | zeigt Live-Logs an, analog zu tail -f |
Beispiel:
docker compose logs -f web
docker compose build
- baut Container-Images gemäss der
docker-compose.yml
docker compose build [OPTIONS] [SERVICE...]
Beispiel
Joomla
Normale Kommandos
docker network create gbsnet
docker run -d --name db --network gbsnet -v gbsdb:/var/lib/mysql /
-e MYSQL_DATABASE=joomla_db -e MYSQL_ROOT_PASSWORD=-gbs- mysql:8.3
docker run -d --name joomla --network gbsnet -v gbshtml:/var/www/html /
-p 80:80 -e JOOMLA_DB_HOST=db:3306 -e JOOMLA_DB_NAME=joomla_db /
-e JOOMLA_DB_USER=root -e JOOMLA_DB_PASSWORD=-gbs- joomla
Mit Docker Compose
services:
db:
container_name: db
networks:
- gbsnet
volumes:
- gbsdb:/var/lib/mysql
environment:
MYSQL_DATABASE: joomla_db
MYSQL_ROOT_PASSWORD: -gbs-
image: mysql:8.3
joomla:
container_name: joomla
networks:
- gbsnet
volumes:
- gbshtml:/var/www/html
ports:
- 80:80
environment:
JOOMLA_DB_HOST: db:3306
JOOMLA_DB_NAME: joomla_DB
JOOMLA_DB_USER: root
JOOMLA_DB_PASSWORD: -gbs-
image: joomla
volumes:
gbsdb:
gbshtml:
networks:
gbsnet:
Mit eigenem Netzwerk, benutzerdefinierten IP-Adressen und Healthcheck:
services:
db:
container_name: db
networks:
- gbsnet
volumes:
- gbsdb:/var/lib/mysql
environment:
MYSQL_DATABASE: joomla_db
MYSQL_ROOT_PASSWORD: -gbs-
image: mysql:8.3
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
joomla:
container_name: joomla
networks:
- gbsnet
volumes:
- gbshtml:/var/www/html
ports:
- 80:80
environment:
JOOMLA_DB_HOST: db:3306
JOOMLA_DB_NAME: joomla_DB
JOOMLA_DB_USER: root
JOOMLA_DB_PASSWORD: -gbs-
image: joomla
# healthcheck: joomla will wait and check all 10 seconds if db is ready and up
depends_on:
db:
condition: service_healthy
volumes:
gbsdb:
gbshtml:
networks:
gbsnet:
Wordpress
Ohne Secrets
services:
wordpress:
container_name: wordpress
image: wordpress
restart: on-failure
volumes:
- wordpress-html:/var/www/html
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: ${DB_NAME}
WORDPRESS_DB_USER: ${DB_USER}
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
depends_on:
- db
db:
container_name: db
image: mysql:9.3
volumes:
- wordpress-db:/var/lib/mysql
environment:
MYSQL_DATABASE: ${DB_NAME}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
restart: on-failure
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 2s
timeout: 5s
retries: 5
start_period: 2s
volumes:
wordpress-db:
wordpress-html:
Mit Secrets
services:
wordpress:
container_name: wordpress
image: wordpress
restart: on-failure
volumes:
- wordpress-html:/var/www/html
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: ${DB_NAME}
WORDPRESS_DB_USER: ${DB_USER}
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
depends_on:
db:
condition: service_healthy
secrets:
- db_password
db:
container_name: db
image: mysql:9.3
volumes:
- wordpress-db:/var/lib/mysql
environment:
MYSQL_DATABASE: ${DB_NAME}
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD_FILE: /run/secrets/db_password
restart: on-failure
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 2s
timeout: 5s
retries: 5
start_period: 2s
secrets:
- db_password
- db_root_password
volumes:
wordpress-db:
wordpress-html:
secrets:
db_password:
file: secret_db_password.txt
db_root_password:
file: secret_db_root_password.txt