Vultr DocsLatest Content

How To Use Docker Compose

Updated on 24 November, 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 setting up interconnected containers for local development. In CI/CD, it automates test environments by providing temporary isolation for testing.

This article explains how to use Docker Compose to create and manage containers. It covers the basics of the docker compose command, how to create a Docker Compose file, and how Docker Compose profiles run containers for different environments.

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 based 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
pull Download the latest images for services docker compose pull

Use Docker Compose Profiles

Profiles enable selective service execution 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 the command below.

    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
    

Update Service Images to the Latest Version

Docker Compose makes it easy to update services to newer container images. The exact update process depends on whether your services use the latest tag or a hard-coded version tag in the docker-compose.yml file.

  • If your service uses the latest tag in its image, such as image: traefik:latest:

    1. Pull the newest version.

      console
      $ docker compose pull
      

      Docker downloads the updated image. Only services with updated images are re-pulled.

    2. Recreate your services.

      console
      $ docker compose up -d
      
  • If your service uses a version-specific tag in its image, such as image: gitea/gitea:1.25.1:

    1. Edit the Docker Compose file to specify the new version.

    2. Pull the newly specified image.

      console
      $ docker compose pull
      
    3. Recreate and restart the updated containers.

      console
      $ docker compose up -d
      
Note
docker compose up -d stops the old containers, starts new ones with the updated image version, and preserves all data stored in volumes.

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