First Steps with Docker Compose

Docker Compose is the tool that allows you to start up a network of several Docker containers together for testing. It turns out that many of the latest books (even within the past couple of years) are either out of date or missing details. Sure, the examples will usually work, but there are now better ways to do things. Here are a few tips to answer questions likely to come up if you're just getting started.

Do I use docker-compose or docker stack deploy?

Neither, if you're just testing locally. You use docker compose.

docker stack deploy is something to use with Docker Swarm for orchestration, which is like Kubernetes. Yes, it will work with your Docker Compose file, but for local testing you probably don't want to use Docker Swarm. See What's the difference between a stack file and a Compose file?.

In fact Docker Compose is being integrated into the docker command, so the latest way to do things is:

docker compose …

So will Docker Compose functionality be integrated into Docker Swarm?

That's unclear at the moment, and they don't always behave the same. As someone said in that forum:

It’s really a mess that probably won’t get cleaned up any time soon.

Is the default Docker Compose file docker-compose.yaml or docker-compose.yml?

The documentation as of v20.10.22 says the default is docker-compose.yml. But in my testing, Docker Compose finds docker-compose.yaml just as well. So I choose to use docker-compose.yaml because yaml is the offically preferred extension for YAML files.

What version indication do I need to put at the top of my Docker Compose file?

You don't need a version indicator anymore. Just start with the body of your file like this:

services:
  my-service:
…

Can I use variables in my Docker Compose file?

Yes, interpolation is supported. But be careful: the syntax for default values uses a subset of shell parameter expansion. (See this cheat sheet.) It is not just a single colon followed by the default value. You musn't forget the preceding dash, such as -latest in the example below.

The following example allows the developer to pass MY_SERVICE_VER to Docker Compose via an environment variable; if not provided, the latest tag is used.

services:
  my-service:
    image: my-service-image:${MY_SERVICE_VER:-latest}

Do I really need to quote my port mappings to prevent YAML from interpreting the number as base 60?

The book Using Docker (O'Reilly, 2015) says on page 82:

Ports can be specified without quotes, but this is best avoided as it can cause confusion when YAML parses statements such as 56:56 as a base 60 number.

This is outdated advice. Apparently YAML 1.1 had a “feature” that would parse two sets of digits, separated by colons, as a number in base 60. This has been removed in YAML 1.2. The following works fine in Docker Compose:

    ports: [8080:8080]

Or if you prefer multiple lines:

    ports:
      - 8080:8080

What's a basic sample Docker Compose file to get me started?

docker-compose.yaml

services:
  my-service:
    image: my-service-image:${MY_SERVICE_VER:-latest}
    ports: [8080:8080]

How do I start it?

You can use the following command to start Docker Compose, using the default definition file.

docker compose up

You can specify a file other than the default using --file or -f.

If you use --detach or -d, it will run in the background and you can go on to do other things in the terminal.

How do I stop it?

If you used --detach, or if you go to another terminal window, you can issue:

docker compose down

Otherwise in the same terminal window you can enter Ctrl+C and it will stop things, no harm done. However it will only stop the containers; it will not remove the containers or the network it created. See Difference between docker-compose down and Ctrl + C.

What if I use docker compose up again after stopping using Ctrl+C?

No harm will be done. It will use the same containers instead of creating new ones. You can verify this using:

docker image list -all

If you've stopped Docker Compose using Ctrl+C and want to make sure things get cleaned up, go ahead and use:

docker compose down

This will remove the containers and the network that were created.