summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Gonzalez <roger@rogs.me>2020-05-14 12:36:19 -0300
committerRoger Gonzalez <roger@rogs.me>2020-05-14 12:36:19 -0300
commitda60bb5be75e206a4287aee4dd8e43378595968c (patch)
treebdbe72a48fc7e73bfc4285e4cf1a99b64179fea1
parentd0ea86d25fe53eb7b098de068740615a8e450cf9 (diff)
Added new post about docker env vars management
-rw-r--r--content/posts/manage-multiple-env-vars-in-docker-compose.md191
1 files changed, 191 insertions, 0 deletions
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 <arg>...] [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