I recently stumbled upon docker-compose's ability to share configurations between .yml files. This means that you can reuse the
docker-compose.yml used for development and testing for different environments by providing another
.yml to override settings which differ. Nice! Let's look at an example:
Let's assume we have the following service, which in our case launches a ghost blog container.
# docker-compose.yml version: '3.1' services: ghost: container_name: my-ghost-blog image: ghost:2.6.2-alpine volumes: - ./some/path/:/var/lib/ghost/content/ ports: - 52368:2368 environment: url: http://localhost:52368
For development this is fine and we can use
docker-compose up to happily verify that our ghost blog is working as intended. But for production we have to change a few things:
- The volume will be in another directory on the production machine
- The port will have to be 80 not 52368
- The url will be different.
Instead of changing the values inside
docker-compose.yml for deployment, which is error-prone has to be done manually every time, we instead use docker-compose's ability to share and overwrite settings. To do that, first we change the
docker-compose.yml into a "base" compose file, which only contains values that are either identical in all environments or can be overwritten later by another
# docker-compose.yml version: '3.1' services: ghost: container_name: my-ghost-blog image: ghost:2.6.2-alpine volumes: - /some/path/:/var/lib/ghost/content/ environment: url: http://localhost:52368
Additionally, we add another file called
docker-compose.override.yml which only contains the now missing settings for our development environment:
# docker-compose.override.yml version: '3.1' services: ghost: ports: - 52368:2368
At this point running
docker-compose up will take both the docker-compose file and the docker-compose.override file, merge them and run the resulting service. To see which configuration is used in particular, run
docker-compose config. Note how all settings from
docker-compose.yml are still there and the port inside
docker-compose.override.yml was added:
# "docker-compose config" output services: ghost: container_name: my-ghost-blog environment: url: http://localhost:52368 image: ghost:2.6.2-alpine ports: - 52368:2368/tcp volumes: - /some/path:/var/lib/ghost/content/:rw version: '3.1'
But how does this help us for production? Easy: we create yet another
docker-compose.prod.yml, which specifies the environment specific configurations for production we listed earlier:
# docker-compose.prod.yml # NOTE: keep this file secret and DON'T add it to version control version: '3.1' services: ghost: ports: - 80:2368 volumes: - /some/prod/path/:/var/lib/ghost/content/ environment: url: http://example-blog.io
To let docker-compose know to use this file instead of
docker-compose.overrride.yml to overwrite the base file, we use a different command:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
To see the complete configuration before running it, we can use
config instead of
up again. Note how the url and the volume settings were overwritten and the bound port is now 80:
# "docker-compose -f docker-compose.yml -f docker-compose.prod.yml config" output services: ghost: container_name: my-ghost-blog environment: url: http://example-blog.io image: ghost:2.6.2-alpine ports: - 80:2368/tcp volumes: - /some/prod/path:/var/lib/ghost/content/:rw version: '3.1'
Read the chapter Adding and overriding configuration to better understand how particular configurations are merged and overwritten.
So now we can use both
docker-compose.override.yml for development and testing, while for production (or any other environment) we can define a
docker-compose.prod.yml and reuse our
docker-compose.yml file. Cool!
docker-compose.ymlto contain base configurations only, which are shared among all environments.
docker-compose.override.ymlwhich contains all missing configurations for development.
docker-compose upnow overwrites and merges both files.
- For deployment to production keep a secret
docker-compose.prod.yml, which contains production configurations. Use
docker-compose -f docker-compose.yml -f docker-compose.prod.yml upto run your service based on the production settings.
upto see and verify the merged compose configuration before running it.