I use init
callbacks with System.get_env
for this.
In endpoint.ex
@doc """
Callback invoked for dynamically configuring the endpoint.
It receives the endpoint configuration and checks if
configuration should be loaded from the system environment.
"""
@spec init(atom, Keyword.t()) :: {:ok, Keyword.t()} | no_return
def init(_key, config) do
if config[:load_from_system_env] do
port = System.get_env("PORT") || raise("expected the PORT environment variable to be set")
secret_key_base =
System.get_env("SECRET_KEY_BASE") ||
raise("expected the SECRET_KEY_BASE environment variable to be set")
config =
config
|> Keyword.put(:http, [:inet6, port: port])
|> Keyword.put(:secret_key_base, secret_key_base)
{:ok, config}
else
{:ok, config}
end
end
and in repo.ex
@doc """
Callback invoked for dynamically configuring the repo.
It receives the repo configuration and checks if
configuration should be loaded from the system environment.
"""
@spec init(atom, Keyword.t()) :: {:ok, Keyword.t()} | no_return
def init(_type, config) do
if config[:load_from_system_env] do
db_url =
System.get_env("DATABASE_URL") ||
raise("expected the DATABASE_URL environment variable to be set")
config = Keyword.put(config, :url, db_url)
{:ok, config}
else
{:ok, config}
end
end
You would need to add load_from_system_env: true
or something similar to your prod configs for your repo and web apps to know when to load vars from env and when not to.
ecto’s prod config
config :my_ecto_app, MyEctoApp.Repo,
load_from_system_env: true, # <---
pool_size: 20
phoenix’s prod config
config :my_phoenix_app, MyPhoenixApp.Endpoint,
load_from_system_env: true, # <---
url: [scheme: :https, host: "somehost.com", port: 443],
cache_static_manifest: "priv/static/cache_manifest.json",
version: Application.spec(:my_phoenix_app, :vsn),
server: true,
root: "."
Works fine with kubernetes and docker so far.