- English
- English
Appearance
Appearance
In daily work, you rarely type many docker run commands to start an entire application. Docker Compose lets you describe several containers in one file and start them with one command.
This configuration file is usually named compose.yaml. Docker Compose also supports the older name docker-compose.yml, but this course uses compose.yaml.
The command is docker compose, with a space. Docker Compose still uses Docker CLI and Docker Engine. Docker CLI sends the Compose configuration to Docker Engine, and the Engine creates and runs the required containers.
We will create an example project with two services:
web, an Nginx web server.db, a PostgreSQL database.The goal is to show how Compose runs multiple containers, creates a network between them, and stores database data in a named volume.
Create a project folder so all example files stay in one place:
mkdir compose-demo
cd compose-demo
mkdir htmlCreate html/index.html. Nginx will display this file:
<h1>Hello from Docker Compose</h1>Next, create compose.yaml with this content:
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
volumes:
pgdata:Create a .env file in the same folder as compose.yaml. This file stores the environment variable value for local development:
POSTGRES_PASSWORD=secretDo not commit a .env file containing secrets to Git. See lesson 8 for a fuller explanation of environment variables.
compose.yaml services: the list of services to run. Each service, such as web and db, creates one container.image: the image used to create the container, just like the image in docker run.ports: maps a host port to a container port, like the -p option. Here, laptop port 8080 maps to port 80 in the Nginx container.volumes: mounts storage into a container. ./html is a bind mount from the project folder, while pgdata is a named volume managed by Docker. See Docker Volume for details.environment: provides environment variables to the container, like the -e option in docker run.restart: unless-stopped: asks Docker to restart the container when Docker Engine restarts, unless the user stopped that container intentionally.In ./html:/usr/share/nginx/html:ro, ./html is a folder on the laptop, while /usr/share/nginx/html is a path inside the container. The :ro suffix means that the container can read the folder but cannot change it.
When you start the project, Compose creates a default network for it. Containers on this network can reach each other using service names as hostnames.
Therefore, the web service can connect to PostgreSQL using hostname db and port 5432, the PostgreSQL port inside the Docker network. This is different from port 8080, which you use to access Nginx from the laptop.
Example connection string from an app:
postgres://postgres:${POSTGRES_PASSWORD}@db:5432/appNotice that it uses @db:5432. Use db, not localhost. From inside the web container, localhost points to the web container itself, not the database container.
See Docker Network for more about communication between containers.
up Make sure the terminal is in the folder containing compose.yaml. Start all services in the background so the terminal remains available:
docker compose up -dup creates the required network, volume, and containers, then starts the services. -d means detached, so logs do not keep streaming in the terminal.
Open http://localhost:8080 in a browser. The page proves that the web container is running and the host port maps correctly to the Nginx port.
To check the startup process for all services, follow their logs:
docker compose logs -f-f means follow. The terminal keeps showing new log entries until you stop it with Ctrl+C.
To check only the database logs, provide its service name:
docker compose logs -f dbThis command only shows logs for the db service, not the web service.
down To stop and remove the containers and network created by Compose:
docker compose downThis command does not remove the pgdata named volume, so the database data remains available when you start the services again.
To remove the containers, network, and named volume together:
docker compose down -vThe -v option removes named volumes and their data. Use this only when you want to reset local data.
depends_on You can use depends_on when one service depends on another. This example asks Compose to start db before web:
services:
web:
image: nginx:1.27-alpine
depends_on:
- db
db:
image: postgres:16depends_on only controls the container start order. It does not mean PostgreSQL is ready to accept connections as soon as the db container starts.
An app that connects too quickly can still fail while PostgreSQL is starting. In daily work, apps usually retry when the database is not available yet.
In the earlier example, the web and db services use images built by someone else through the image field. Compose pulls those images if they are not available on the laptop. It does not build them from our source code.
For an app whose image is built from your own Dockerfile, use the build field. This example asks Compose to use the Dockerfile in the current project folder:
services:
api:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/app
depends_on:
- dbbuild: . asks Compose to use the Dockerfile in the current folder. Compose uses the resulting image to run the api service, so you do not need to run docker build manually every time you start the project.
After changing the Dockerfile or source code copied into the image, use --build to rebuild the image before starting the services:
docker compose up -d --build--build only affects services that use the build field. Services that only use image, such as web and db above, are not rebuilt from source code.
Without --build, Compose may use the previous image. Changes to the Dockerfile or source code may therefore not appear in the new container.
If you can run an app and database with Compose, inspect logs, and connect the app to the database by service name, you understand the Docker and Docker Compose basics.
See the Docker Essentials Cheatsheet for a summary of the most useful Docker Essentials commands.