Docker-compose Tricks and Best Practices
Maximize your usage of docker-compose for your environments
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:
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!
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
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:
- 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?
- 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:
Would replace the variable
$IMAGE_LABEL in the following docker-compose.yml:
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