Manage environmental differences with docker-compose overrides
Foreword: So recently I had the problem that I’ve deployed some software (Sentry) via docker-compose and needed to add some changes to the docker-compose.yml file to implement the correct routing for my setup. In doing so, I didn’t want to fork the project to make my changes in the official docker-compose file and so I found the override “function” for docker-compose. And here is how you can use it.
Different Environments with differing scopes
While it is good practice to keep your environments as similar as possible, there can still be differences in their configuration. A few examples of this would be:
- As a software developer, you want to test your code on your local machine and you want to set up your application from source code, rather than from a final built container.
- You don’t use the same database for your live and test systems.
- Your testing environment maybe use a different instance for example for your logging or your monitoring.
How docker-compose overrides work?
So docker-compose has an inbuilt function to merge two or more compose files together into a single merged file.
From the official docker-compose documentation :
By default, Compose reads two files, a docker-compose.yml and an optional docker-compose.override.yml file. By convention, the docker-compose.yml contains your base configuration. The override file, as its name implies, can contain configuration overrides for existing services or entirely new services.
If a service is defined in both files, Compose merges the configurations using the rules described in Adding and overriding configuration .
Through this feature, in my specific case, I was able to take the official docker-compose file and make my changes to docker-compose.override.yml. This spared me the creation of a repository fork and additionally, I get notified about direct changes in the official repository.
Example
To show the explained functionality a bit clearer I would like to show an example how the whole thing can look like. The example is based on the official Sentry docker-compose.yml and my docker-compose.override.yml to implement my traefik setup in front of the Sentry containers.
So here is a snippet of one of the services out of the official docker-compose.yml that I want to modify for my personal needs:
1services:
2 nginx:
3 <<: *restart_policy
4 ports:
5 - "$SENTRY_BIND:80/tcp"
6 image: "nginx:1.21.5-alpine"
7 volumes:
8 - type: bind
9 read_only: true
10 source: ./nginx
11 target: /etc/nginx
12 depends_on:
13 - web
14 - relay
And here is the content from my docker-compose.override.yml file:
1networks:
2 default:
3 traefik:
4 external: true
5 name: traefik_network
6
7services:
8 nginx:
9 networks:
10 - traefik
11 - default
12 labels:
13 traefik.enable: true
14 traefik.http.routers.sentry.rule: "Host(`example.com`)"
15 traefik.docker.network: traefik_network
16 traefik.http.routers.sentry.entrypoints: websecure
17 traefik.http.routers.sentry.tls: true
18 traefik.http.routers.sentry.tls.certresolver: default
As you can see, we add the traefik labels and some network configuration in our ‘override’ file.
After that, you can safe both compose files in the same location and just do your normal
docker-compose up -d
This is just a simple example. With the infinite flexibility of overrides, you can create any combination of environments to suit your needs.
Sources
Docker Compose documentation - https://docs.docker.com/compose/
Official Sentry repository - https://github.com/getsentry/self-hosted
Traefik documentation - https://doc.traefik.io/traefik/