How To Use Docker Compose

Updated on 30 July, 2025
Learn how to manage multi-container applications with Docker Compose using compose.yaml, service profiles, and essential CLI commands.
 How To Use Docker Compose  header image

Docker Compose is a multi-container orchestration tool for a single host. It uses the Docker engine to manage and orchestrate the Docker containers. It simplifies your local development environment by allowing you to create complex and interconnected containers declaratively. Docker Compose also automates the test suite in the CI/CD process by providing a temporary and isolated environment for testing.

This article explains how to use Docker Compose to create and manage containers. It covers the basics of the docker compose command and how to create the compose.yaml manifest. It also explores the Docker Compose profile for running containers depending on your environment.

The Short Answer

Below are some basic Docker Compose commands that operate on a compose.yaml or docker-compose.yaml file.

# Create/build and start all services in the background.
$ docker compose up -d

# Stop and remove all service containers, networks, and volumes.
$ docker compose down

# Stop all services.
$ docker compose stop

# Start and run stopped services.
$ docker compose start

# View the status of running services.
$ docker compose ps

# Check the logs of all services.
$ docker compose logs

Create a Docker Compose File

This section covers creating a sample Docker Compose file compose.yaml for a sample flask application.

  1. Download the sample application.

    console
    $ git clone https://github.com/ndlrfz/flask-redis-postgresql
    
  2. Navigate to the flask-redis-postgresql project directory.

    console
    $ cd flask-redis-postgresql
    
  3. The directory contains a file compose.yaml with the following contents.

    console
    $ cat compose.yml
    

    You'll see the following Docker Compose manifest:

    yaml
    name: myproject
    
    services:
      redis:
        image: "redis:alpine"
        restart: always
        ports:
          - 6379:6379
        volumes:
          - redis:/data
    
      postgresql:
        image: "postgres:16-alpine"
        ports:
          - "5432:5432"
        volumes:
          - pgdata:/var/lib/postgresql/data
        environment:
          POSTGRES_USER: ${DATABASE_USER}
          POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
          POSTGRES_DB: ${DATABASE_NAME}
    
      flask:
        build: .
        restart: always
        env_file:
          - ".env"
        depends_on:
          - redis
          - postgresql
        ports:
          - "8000:5000"
        volumes:
          - ./:/code
    
    volumes:
      redis:
        driver: "local"
      pgdata:
        driver: "local"
    

    In this file,

    • name: Sets the project name to myproject.
    • services: Defines the individual containers that make up your application.
    • Define the redis service with these details:
      • image: Creates the service from the redis:alpine image.
      • restart: always: Sets a policy to always restart this container if it stops.
      • ports: Maps port 6379 on the host to port 6379 in the container.
      • volumes: Mounts the named volume redis to the /data directory inside the container for persistent data.
    • Define the postgresql service with the following:
      • image: Creates the service from the postgres:16-alpine image.
      • ports: Maps port 5432 on the host to port 5432 in the container.
      • volumes: Mounts the named volume pgdata to the /var/lib/postgresql/data directory for persistent data.
      • environment: Sets environment variables inside the container. The values for ${DATABASE_USER}, ${DATABASE_PASSWORD}, and ${DATABASE_NAME} are substituted from your shell's environment (often loaded from an .env file).
    • Define the application service flask with the following:
      • build: .: Builds a Docker image in the current directory from the Dockerfile.
      • restart: always: Sets a policy to always restart this container if it stops.
      • env_file: Loads environment variables for the service directly from a .env file.
      • depends_on: Controls the startup order. The flask service will start only after the redis and postgresql services have been started.
      • ports: Maps port 8000 on the host to port 5000 inside the container.
      • volumes: Mounts the current project directory on the host to the /code directory inside the container.
    • volumes: Defines two named volumes, redis and pgdata, using the local driver. These are managed by Docker and stored on the host machine.
  4. Create a file .env.

    console
    $ nano .env
    

    Add the following environment variables for PostgreSQL credentials. You can replace the following details with your credentials.

    ini
    DATABASE_USER=app_user
    DATABASE_PASSWORD=app_password
    DATABASE_NAME=appdb
    DATABASE_HOST=postgresql
    DATABASE_PORT=5432
    

    Save and exit the file.

  5. Build and start your services.

    console
    $ docker compose up -d
    

    The option -d allows you to run containers in the background.

  6. Run the command below to check the running containers or services.

    console
    $ docker compose ps
    

    Output:

    NAME                     IMAGE                COMMAND                  SERVICE      CREATED              STATUS              PORTS
    myproject_flask-1        myproject_flask      "flask run --debug"      flask        About a minute ago   Up About a minute   0.0.0.0:8000->5000/tcp, [::]:8000->5000/tcp
    myproject_postgresql-1   postgres:16-alpine   "docker-entrypoint.s…"   postgresql   About a minute ago   Up About a minute   0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp
    myproject_redis-1        redis:alpine         "docker-entrypoint.s…"   redis        About a minute ago   Up 32 seconds       0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp

    Output explanation:

    • flask service is running on port 8000 on the host machine, which is based on the Docker image myproject_flask.
    • postgresql service running on port 5432 based on the Docker image postgres:16-alpine.
    • redis service is running on port 6379 based on the Docker image redis:alpine.
  7. Check the list of images that are used by your services.

    console
    $ docker compose images
    

    Output:

    CONTAINER                REPOSITORY          TAG                 IMAGE ID            SIZE
    myproject_flask-1        myproject_flask     latest              1c3d151b6276        254MB
    myproject_postgresql-1   postgres            16-alpine           b56133b65cd3        275MB
    myproject_redis-1        redis               alpine              d470ca4bc10c        60.5MB
  8. Open a web browser and visit http://<SERVER-IP>:8000/ to verify that your application is running.

    Flask application running

Manage Docker Compose Stack

The following table describes the common docker compose commands for managing your application stack.

Command Description Example
build Build or rebuild containers docker compose build
up Create and start containers docker compose up -d
down Stop and remove containers docker compose down
start Start existing containers docker compose start app
stop Stop containers docker compose stop app
kill Force stop containers docker compose kill app
ps Check running containers docker compose ps
logs Check logs for containers docker compose logs app
exec Execute command in the container docker compose exec app bash
images Listing images used by containers docker compose images
rm Remove stopped containers docker compose rm

Use Docker Compose Profiles

Profiles allow selective applications or services to run based on the environment or use cases, such as development and production.

  1. Edit the compose.yml file.

    console
    $ nano compose.yml
    
  2. Add the following configuration under the flask service.

    yaml
    adminer:
        image: adminer
        restart: always
        depends_on: [postgresql]
        profiles: [dev]
        ports:
          - 8080:8080
      redis-insight:
          image: redis/redisinsight:latest
          restart: always
          profiles: [dev]
          depends_on: [redis]
          ports:
            - "8001:8001"
    

    Save and close the file.

    In this configuration:

    • adminer: Defines a service named adminer that uses the adminer Docker image.
      • restart: always: Sets a policy to always restart the container if it stops.
      • depends_on: Ensures the adminer service starts only after the postgresql service starts.
      • profiles: Assigns the dev profile to the service.
      • ports: Maps port 8080 on the host to port 8080 in the container.
    • redis-insight: Defines a service named redis-insight that uses the redis/redisinsight:latest Docker image.
      • restart: always: Sets a policy to always restart the container if it stops.
      • depends_on: Ensures the redis-insight service starts only after the redis service starts.
      • profiles: Assigns the dev profile to the service.
      • ports: Maps port 8001 on the host to port 8001 in the container.
  3. Start the adminer service.

    console
    $ docker compose --profile dev up -d
    

    Use the --profile dev option to activate and start services assigned to the dev profile. This tells Docker Compose to include the adminer service, which it ignores by default.

  4. Check the running container with the following command.

    console
    $ docker compose ps
    

    You'll see the adminer service is running.

    NAME                        IMAGE                       COMMAND                  SERVICE         CREATED         STATUS         PORTS
    myproject-adminer-1         adminer                     "entrypoint.sh docke…"   adminer         2 seconds ago   Up 1 second    0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp
    myproject-flask-1           myproject-flask             "flask run --debug"      flask           2 seconds ago   Up 1 second    0.0.0.0:8000->5000/tcp, [::]:8000->5000/tcp
    myproject-postgresql-1      postgres:16-alpine          "docker-entrypoint.s…"   postgresql      3 seconds ago   Up 2 seconds   0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp
    myproject-redis-1           redis:alpine                "docker-entrypoint.s…"   redis           3 seconds ago   Up 2 seconds   0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp
    myproject-redis-insight-1   redis/redisinsight:latest   "./docker-entry.sh n…"   redis-insight   3 seconds ago   Up 1 second    5540/tcp, 0.0.0.0:8001->8001/tcp, [::]:8001->8001/tcp
  5. To stop a service, for example adminer, use

    console
    $ docker compose stop adminer
    
  6. Remove the stopped adminer service.

    console
    $ docker compose rm adminer
    
  7. Destroy all services (including the dev profile).

    console
    $ docker compose --profile dev down
    

Conclusion

In this article, you've explored how to use Docker Compose to manage container stacks. You have learned how to start, stop, restart, and destroy containers using the docker compose command, how to create the compose.yaml file for your application stack, and the basic usage of Docker Compose Profiles for selectively running containers depending on your environment. For more information, check the Docker Compose documentation.

Tags:

Comments

No comments yet.