I recently started working on a new python project (yeah!). This project is really interesting, but the first lines of code are at least a decade old. Fortunately, this small project is relatively well designed on a Bash script and a docker compose basis. In theory, this is rather good news, but in practice, the deployment remains quite tedious.
This is because for every new configuration, we need to edit the docker-compose.yml to change some parameters (ports numbers for instance). The easiest way to manage these different parameters would be to create a docker-compose.yml file for each configuration. But in our case, we want to keep a much finer granularity where – at any time and whatever the environment (dev, prod, …) – we can change some parameters when launching all the dockers.
This finesse in the configuration of the launch of docker-compose has asked us to automate a little more the deployment of the application, through the use of environment variables.
Environment Variables
To use any environment variable with docker-compose, we need to use them inside the docker-compose.yml file:
services:
my-container:
ports:
- “${PORT}:${PORT}”
If we prefer, we can also use this format :
services:
my-container:
ports:
- “$PORT:$PORT”
With, that in mind, we are able to produce a very generic docker-composer.yml file. We can use those variables in all the file, even to configure the entrypoint script:
services:
my-container:
container_name:my_container-${VERSION}
image: “XXX.XX.XX.XXX:XXXX/my_container:${VERSION}”
ports:
- “${PORT}:${PORT}”
entrypoint:
- /local/start.sh
- -opt1=${OPTION1}
- -opt2=${OPTION2}
- -port=${PORT}
Manage the environment variables with the Environment File
The first question that should come to our mind at this point is “What will happen if those environment variables are not defined ?”. Well docker-compose will pass an empty string to any variable that will not be defined. To ensure that those variables always exist, you can store some default values in an environment file : .env. Here is an example :
#./.env
PORT=8080
VERSION=1.0
OPTION1=”my first option”
OPTION2=”my second option”
Then if the .env file is in the same directory as the docker-compose.yml file, everything should work like a charm.
Manage the environment variables in the script file
Back to our specific project, we want to be able to change any of these variables quickly. In our case, our project is a little more complex than a simple docker-compose command to launch all our docker images. So, to launch docker-compose, we go through a .sh script that does a number of things before launching the dockers. Among other things, this script allows us to launch some commands like docker-compose up, docker-compose start, docker-compose stop, rm, cp, …. Since we are really lazy, we don’t want to update the .env file every time we change the configuration. So we decide to update our script to set our environment variables via parameters. This solution will allow us to launch the application with all the options we need in a single order like this :
./myScript.sh --port=5050 --opt1=”test” --opt2=”test-server”
Which is very simple to do inside the .sh script. All we need to do is export our variables to our local environment at the end of the script, so docker will have access to these variables :
for i in “$@”
do
case $i in
--port=*)
CUTOM_PORT=”${i#*=}”
;;
--opt1 =*)
CUTOM_OPTION1=”${i#*=}”
;;
--opt2 =*)
CUTOM_OPTION2=”${i#*=}”
esac
done
# do other things if needed…
export PORT=$CUTOM_PORT
export OPTION1=$CUTOM_OPTION1
export OPTION2=$CUTOM_OPTION2
export VERSION=”1.0”
When all those modifications are done, we just need to run our docker-compose command as usual (inside the .sh file for instance) and everything will be set-up as we want !
Give it a try, it is really cool !