Django check and alternate Docker Compose file: Debug flag not being set?
Question:
I’m trying to prep a Django application for production. I created an alternate docker-compose YML file where I specify DEBUG=0. However when I run the django check for deployment, it says that DEBUG is set to True.
Any thoughts on where I’m going wrong? I thought it was an issue with my use of Docker. But is it perhaps an issue with how I’m using Django?
Here are my steps:
- Created my project with docker-compose.yml (see below)
- Created docker-compose-prod.yml for production (see below)
- Ran the following
$ docker-compose down
$ docker-compose -f docker-compose-prod.yml up -d --build
$ docker-compose exec web python manage.py check --deploy
- Output of the check:
?: (security.W018) You should not have DEBUG set to True in deployment.
Some of investigatory steps so far:
A. Check the environment variables.
$ docker-compose exec web python
>>> import os
>>> os.environ.get('DEBUG')
'0'
B. Try rebuilding docker image in different ways, e.g. with –no-cache flag
C. Set the DEBUG flag in settings.py in a conditional code block (rather than using os.environ.get). This seemed to work. But I don’t understand why? Code detail below.
Code excerpts
- Excerpt from docker-compose.yml
services:
web:
...
environment:
- ENVIRONMENT=development
- SECRET_KEY=randomlongseriesofchars
- DEBUG=1
- Excerpt from docker-compose-prod.yml
services:
web:
...
environment:
- ENVIRONMENT=production
- SECRET_KEY=anotherrandomlongseriesofchars
- DEBUG=0
- Excerpts from settings.py
ENVIRONMENT = os.environ.get('ENVIRONMENT', default='production')
SECRET_KEY = os.environ.get('SECRET_KEY')
DEBUG = os.environ.get('DEBUG', default=0) #How is DEBUG being set to True?
...
if ENVIRONMENT == 'production':
[Various settings for production]
[Putting DEBUG=0 in this conditional block works]
Answers:
Environment variables are strings, so result of os.environ.get()
is a string.
If code expects variable to be int, boolean, etc – not string – first, it might fail. Or, try converting to desired type, an that might differ from desired result.
I.e., if converting to boolean, only empty string would result in False
.
So, possible options are:
- add logic to first read env vars and then correctly convert or parse them into target arguments.
- use env helpers, like django-environ, environs which allow to auto-convert env vars to taget type and provide useful utility methods, generally providing something you might have implemented yourself in option 1
- use different schema to pass arguments – i.e. not by env vars, but by custom settings file (there also exist helpers for that). Someone prefers env vars, someone prefers files, it also might depend on project / team / how you deploy (what is supported by instrument).
DEBUG = (os.getenv('DEBUG', '0') == '1')
I’m trying to prep a Django application for production. I created an alternate docker-compose YML file where I specify DEBUG=0. However when I run the django check for deployment, it says that DEBUG is set to True.
Any thoughts on where I’m going wrong? I thought it was an issue with my use of Docker. But is it perhaps an issue with how I’m using Django?
Here are my steps:
- Created my project with docker-compose.yml (see below)
- Created docker-compose-prod.yml for production (see below)
- Ran the following
$ docker-compose down
$ docker-compose -f docker-compose-prod.yml up -d --build
$ docker-compose exec web python manage.py check --deploy
- Output of the check:
?: (security.W018) You should not have DEBUG set to True in deployment.
Some of investigatory steps so far:
A. Check the environment variables.
$ docker-compose exec web python
>>> import os
>>> os.environ.get('DEBUG')
'0'
B. Try rebuilding docker image in different ways, e.g. with –no-cache flag
C. Set the DEBUG flag in settings.py in a conditional code block (rather than using os.environ.get). This seemed to work. But I don’t understand why? Code detail below.
Code excerpts
- Excerpt from docker-compose.yml
services:
web:
...
environment:
- ENVIRONMENT=development
- SECRET_KEY=randomlongseriesofchars
- DEBUG=1
- Excerpt from docker-compose-prod.yml
services:
web:
...
environment:
- ENVIRONMENT=production
- SECRET_KEY=anotherrandomlongseriesofchars
- DEBUG=0
- Excerpts from settings.py
ENVIRONMENT = os.environ.get('ENVIRONMENT', default='production')
SECRET_KEY = os.environ.get('SECRET_KEY')
DEBUG = os.environ.get('DEBUG', default=0) #How is DEBUG being set to True?
...
if ENVIRONMENT == 'production':
[Various settings for production]
[Putting DEBUG=0 in this conditional block works]
Environment variables are strings, so result of os.environ.get()
is a string.
If code expects variable to be int, boolean, etc – not string – first, it might fail. Or, try converting to desired type, an that might differ from desired result.
I.e., if converting to boolean, only empty string would result in False
.
So, possible options are:
- add logic to first read env vars and then correctly convert or parse them into target arguments.
- use env helpers, like django-environ, environs which allow to auto-convert env vars to taget type and provide useful utility methods, generally providing something you might have implemented yourself in option 1
- use different schema to pass arguments – i.e. not by env vars, but by custom settings file (there also exist helpers for that). Someone prefers env vars, someone prefers files, it also might depend on project / team / how you deploy (what is supported by instrument).
DEBUG = (os.getenv('DEBUG', '0') == '1')