Docker-compose Tricks and Best Practices

Docker-compose is a very useful tool when you need to orchestrate multiple containers, especially if those containers serve a common purpose.

Technically everything that you can do with docker-compose you could also do it with docker commands, but it would be rather tedious and prone to error. Also running commands, even if you script them, doesn’t give you the capabilities that docker-compose gives you to inspect the state of what’s running and apply changes on the fly and manage container elegantly.

Here are some tips I use often because I find rather useful

Use an init process in your containers

There is a very good reason to use an init process in your containers, you can read about it here.

If you are fastidious like me, you like following best practices as much as you can and whenever possible — especially when it’s this simple! This is why I like to enable an init process in all of my docker containers by using the init command in docker compose like so:

version: '3.7'
services:
redis:
image: redis
init: true
container_name: redis

Bear in mind init works with version 2.2 of docker-compose and 3.7 onwards as specified in the yaml above.

Update containers on the fly with minimal downtime

Let’s just say we wanted to update the docker-compose.yml file above to change the redis image to their alpine version, and yes you should always use alpine whenever possible!

version: '3.7'
services:
redis:
image: redis:4.0.9-alpine
init: true
container_name: redis

After changing our all we have to do is run docker-compose up -d again and this is the result:

$ sudo docker-compose up -d
Pulling redis (redis:4.0.9-alpine)...
4.0.9-alpine: Pulling from library/redis
ff3a5c916c92: Already exists
aae70a2e6027: Pull complete
87c655da471c: Pull complete
fc6318d8b86d: Pull complete
0ce2c55a2dbe: Pull complete
c0f508e83020: Pull complete
Digest: sha256:8a2bec06c9f2aa9105b45f04792729452fc582cf90d8540a14543687e0a63ea0
Status: Downloaded newer image for redis:4.0.9-alpine
Recreating redis ... done

The image gets downloaded and the container gets recreated afterwards with minimal downtime.

Assign an ip to your container

If you are dealing with containers and you want to create a network and assign them ips you can do the following:

version: '3.7'
services:
redis:
image: redis:4.0.9-alpine
init: true
container_name: redis
networks:
dockernet:
ipv4_address: 172.20.0.2
networks:
dockernet:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16

However, you can also use the name of the service as your dns and you will be able to talk to other containers without the need to create a network. That’s a better option to keep your docker-compose files as simple as possible.

Use Yaml Templates

Imagine your first container has a lot of options that get repeated over and over in all of your service definitions. Rather than repeating yourself continuously, why not creating a template from your first service to reuse in following services?

version: '3.7'
services:
redis: &service_default
image: redis:4.0.9-alpine
init: true
restart: always
container_name: redis
extra_hosts:
- 'redis:172.20.0.2'
- 'nginx:172.20.0.3'
networks:
dockernet:
ipv4_address: 172.20.0.2
nginx:
<<: *service_default
image: nginx:1.14-alpine
container_name: nginx
networks:
dockernet:
ipv4_address: 172.20.0.3
ports:
- 80:80
- 443:443
networks:
dockernet:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16

In the above example we are defining extra_hostswhich is a way to create a host file within your docker container, think of it as makeshift dns server inside a container. We are also defining restart:always which will restart the container automatically if it crashes. Instead of having to add those to all of the containers, we define them once and we then replicate.

If you want to delve deeper into yaml templating capability for docker-compose check out this article.

Use a .env file to replace variables in your docker-compose.yml file

Sometimes you may need to create a template docker-compose file and replace some values inside.

Let’s say that you have multiple environments that are mostly the same except for a few different configurations that are different. In that case you could automatically generate a .env file with all your required variables that would replaced in your docker-compose.yml file.

For example the following .env file placed in the same directory as the docker-compose.yml file:

IMAGE_LABEL=4.0.9-alpine

Would replace the variable $IMAGE_LABEL in the following docker-compose.yml:

version: '3.7'
services:
redis:
image: redis:${IMAGE_LABEL}
init: true
container_name: redis

Use the build flag to rebuild your containers

Sometimes you want to force a rebuild of your containers with docker-compose, do it like this:

docker-compose up -d --build
# Ignore the cache:
docker-compose build --no-cache

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store