3 ms·
It's been a while since I've been relying on environment variables per-configuration key. I haven't defined profiles such as dev or production for a really long
by 1337shadow 6y ago
It's been a while since I've been relying on environment variables per-configuration key. I haven't defined profiles such as dev or production for a really long time, with Django projects in particular. I have collected a handful of little secrets that I can share with you.
I do have if DEBUG: based switch all along my settings file, and enforce DEBUG=True in manage.py at the same time: in manage.py set os.environ['DEBUG'] = '1', and in settings.py DEBUG = bool(os.getenv('DEBUG', False)).
My objective is that when a new developer clones the repo, and runs ./manage.py runserver or shell, it will load with all development settings by default.
In theory this could cause the problem that running manage.py commands in production would run them with DEBUG=True. I tried that, and in practice this turned out to never be a problem. But this could certainly bite you if you're not careful.
In particular, I also spread env vars in two config files: docker-compose.persistent.yml for persistent deployments, and docker-compose.ephemeral.yml for ephemeral deployments.
To complete that, because I don't want to store secrets in the git repository, I do have things like that to load multi-line environment variables in CI:
- export $(echo $PROD_EMAIL_SETTINGS | xargs)
- export $(echo $PROD_ENV | xargs)
- export $(echo $PROD_SOMEAPI | xargs)
So for example, in PROD_EMAIL_SETTINGS I have a a multiline value with EMAIL_SOME_SETTING=something for every setting that settings.py will fetch from the environment to provision the Python email settings.
And if I want the production email server settings in staging and production, I can load the set of variables that configures for the production email server with that single line.
Anyway, for me the best setting profile management, is no profile management at all: local clone should have development settings by default and just work with 0 config, configuration for deployments in compose files for non-secrets, in CI vars for secrets, and I should be able to easily decide if I need any of the settings that are in production to develop something in which case I end up building a custom profile with environment variables (ie. to debug a blackbox such as a partner API) just "for the time being", for example I have dumped the blackbox request/responses and then build up my unit tests based on that.
I'm extremely happy with that trivial setup that I have in a bunch of projects now for the last years, I thought that's what everybody who's not using a profile-based system was doing, I thought that was the essence of 12factor/config, at least that's what I understood.
- whalesalad 6y agoMitigating human errors is certainly important. The brittle nature of your onboarding story is exactly why I wrote this post and encourage the practice in it. Larger apps that I deploy have a development.py.example file that people can copy to development.py (or fredsmith.py, madonna.py, it doesn't matter. These would not be checked-in to Git) Then all I need to do before running anything in my project is prefix with ENV=fredsmith. As a team we could settle on a different name for this variable. We could all have our own environments. We could even decide, as a team, to check them into Git so that we can all see each others config in case there is an issue.
- 1337shadow 6y agoCopying a file is a manual step, that's the kind of step that I strive to remove from workflows I provide to others. Using different names for the same thing across different teams also looks like something I'd typically strive against.