Context
I have a small team working on one elixir application.
Every developer runs the app locally.
The app is built with mix release
inside docker on CI and deployed as a container.
Over time, we’ve settled on this approach to configuration files:
-
config/config.exs
provides a common build-time configuration base for all dev/test/prod -
config/dev.exs
provides a build-time configuration for all developers -
config/dev.local.exs
gives a handy way to override development config locally - each developer can put whatever they need in there (per-user config, developer secrets, etc.), this file is put into.gitignore
-
config/test.exs
provides all necessary configuration to run tests - this is to ensure thatmix test
can be run right aftergit clone
without any configuration necessary -
config/prod.exs
provides build-time config for production -
config/releases.exs
provides runtime config for production, which is essentially ENV variables mapping withSystem.fetch_env!/1
so the app fails to start when some configuration is missing
Config files examples
Click to expand
# config/config.exs - common build-time config for all
use Mix.Config
config :phoenix, :json_library, Jason
import_config "#{Mix.env()}.exs"
# config/dev.exs - all config for development
use Mix.Config
config :myapp, MyAppWeb.BasicAuth, user: "", pass: ""
import_config "dev.local*.exs"
# config/prod.exs - build-time config for production
use Mix.Config
config :myapp, MyAppWeb.Endpoint, server: true
# config/test.exs - all config for test
use Mix.Config
config :myapp, MyAppWeb.Endpoint, server: false
config :myapp, MyAppWeb.BasicAuth, user: "test", pass: "test"
# config/dev.local.exs - local config for development, gitignored
use Mix.Config
config :myapp, MyAppWeb.Endpoint, url: [host: "alice-dev-proxy.example.com"]
config :myapp, MyAppWeb.BasicAuth, user: "", pass: ""
# config/releases.exs - runtime config for production
import Config
config :myapp, MyAppWeb.BasicAuth,
user: System.fetch_env!("ADMIN_USER"),
pass: System.fetch_env!("ADMIN_PASS")
The problem
The new preferred way of runtime configuration is to use config/runtime.exs
.
This file will be executed regardless if run with mix
or as a part of the release.
Now, if I simply rename my config/releases.exs
to config/runtime.exs
it will blow up in dev & test due to System.fetch_env!/1
usage. Nobody have all the ENV values referenced locally (a lot of the are secrets).
I can’t seem to find any reference on how to deal with such case.
Any ideas?
Bonus question
Another, somehow-related issues is using .exs
files as runtime configuration.
With elixir 1.10
I could add import_config "foo.exs"
at the bottom of config/releases.exs
and then mount foo.exs
file on a production system at /app/releases/0.1.0/foo.exs
(docker on kubernetes via ConfigMap).
With elixir 1.11
it now fails with ** (RuntimeError) import_config/1 is not enabled for this configuration file. Some configuration files do not allow importing other files as they are often copied to external systems
, which seems to be a bit ironic, as I do want to “copy to external system”
The question here is: I DO want to use runtime-mounted .exs
file as a configuration (alongside ENV vars) simply because it is much better than yaml, but it seems to be discouraged.