Starting each container separately means remembering its network, ports, and name. A Compose service puts those choices under one named entry in a YAML file. The top-level services section lists application components; Compose uses those definitions to create containers. A service can also run several containers from the same image. section 7.1 section 7.2
Listing 7.1 A Docker Compose file to run the to-do app
services:
todo-web:
image: diamol/ch06-todo-list:2e
ports:
- "8020:80"
networks:
- app-net
networks:
app-net:
name: nat
external: true
Start with one service: todo-web specifies an image, publishes host port 8020 to container port 80, and joins app-net. YAML indentation keeps each property under its service. The network is separately defined as an existing Docker network named nat. section 7.1
Read a service definition as a set of practical container choices:
- image selects what runs; ports publishes a container port on the host; networks connects the container to a Docker network. These properties closely match docker container run options. section 7.1
- The service name gives other containers a DNS name to use on the Docker network. section 7.1
- depends_on tells Compose to start listed services before a dependent service. section 7.2
Listing 7.2 Compose services for the multi-container app
accesslog:
image: diamol/ch04-access-log:2e
iotd:
image: diamol/ch04-image-of-the-day:2e
ports:
- "80"
image-gallery:
image: diamol/ch04-image-gallery:2e
ports:
- "8010:80"
depends_on:
- accesslog
- iotd
Compare three components: accesslog needs only an image; iotd publishes container port 80 to a random host port; image-gallery uses a fixed host port and depends on the other two services. section 7.2
Services can also carry application configuration. In the to-do app, todo-db runs PostgreSQL while todo-web sets Database:Provider through environment and receives a database connection secret as a file. For Compose on a single machine, that secret is loaded from a local file. section 7.4
Listing 7.3 Compose services for an app with a Postgres database
services:
todo-db:
image: diamol/postgres:2e-12
ports:
- "5433:5432"
networks:
- app-net
todo-web:
image: diamol/ch06-todo-list:2e
ports:
- "8020:80"
environment:
- Database:Provider=Postgres
depends_on:
- todo-db
networks:
- app-net
secrets:
- source: postgres-connection
target: /app/config/secrets.json
Follow the two-service configuration: todo-web depends on todo-db, shares app-net with it, and maps the postgres-connection secret to /app/config/secrets.json. The secret’s local source file is declared separately. section 7.4
Run and inspect the services
From ./ch07/exercises/image-of-the-day, run docker compose up --detach to start the application in the background. Try docker compose up -d --scale iotd=3, then docker compose logs --tail=1 iotd to inspect that service. docker compose stop and docker compose start retain the application; docker compose down followed by docker compose up -d recreates it from the file. section 7.2

