Search code examples
dockerdocker-compose

How to use variables from a .env file located in a parent directory when including other compose files in child directories with docker-compose


I'm using docker-compose to manage my homelab stacks. To keep things tidy, I've nested directories for the different parts of my infrastructure. It looks something like this:

main
|__ docker-compose.yaml
|__ networking
|   |__ docker-compose.yaml
|   |__ www_nginx
|   |__ etc_pihole
|   |__ .env
|   ...
|__ backups
    |__ docker-compose.yaml
    |__ .env

The top-level docker-compose.yaml looks like this:

---
version: "3"

include:
  - networking/docker-compose.yaml
  - backups/docker-compose.yaml

I want to have a single .env file under main, instead of seperate ones in each child directory.

I did a bunch of research online, and I've seen that you can point a container to an env_file, but not the compose. Apparently it's different and compose variables have to come from a .env.

However, in my case, each included sub-compose (I'll just call it that for simplicity), it pulls the .env from its own directory.

There is an issue open on Github requesting for the ability to define an alternate location than the current directory. Their main reason was to use a filename different from .env, but in my case, I want it to be usable from the parent directory.

Is there any way to achieve this? Maybe a property under include: that I missed? Or should I add another comment to the issue thread? I don't think I'm quite ready to hunt down the change and open a PR, especially if there is a better way.


Solution

  • Instead of using include, you could use the composition mechanism (or merge) of compose and use the environment variable COMPOSE_FILE to define which compose file to use.

    Given the file strucure:

    .
    ├── .env
    ├── backups
    │   └── compose.yml
    └── networking
        └── compose.yml
    

    The environment file .env:

    COMPOSE_FILE=networking/compose.yml:backups/compose.yml
    
    FOO=foo
    BAR=bar
    

    The file backups/compose.yml

    services:
      backup:
        image: alpine
        command: echo $FOO
    

    The file networking/compose.yml

    services:
      network:
        image: alpine
        command: echo $BAR
    

    Running docker compose up from the root folder would give:

    $ docker compose up
    [+] Running 1/3
     ✔ Network networking_default      Created                            0.1s 
     ⠋ Container networking-backup-1   Created                            0.1s 
     ⠋ Container networking-network-1  Created                            0.1s 
    Attaching to backup-1, network-1
    backup-1   | foo
    network-1  | bar
    backup-1 exited with code 0
    network-1 exited with code 0
    

    Important warning: the file separator in the .env file depends on your host OS, but that could also be adaped in your environment file with the variable COMPOSE_PATH_SEPARATOR.