From da60bb5be75e206a4287aee4dd8e43378595968c Mon Sep 17 00:00:00 2001 From: Roger Gonzalez Date: Thu, 14 May 2020 12:36:19 -0300 Subject: Added new post about docker env vars management --- .../manage-multiple-env-vars-in-docker-compose.md | 191 +++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 content/posts/manage-multiple-env-vars-in-docker-compose.md (limited to 'content') diff --git a/content/posts/manage-multiple-env-vars-in-docker-compose.md b/content/posts/manage-multiple-env-vars-in-docker-compose.md new file mode 100644 index 0000000..e8e2f85 --- /dev/null +++ b/content/posts/manage-multiple-env-vars-in-docker-compose.md @@ -0,0 +1,191 @@ +--- +title: "How I manage multiple development environments in my Django workflow using Docker compose" +date: 2020-05-13T11:36:48-03:00 +lastmod: 2020-05-13T11:36:48-03:00 +tags : [ "docker", "programming", "django" ] +--- + +Hi everyone! + +Last week I was searching how to manage multiple development environments with the same docker-compose configuration for my Django workflow. I needed to manage a development and a production environment, so this is what I did. + +Some descriptions on my data: + +1) I had around 20 env vars, but some of them where shared among environments. +2) I wanted to do it with as little impact as possible. + +# First, docker-compose help command + +The first thing I did was run a simple `docker-compose --help`, and it returned this: + +```bash +Define and run multi-container applications with Docker. + +Usage: + docker-compose [-f ...] [options] [COMMAND] [ARGS...] + docker-compose -h|--help + +Options: + -f, --file FILE Specify an alternate compose file + (default: docker-compose.yml) +# more not necessary stuff + --env-file PATH Specify an alternate environment file +``` + +I went with the `-f` flag, because I also wanted to run some docker images for development. By using the `-f` flag I could create a base compose file with the shared env vars (docker-compose.yml) and another one for each of the environments (prod.yml and dev.yml) + +So I went to town. I kept the shared variables inside `docker-compose.yml` and added the specific variables and configuration to `prod.yml` and `dev.yml` + +`docker-compose.yml`: +```yaml +version: "3" + +services: + app: + build: + context: . + ports: + - "8000:8000" + volumes: + - ./app:/app + command: > + sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000" + environment: + - myvar1=myvar1 + - myvar2=myvar2 + ... + - myvarx=myvarx +``` + +Since I'm going to connect to a remote RDS and a remote Redis, in my `prod.yml`, I don't need to define a Postgres or Redis image: +```yaml + +version: "3" +services: + app: + environment: + # DB connections + - DB_HOST=my-host + - DB_NAME=db-name + - DB_USER=db-user + - DB_PASS=mysupersecurepassword + ... +``` + +For `dev.yml` I added the Postgres database image and Redis image: +```yaml +version: "3" + +services: + app: + depends_on: + - db + - redis + environment: + # Basics + - DEBUG=True + # DB connections + - DB_HOST=db + - DB_NAME=app + - DB_USER=postgres + - DB_PASS=supersecretpassword + ... + db: + image: postgres:10-alpine + environment: + - POSTGRES_DB=app + - POSRGRES_USER=postgres + - POSTGRES_PASSWORD=supersecretpassword + links: + - redis:redis + + redis: + image: redis:5.0.7 + expose: + - "6379" +``` + +And to run it between environments, all I have to do is: + +```bash +# For production +docker-compose -f docker-compose.yml -f prod.yml up + +# For development +docker-compose -f docker-compose.yml -f dev.yml up +``` + +That's it! I have multiple `docker-compose` files for all my environments, but I could go even further. + +# Improving the solution + +## Improving the base docker-compose.yml file + +I liked the way it looked, but I knew I could go deeper. A bunch of vars inside the base `docker-compose.yml` looked weird, and made the file a little unreadable. So again, I went to the `docker-compose` documentation and found what I needed: [env files in docker-compose](https://docs.docker.com/compose/environment-variables/#the-env-file). + +So I created a file called `globals.env`, and moved all the global env vars to that file: + +```yaml +myvar1=myvar1 +mivar2=myvar2 +... +``` +And on the `docker-compose.yml` file I called the `globals.env` file: + +```yaml + app: + env_file: globals.env +``` + +This is the final result: + +```yaml +version: "3" + +services: + app: + build: + context: . + ports: + - "8000:8000" + volumes: + - ./app:/app + command: > + sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000" + env_file: globals.env +``` + +## Improving the running command + +As I mentioned before, I wanted as little impact as possible, and `docker-compose -f docker-compose.yml -f envfile.yml up` was a bit long for me. So I created a couple of bash files to ease the ingestion of `docker-compose` files: + +`prod`: +```bash +#!/usr/bin/env bash +# Run django as production +docker-compose -f docker-compose.yml -f prod.yml "$@" +``` + +`dev`: +```bash +#!/usr/bin/env bash +# Run django as development +docker-compose -f docker-compose.yml -f dev.yml "$@" +``` + +The `"$@"` means "Append all extra arguments here", so if I ran the `dev` command with the `up -d` arguments, the full command would be `docker-compose -f docker-compose.yml -f development.yml up -d`, so it is exactly what I wanted + +A quick permissions management: +```bash +chmod +x prod dev +``` + +And now I could run my environments as: +```bash +./dev up +./prod up +``` + +# All good? + +I was satisfied with this solution. I could run both environments wherever I want with only one command instead of moving env vars all over the place. I could go even further by moving the environment variables of each file to its own `.env` file, but I don't think that's needed for the time being. At least I like to know that I can do that down the road if it is necessary -- cgit v1.2.3