Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

1. Overview

Docker Compose helps start and run services defined in a docker-compose.yml file, automatically creating the necessary containers around them. However, once the containers are up and running, Docker doesn’t directly support a straightforward way to locate the YAML file used to start them. Now, we may come across a situation where we need to manage or restart the services but can’t recall where the configuration file is located.

In this tutorial, we’ll explore how to find the location of the configuration file docker-compose.yml file using a running container associated with it.

2. Understanding the Problem

To begin, let’s note that Docker and Docker Compose work hand-in-hand. In particular, Docker Compose translates the instructions in the docker-compose.yml file into individual Docker commands. However, no Docker command exists that can help us display the actual file path of the docker-compose.yml file used to launch a running container. As a result, it becomes difficult to trace a running container to its configuration file.

Although Docker doesn’t store the path to the Compose file, it stores some metadata we can use, in this case, labels. Specifically, Docker Compose assigns labels to each container it creates. These labels contain information such as the project name which we use to identify and locate docker-compose.yml.

So, let’s work with a sample structure:

$ tree
.
├── first_compose_project
│   └── docker-compose.yml
└── second_compose_project
    └── docker-compose.yml

2 directories, 2 files

Above, we utilize the Linux command tree to display part of the filesystem. To clarify, we create this directory structure in the parent directory, docker-management.

Now, let’s proceed to locate the docker-compose.yml file.

3. Using Labels to Locate docker-compose.yml

To locate the potential docker-compose.yml file for a given container, we can follow several steps.

3.1. Enumerate Labels

When talking about utilizing metadata to map a running container back to its docker-compose.yml file, we most often check for labels in the specified container via the inspect subcommand:

$ docker inspect container_name

Above, we’re interested in the label com.docker.compose label.project present in the output:

"Labels": {
    "com.docker.compose.project": "project_name",
}

Let’s now discuss locating the docker-compose.yml file.

3.2. Locate the Compose File

First, let’s list the running containers:

$ docker ps --filter "label=com.docker.compose.project"
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS                    NAMES
6981dadd4d23   postgres:13       "docker-entrypoint.s…"   39 minutes ago   Up 39 minutes   5432/tcp                 second_compose_project_db_1
ddb325f5d405   python:3.9-slim   "python -m http.serv…"   39 minutes ago   Up 39 minutes   0.0.0.0:8000->8000/tcp   second_compose_project_app_1
682358d4a278   nginx:latest      "/docker-entrypoint.…"   39 minutes ago   Up 39 minutes   0.0.0.0:8080->80/tcp     first_compose_project_web_1
ef3a66d20fd1   redis:latest      "docker-entrypoint.s…"   39 minutes ago   Up 39 minutes   6379/tcp                 first_compose_project_redis_1

The Docker Compose containers that are currently running are listed via the ps subcommand. To explain, we use the com.docker.compose.project label as a filter since it’s usually applied to any container created by Docker Compose. As a result, it enables us to concentrate on running containers associated with only Compose projects.

Additionally, we can modify the command to get only the container names:

$ docker ps --filter "label=com.docker.compose.project" --format "{{.Names}}"
second_compose_project_db_1
second_compose_project_app_1
first_compose_project_web_1
first_compose_project_redis_1

Next, let’s use the com.docker.compose.project label to extract the project names for the listed container names:

$ docker inspect --format '{{ index .Config.Labels "com.docker.compose.project" }}' $container_name

Here, each container has a project name that matches the directory containing docker-compose.yml. We can now retrieve the location of docker-compose.yml using the project name. As an illustration, the directory name first_compose_project corresponds to the project name first_compose_project:

/home/maurice/docker-management/$project_name/docker-compose.yml

Critically, we can map the project name to a specific path by understanding the structure of the base directory docker_management. Of course, understanding how the projects were initially stored is paramount for this process to work.

At this point, let’s use a Bash script to automate the steps.

3.3. Automating the Process With a Bash Script

First, we create the find_compose_script.sh file in the base directory containing the Compose projects:

$ cat /home/maurice/docker-management/find_compose_script.sh
#!/bin/bash

# Store the location of the Compose projects
base_dir="/home/maurice/docker-management"

# List all of the containers that Docker Compose has generated
containers=$(docker ps --filter "label=com.docker.compose.project" --format "{{.Names}}")

# Loop through the containers
for container in $containers; do

    # Obtain the project name from the container labels
    project_name=$(docker inspect -f '{{ index .Config.Labels "com.docker.compose.project" }}' $container)

    # Specify the location to the docker-compose.yml file based on the project name
    compose_file="$base_dir/$project_name/docker-compose.yml"

    # Verify whether the Compose file is present
    if [ -f $compose_file ]; then
        echo "For project $project_name, docker-compose.yml was located at $compose_file"
        # Go to the directory and restart the services
        cd "$base_dir/$project_name" && docker-compose -f $compose_file restart
        echo
    else
        echo "docker-compose.yml for project $project_name not found!"
    fi
done

Let’s look at a partial output after we run the script:

$ bash find_compose_script.sh
For project second_compose_project, docker-compose.yml was located at /home/maurice/docker-management/second_compose_project/docker-compose.yml
Restarting second_compose_project_db_1  ... done
Restarting second_compose_project_app_1 ... done

For project first_compose_project, docker-compose.yml was located at /home/maurice/docker-management/first_compose_project/docker-compose.yml
Restarting first_compose_project_web_1   ... done
Restarting first_compose_project_redis_1 ... done

...

The first thing the script does is define the variable base_dir, which holds the path to the Docker Compose projects. After that, it provides a list of all Docker Compose containers that are currently running, iterating through each one to extract the project name from its labels.

The script then determines if the file docker-compose.yml is present at the location $base_dir/$project_name/docker-compose.yml. If the Compose file exists, the script navigates to its location and uses the command docker-compose restart to restart the services. On the other hand, the script logs the error that the docker-compose.yml file couldn’t be located if the Compose file isn’t present.

4. Conclusion

In this article, we explored how to locate the docker-compose.yml file used to start running containers.

We leveraged Docker labels, particularly the label com.docker.compose.project to map running containers back to their Compose projects. To automate locating the docker-compose.yml file, we created a Bash script.

Now, we can manage Docker Compose containers and their respective Compose files by comprehending how Docker Compose applies labels and combining this with Linux command-line tools. Thus, we can more easily manage multiple Docker Compose projects.