Home / Alt manpages / docker-compose(1)

  • docker-compose(1)
  • User command
  • linux

Run a Small Application Safely with docker-compose

You will define a small two-service application, start it as one Compose project, check what is running, and clean it up without accidentally deleting its data. Allow about 15 minutes if Docker is already installed and its daemon is available.

Before you start

This guide targets the installed Python-era command, docker-compose. The local command reports version 1.29.2. Docker now documents Compose v2 as the supported command-line generation, invoked as docker compose; the hyphenated command is retained here because it is the installed program and the subject of the local manpage. Options and output can differ between those generations.

You need Docker Engine running, permission to access its daemon, and a shell. Most commands below are ordinary user commands. Add sudo only if your local Docker setup requires it, and remember that granting Docker daemon access is effectively privileged access.

Check the version before spending time debugging a command copied from newer documentation:

$ docker-compose --version
docker-compose version 1.29.2, build unknown

Checkpoint 1: create the Compose file

Make a new directory and enter it. The directory name becomes the default project name, so choose a name that will not collide with another application on this Docker host.

$ mkdir compose-demo
$ cd compose-demo

Create docker-compose.yml with two services. The web service serves a small response on port 8080. The worker service prints a message and stays alive so that it is easy to inspect. The depends_on entry controls start order, not application readiness: a dependent service can still need its own health or retry logic.

version: "3.8"

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
  worker:
    image: alpine:3.19
    command: ["sh", "-c", "echo worker is running; sleep 3600"]
    depends_on:
      - web

Pinning image tags makes this example easier to repeat than using latest. It does not make an image immutable: tags can still be moved in a registry. For a controlled deployment, review and pin image digests separately.

Ask Compose to parse and render the merged configuration before starting containers. This command is available in the installed 1.29.2 program even though it is absent from the older local manpage:

$ docker-compose config

Expected output includes services:, followed by web: and worker:. A YAML indentation error or an unavailable field should be fixed at this checkpoint, before anything is started.

Checkpoint 2: start the project

Start both services in the foreground first. Compose creates or recreates containers, attaches their output, and normally stops them when you interrupt the command.

$ docker-compose up

On the first run, Docker may pull the two images. You should see creation or startup messages and then output from worker. In another terminal, verify the project without interrupting it:

$ cd compose-demo
$ docker-compose ps

Both services should appear with a running state. The host port is now occupied by the web container, so another application already listening on 8080 will cause startup to fail. Change the left side of "8080:80", for example to "18080:80", then run docker-compose up again.

Press Ctrl-C in the foreground terminal to stop the attached run. This stops the containers but does not remove their definitions or images. Restart existing containers later with:

$ docker-compose start
$ docker-compose ps

Checkpoint 3: run detached and inspect logs

For a background project, use detached mode. This command changes host state and leaves both containers running after your shell returns:

$ docker-compose up -d

Verify the result before using the application:

$ docker-compose ps
$ curl http://127.0.0.1:8080/

The second command should return the Nginx welcome response. If curl is not installed, use a browser or another HTTP client. To investigate startup or application output, show the project logs without colour codes:

$ docker-compose logs --no-color
$ docker-compose logs --no-color web

To find the host port from the Compose definition rather than assuming it, ask for the published port. The service port is 80 and the protocol defaults to TCP:

$ docker-compose port web 80

Expected output has the form 0.0.0.0:8080 or an equivalent host address and port. If you run multiple instances of a service, the manpage's --index option selects which container to inspect.

Run a one-off command without changing the service

run creates a temporary container using a service's configuration and replaces that service's command. It does not publish the service's configured ports unless you explicitly add --service-ports, which prevents accidental port collisions.

$ docker-compose run --rm worker sh -c 'printf "one-off check\n"'
one-off check

The --rm option removes that one-off container after the command exits. It is useful for checks and migrations, but do not use it as a substitute for an explicit backup or rollback plan. Use --no-deps when the command must not start linked services.

Stop, remove, and recover

When you are finished testing, stop the running containers without deleting them:

$ docker-compose stop
$ docker-compose ps

Start them again with docker-compose start. If you want to remove stopped service containers, use:

$ docker-compose rm

Compose asks for confirmation. Add -f only when that removal is deliberate. The local manpage documents -v with rm to remove volumes associated with the containers. Treat that option as destructive: do not use it until you have confirmed that the volumes contain no data you need. The example above has no named volume, so it has no application data to preserve.

To undo the demo completely, stop it and remove its containers. If you changed the file or image and want Compose to apply the change, plain up may recreate existing containers; use --no-recreate when reusing the existing containers is the safer choice, or --no-build when a missing image must not trigger a build.

$ docker-compose stop
$ docker-compose rm
$ docker-compose ps

An empty service listing confirms that the demo containers are gone. The downloaded images remain until you remove them with Docker's own image-management commands. Keeping them is usually the quickest recovery if you intend to repeat the test.

Common traps

  • Wrong project: Compose groups resources by project name. Run commands from the directory containing the intended file, or set -p PROJECT_NAME. The environment variable COMPOSE_PROJECT_NAME provides the same project-name override.
  • Wrong file: the default is docker-compose.yml. Use -f PATH for a different file. COMPOSE_FILE can provide the file through the environment, but an explicit command-line choice is easier to see during recovery.
  • Service is running but not ready: start order does not prove readiness. Make the application retry its dependency or add an appropriate health check supported by the Compose version you are using.
  • Port already allocated: change the host side of the mapping, then recreate the affected service. Do not stop an unrelated production service merely to make a demo start.
  • Daemon connection failure: inspect DOCKER_HOST. The manpage's default is unix:///var/run/docker.sock; DOCKER_TLS_VERIFY and DOCKER_CERT_PATH alter TLS connections. Avoid copying certificates or using an insecure registry option into a script without understanding the security impact.

Done means

  • docker-compose --version identified the installed command generation.
  • docker-compose config accepted the YAML.
  • docker-compose ps showed the expected services at the running checkpoint.
  • curl http://127.0.0.1:8080/ or an equivalent check reached the web service.
  • You stopped or removed the project deliberately, and did not use volume removal without checking for data.