--- gitea: none include_toc: true --- # Docker compose - __Purpose:__ Defines and manages multi-container Docker applications. - __Usage:__ Orchestrates multiple services (containers), networks, and volumes for an application. - __Key Features:__ - Describes how to run one or more containers together. - Can manage container networking and persistent storage. - Useful for applications with multiple services (e.g., a web app + database). - __Output:__ A running application consisting of multiple containers. `docker-compose.yml` is the file which includes all nescessary information. It can include multiple services like web (built from a Dockerfile) and db (pulled from Docker Hub). ## docker-compose vs. docker compose - If you're using a modern Docker installation (20.10+), use `docker compose`. - If you're working on a system with an older Docker version or have compatibility concerns, use `docker-compose`. | Feature | docker compose | docker-compose | | --- | --- | --- | | Integration | Integrated into Docker CLI | Standalone binary | | Compose Specification | Supports Compose V2 | Supports older Compose V1 | | Performance | Faster and more efficient | Slower compared to Compose V2 | | Availability | Docker 20.10+ and Docker Desktop | Any Docker version, standalone | | Future-proof | Actively developed and maintained | Legacy, less maintained | check your docker compose version (examples): ``` docker compose version Docker Compose version v2.32.1 # is installed together with docker v27.4.1 docker-compose --version docker-compose version 1.25.0, build unknown # separate installation for old version. ``` ## docker-compose.yaml version Use `version: "3.9"` which is the latest version. Or, with Docker Compose v2 (the newer, built-in CLI plugin), you no longer need a version: line. If you remove it, Compose will simply default to the current spec. ## Image location ### Registry In docker compose, use `image` to use an existing image from the registry. ``` services: redis: init: true image: redis:latest ``` ### Local Image If the image needs to be built, use `build`. ``` services: my-local-app: init: true build: . ``` `build: .` tells Docker Compose to look for a `Dockerfile` in the same directory as the `docker-compose.yml`. If the Dockerfile is in a subdirectory, specify the context and Dockerfile path: ``` services: my-local-app: init: true build: context: ./my-app dockerfile: Dockerfile.dev ``` - `context:` Specifies the directory containing the application code. - `dockerfile:` Specifies the name of the Dockerfile if it’s not the default Dockerfile. You can mix local builds and images from a registry in the same docker-compose.yml file: ``` services: myapp: init: true build: ./my-app ports: - 8080:8080 redis: init: true image: redis:latest webapp: init: true build: . image: registry.cs.zi.uzh.ch/zi-adb-dba/export-digicert-report:latest ``` ## Docker Volumes Bind mounts: ``` version: '3.9' services: caddy: image: caddy:2.6.2 volumes: - /opt/roger/ssl/certifcate.pem:/cert.pem:ro # OR: Bind mounts of remote share which are defined through docker volumes version: '3.9' services: fedora: init: true image: docker.cloudsmith.io/docuteam/docker/fcrepo:6.2.0 volumes: - fedora_data:/fcrepo_home volumes: fedora_data: driver_opts: type: cifs device: //remote-hostname.com/path/to/share/fedora o: addr=remote-hostname.com,username=user,password=mysuperpassword,nodev,noexec,nosuid,vers=2.1,uid=1000,gid=1000 ``` Docker volumes: ``` version: '3.9' services: caddy: init: true image: caddy:2.6.2 volumes: - caddy_data:/data volumes: caddy_data ``` ### Read-Only Add `:ro` at the end of the line. ``` volumes: - /opt/roger/ssl/certifcate.pem:/cert.pem:ro ``` ## Dependencies If there is a special order of starting the containers, you can use `depends_on`, like this: ``` services: myapp: init: true build: ./my-app ports: - 8080:8080 redis: init: true image: redis:latest depends_on: - myapp ``` You can also add `condition`s, like `service_started`, `service_healthy` and `service_completed_successfully`: ``` services: myapp: init: true build: ./my-app ports: - 8080:8080 redis: init: true image: redis:latest depends_on: myapp: condition: service_started ``` In the following example, Compose will first start the database service, execute the pg_isready command specified in the healthcheck.test property, start the migration service if the value returned by the test command is 0, and finally start the api service if the exit status of the migration service's container is also 0. ``` services: api: init: true build: . depends_on: database: condition: service_healthy migration: condition: service_completed_successfully database: init: true image: postgres healthcheck: test: ["CMD-SHELL", "pg_isready"] migration: init: true image: migration-tool ``` ## Variables ### Variables for docker-compose.yaml Use `${VARIABLE_NAME}`, like this: ``` services: ui: init: true image: nginx:${NGINX_VERSION}-alpine ``` You can pass the variable when starting docker compose like this: ``` NINGX_VERSION=1.21.5 docker compose up -d ``` You can also use an environment file. If no variable is set on calling `docker compose up`, then it will use the value in the `.env` file. ``` touch .env # then add the variables: NINGX_VERSION=1.21.4 ``` If the file has a different name or is located in a different path, you can specify the location when starting docker-compose. ``` docker compose --env-file /path/to/environmentfile up -d ``` ### Variables for containers If a variable is already set in the shell, like `PORT` in this example, it will be automatically passed to docker compose, like this: ``` services: ui: init: true image: nginx:1.21.5-alpine environment: - PORT ``` To specify the variable in docker compose: ``` services: ui: init: true image: nginx:1.21.5-alpine environment: - PORT=81 ``` You can also specify a file: ``` services: ui: init: true image: nginx:1.21.5-alpine environment: - PORT=81 env_file: - ./path/to/envfile ``` ## Profiles Start only containers within a certain profile. Note that services WITHOUT a profile will always start! ``` services: myapp: init: true build: ./my-app ports: - 8080:8080 profiles: - blabla ui: init: true image: nginx:1.21.5-alpine profiles: - profilename ``` start like this, and it will start only the "ui" service. ``` docker compose --profile profilename up -d ``` ## Networks All containers in a docker compose setup can communicate with eachother. The services, like `myapp` or `ui` can be used as hostnames. This will make linking the containers easier. If the network must be specialized, e.g. not all containers have connection to other containers, you need to build your own networks. ``` services: myapp: init: true build: ./my-app networks: - test ui: init: true image: nginx:1.21.5-alpine profiles: - profilename networks: - test networks: test: driver: bridge attachable: true # default; set to false, so that other containers can not be added to the network in the future. ``` ## Restart policy ``` ui: init: true image: nginx:1.21.5-alpine restart: always # or other settings... ``` ## Commands ### Config The following command shows you the docker-compose.yaml as it is interpreted by docker. ``` docker compose config ``` ### Start `-d` für das Ausführen im Hintergrund. #### start Startet nur bereits existierende, gestoppte Container neu. Baut NICHT neu, erstellt KEINE neuen Container. Wird ein Container zum ersten Mal gestartet, muss up verwendet werden. ``` docker-compose start -d ``` #### up Verwendet, wenn möglich, vorhandene Images. Falls lokal schon ein Image mit dem passenden Namen und Tag existiert, wird NICHT neu gebaut. Nur wenn das Image nicht existiert, wird gebaut. ``` docker compose up -d ``` #### up mit build Baut immer neu, auch wenn ein Image schon existiert (empfohlen nach jedem Code- oder Dockerfile-Update). ``` docker compose up --build -d ``` ### Stop - The `docker compose stop` command will stop your containers, but it won’t remove them. - The `docker compose kill` command will stop your containers faster, but it won’t remove them. - The `docker compose down` command will stop your containers, but it also removes the stopped containers as well as any networks that were created. - You can take down 1 step further and add the `-v` flag to remove all volumes too. This is great for doing a full blown reset on your environment by running `docker compose down -v`. ### Events ``` docker compose events ```