Docker Compose reads .env files by default
So this it might have been apparent to everyon else, but not to me. It turns out docker compose
reads the .env of the directory you’re in and honors any of it’s COMPOSE_* environment variables
that are set there.
How I discovered this
I recently switched to using herdr from a combination of cmux and Zellij.
Part of the appeal was it’s native ability to handle git worktrees and I’ve found myself
wanting/needing that more recently.
But, 95+% of my projects run entirely in Docker Compose and to make matters worse (in this case)
I have a fancy dnsmasq -> traefik setup locally that maps https://www.project1.test to
the right docker container(s) using a COMPOSE_FILE overlay. This removes any port conflicts
when trying to run several projects who all want to expose port 8000 for example.
I use these COMPOSE_FILE overlays so they automatically are in play for when I run docker compose up
I get my fancy DNS naming/routing but do not in any way have to distrub the shared compose.yml I have
with my coworkers.
I was trying to figure out a clean/easy way to do different hostnames by worktree so I can make
https://feature-1.project1.test and https://feature-2.project1.test happen automatically
for me based on the git worktree.
During the investigation my LLM told me about this and I almost couldn’t believe it. I think
my confusion was around the that we, in most projects, define the .env to be loaded as
the environment INSIDE the docker container and since setting that required a specific
configuration that docker compose would not be looking at that file for it’s OWN configuration
on start.
I was happily surprised!
How I’m using it
I need to have overlays that look something like this:
services:
web:
ports: !reset [] # This removes ALL port mappings from base file
labels:
- "traefik.enable=true"
# HTTPS router
- "traefik.http.routers.revsys-web.rule=Host(`www.revsys.test`)"
- "traefik.http.routers.revsys-web.entrypoints=websecure"
- "traefik.http.routers.revsys-web.tls=true"
- "traefik.http.services.revsys-web.loadbalancer.server.port=8000"
# HTTP to HTTPS redirect
- "traefik.http.routers.revsys-web-http.rule=Host(`www.revsys.test`)"
- "traefik.http.routers.revsys-web-http.entrypoints=web"
- "traefik.http.routers.revsys-web-http.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.docker.network=traefik-public"
environment:
# misc things set here
networks:
- traefik-public
- default
db:
ports: !reset [] # This removes ALL port mappings from base file
networks:
- default
memcached:
ports: !reset [] # This removes ALL port mappings from base file
networks:
- default
utility:
ports: !reset [] # This removes ALL port mappings from base file
networks:
- default
networks:
traefik-public:
external: true This uses the !reset [] to wipe out the previous defined exposed ports so there are no
conflicts and adds the docker labels that traefik needs to map the hostname routing.
So I need COMPOSE_FILE=compose.yml:frank-compose.yml so my special/fancy overlay in frank-compose.yml
is used.
Then I just needed my custom herdr plugin to inject this into the existing .env for each project
and everything lines up the way I wanted it.
Hope this little tidbit was useful for you!