Starting a frontend, API, and database with separate `docker container run` commands means repeating port, network, and storage options by hand. A `docker-compose.yml` file puts those choices in one actionable definition. It describes the application’s desired state; `docker compose up` asks Docker to create the containers, networks, and volumes needed to reach it. section 7.1
The file uses YAML, so indentation matters. Under `services`, name each application component and give it an image and any options it needs. A service can run more than one container from the same image. Other top-level entries, such as `networks`, define resources the services use. section 7.1
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
This small working definition names a web service, publishes host port 8020 to container port 80, and connects the service to an existing `nat` network. section 7.1
For a multi-container app, add only the settings each service needs:
- Use `image` to select the packaged component. A service that needs no published port can have just an image. section 7.2
- Use `ports` to publish a container port. `8010:80` fixes the host port at 8010; `80` publishes container port 80 on a randomly selected host port. section 7.2
- Use `depends_on` when one service should be running before another starts. Put communicating services on the appropriate network. section 7.2 section 7.1
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 the three image-gallery services: a log collector with no published port, an API with a random host port, and a frontend with a fixed port and startup dependencies. section 7.2
Run, inspect, and reset the app
From the directory containing the Compose file, run `docker compose up -d` to start in the background. Try `docker compose up -d --scale iotd=3`, then `docker compose logs --tail=1 iotd` to inspect the scaled API. `docker compose stop` and `docker compose start` stop and restart the app; `docker compose down` followed by `docker compose up -d` removes and recreates it from the file. Compose applies the definition when invoked, but does not continuously replace containers that fail or are manually removed. section 7.2 section 7.5
Keep a common service definition and add override files for development or test. An override can change ports, environment variables, and `env_file` values; a service can also mount a configuration file as a secret. Define any secret referenced by a service—an otherwise incomplete core file may not run alone. Select files with `docker compose -f ... -f ...` or configure defaults with `COMPOSE_FILE`. This lets the same tested image run with different environment settings, though secret paths may need a Windows-specific override. section 10.3 section 10.5
Treat the file as executable deployment documentation, not a high-availability platform. It applies a definition to one Docker machine; it does not continuously enforce desired state like Kubernetes. For practice, define a test app with a database bind mount, restart behavior, and a published web port, then bring it down and up to check whether its data remains. section 7.5 section 7.6



