Docker Compose
Compose runs a set of related containers as one project. Use the current Compose plugin through docker compose. The old standalone Compose v1 command is retired and should not be used for new work.
Check the plugin.
1docker compose version
2docker compose ls
Compose files
The preferred file name is compose.yaml. Current Compose files follow the Compose Specification; do not add a top-level version key to new files.
The sample below defines three services: a MySQL database, a Flask API, and an nginx-hosted frontend.
1name: student-stack
2services:
3 db:
4 image: db-app:local
5 container_name: db
6 ports:
7 - "3306:3306"
8 volumes:
9 - type: bind
10 source: ./mysql/docker-entrypoint-initdb.d
11 target: /docker-entrypoint-initdb.d
12 consistency: consistent
13 environment:
14 MYSQL_ROOT_PASSWORD: "oneoffcoder"
15 healthcheck:
16 test: mysqladmin ping -h localhost -p$$MYSQL_ROOT_PASSWORD && test '0' -eq $$(ps aux | awk '{print $$11}' | grep -c -e '^mysql$$')
17 flask:
18 image: rest-app:local
19 container_name: rest
20 ports:
21 - "5000:5000"
22 healthcheck:
23 test: ["CMD", "curl", "-f", "http://localhost:5000"]
24 interval: 60s
25 timeout: 10s
26 retries: 3
27 start_period: 40s
28 depends_on:
29 - db
30 ng:
31 image: ui-app:local
32 container_name: ui
33 ports:
34 - "80:80"
35 healthcheck:
36 test: ["CMD", "curl", "-f", "http://localhost:80"]
37 interval: 60s
38 timeout: 10s
39 retries: 3
40 start_period: 40s
41 depends_on:
42 - flask
43 - db
The YAML file is mostly self-explanatory.
We create three services:
db,flaskandng.Each service has a specified container image:
db-app:local,rest-app:localandui-app:local.The database mounts initialization scripts and receives its root password through environment configuration.
Health checks describe how Compose can tell whether a service is healthy.
For services that need a dependency to be healthy before startup, use long-form depends_on.
1services:
2 api:
3 image: rest-app:local
4 depends_on:
5 db:
6 condition: service_healthy
Environment files
Keep local defaults in a .env file or pass an explicit environment file. Do not commit real secrets.
1docker compose --env-file .env.local config
2docker compose --env-file .env.local up --build
Profiles
Profiles let optional services stay out of the default development loop.
1services:
2 worker:
3 image: worker-app:local
4 profiles:
5 - jobs
Run the optional service only when the profile is requested.
1docker compose --profile jobs up
Secrets and configs
Compose supports secrets and configs. For local development, a secret can be mounted from a file.
1services:
2 api:
3 image: rest-app:local
4 secrets:
5 - db_password
6
7secrets:
8 db_password:
9 file: ./secrets/db_password.txt
The application reads the mounted file rather than receiving the value through an environment variable.
Networks and volumes
Compose creates a project network by default. Add named networks when you need explicit boundaries, and use named volumes for persistent state.
1services:
2 db:
3 image: db-app:local
4 volumes:
5 - db_data:/var/lib/mysql
6 networks:
7 - backend
8
9volumes:
10 db_data:
11
12networks:
13 backend:
Daily commands
The commands below cover the normal loop.
1docker compose -f compose.yaml config
2docker compose -f compose.yaml up --build
3docker compose -f compose.yaml ps
4docker compose -f compose.yaml logs -f
5docker compose -f compose.yaml exec flask sh
6docker compose -f compose.yaml down --volumes
Use Compose for local development, integration tests, and simple single-host deployments. For managed cloud deployments, translate the same image and configuration ideas into the target platform’s native model, such as ECS task definitions or Kubernetes manifests.
Dockerfiles
MySQL
1FROM mysql:latest
Flask
1FROM python:3
2
3WORKDIR /rest-app
4COPY ./rest-app .
5RUN pip install --no-cache-dir requests flask flask-cors mysql-connector-python SQLAlchemy
6
7CMD [ "python", "./app.py" ]
Angular
1FROM node:lts AS node_builder
2WORKDIR /tmp/ui-app
3COPY ./ui-app .
4RUN npm install -g @angular/cli@latest
5RUN npm install
6RUN ng build
7
8FROM nginx:alpine
9COPY --from=node_builder /tmp/ui-app/dist/ui-app /usr/share/nginx/html
10EXPOSE 80