By now a single docker run for a real service is a mouthful - a name,
a port, a few environment variables, a volume, a network, a restart
policy:
docker run -d --name db \
--network appnet \
-e POSTGRES_PASSWORD=s3cret \
-e POSTGRES_DB=orders \
-v pgdata:/var/lib/postgresql/data \
--restart unless-stopped \
postgres:16-alpine
That is one service. A real app has several - a web server, a database, a cache - each with its own long command, plus a network to create first. Typing all that by hand, in the right order, every time, is error-prone and impossible to hand to a teammate cleanly.
Two pain points come from managing multi-container apps by hand:
Docker Compose lets you describe your whole application in one file - every service, its image, ports, environment, volumes, and networks - and then start all of it with a single command. The file is the source of truth. Commit it to the repo and anyone can bring the app up identically.
docker compose up
That one command reads the file and starts every service, creating the networks and volumes they need along the way. No long flags, no remembering the order.
Compose ships with Docker as the docker compose subcommand - nothing
extra to install here. The rest of this topic covers the file format
and the handful of commands you use to run it.