loading...

How to version control docker-compose file

ducaale profile image Mohamed Dahir Originally published at ducaale.github.io ・2 min read

At some point docker-compose file gets complicated and we need to version control it. the typical directory structure looks like this:

todo
├── .env
├── docker-compose.yml
├── todo-api/
├── todo-worker/
└── todo-database/

and our docker-compose.yml file is like this:

# todo/docker-compose
version: '3.1'

services:
  todo-database:
    image: postgres:11.3
    volumes:
      - ./todo-database:/docker-entrypoint-initdb.d/
    environment:
      POSTGRES_PASSWORD: $POSTGRES_PASSWORD

  todo-api:
    build: ./todo-api
    environment:
      APP_KEY: $APP_KEY
      DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@todo-database:5432/postgres

  todo-worker:
    build: ./todo-worker
    environment:
      DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@todo-database:5432/postgres

and here is our .env file

# todo/.env
POSTGRES_PASSWORD=secret-1
APP_KEY=secret-2

So how we can version control it?

One way to do it is by creating todo-compose/ folder and moving .env and docker-compose.yml files to todo-compose/ so we can initialize a git repo in it

$ mkdir todo-compose
$ mv docker-compose.yml .env todo-compose/

then we rename .env to .env.example and remove all passwords in it so we can use it as a reference. now todo-compose/ should be like this:

todo-compose
├── .env.example
└── docker-compose.yml

because we moved docker-compose.yml file to its own folder, we will have to modify each service build and volume keys to move up one directory like this:

# todo/todo-compose/docker-compose.yml
version: '3.1'
  # ...
  todo-database:
    volumes:
      - ../todo-database:/docker-entrypoint-initdb.d/
  # ...
  todo-api:
    build: ../todo-api
  # ...
  todo-worker:
    build: ../todo-worker
  # ...

but can we do better? it turns out that we can use symbolic links to make docker think that docker-compose.yml exists in todo/ while in reality it is inside todo/todo-compose/

$ ln -s todo-compose/docker-compose.yml ./docker-compose.yml

now we copy our .env.example reference file to todo/

$ cp todo-compose/.env.example ./.env

next we modify our newly created .env to contain project passwords. now our directory structure should be like this:

todo
├── .env
├── docker-compose.yml -> todo-compose/docker-compose.yml
├── todo-compose/
│   ├── .env.example
│   └── docker-compose.yml
├── todo-api/
├── todo-worker/
└── todo-database/

One benefit that this method has is if you have multiple docker files like this:

todo-compose
├── .env.example
├── docker-compose.yml/
├── docker-compose.prod.yml/
└── docker-compose.dev.yml/

and you were issueing docker-compose -f docker-compose.yml -f docker-compose.dev.yml up in development and docker-compose -f docker-compose.yml -f docker-compose.prod.yml up in production. now you just have to do

# in development
$ ln -s todo-compose/docker-compose.yml ./docker-compose.yml
$ ln -s todo-compose/docker-compose.dev.yml ./docker-compose.override.yml

# in production
$ ln -s todo-compose/docker-compose.yml ./docker-compose.yml
$ ln -s todo-compose/docker-compose.prod.yml ./docker-compose.override.yml

then you can use the same command docker-compose up for development and production

this post first appeared at https://ducaale.github.io

Posted on by:

Discussion

pic
Editor guide