First things first, please indulge me, this is not my mother tongue!
One of the problems we are facing with every new application is the proper usage of Elixir with the possibility to use environment variables from a “docker-compose” file to configure the application at runtime.
There a several approaches to do this, but i want to show you my preffered way with Distillery and the “configTuples” Provider.
This combination allows us to build a new release and set configuration parameters like Database credentials at runtime.
I will guide you through one simple example, we will create a new Elixir application, add the nessecary config provider and run/build it with Docker.
Create our example application
Lets create a new application, I will call it “fuchsbau” … don’t ask me why :-)
$ mix new fuchsbau --module Fuchsbau
We will add some stupid code to echo a bunch of example environment variables (just to verify that this approach is working as expected).
## Example code to test environment variables
Create a new file “../lib/starter.ex” with the following content, to echo our configuration.
defmodule Starter do
use Application
def start(_type, _args) do
IO.puts("... hey fuchsbau")
Starter.echo_variables
end
@doc """
Echo defined environment variables from config.exs
"""
def echo_variables do
owner = Application.get_env(:fuchsbau, :config)[:fuchsbau_owner]
street = Application.get_env(:fuchsbau, :config)[:fuchsbau_street]
phone = Application.get_env(:fuchsbau, :config)[:fuchsbau_phone]
IO.inspect(owner)
IO.inspect(street)
IO.inspect(phone)
{:ok, self()}
end
end
To run this code we have to add it to our “mix.exs”
# Run "mix help compile.app" to learn about applications.
def application do
[
mod: {Starter, []},
extra_applications: [:logger]
]
end
Add examples to config.exs
To have some config variables for our test, please add some config values to your config.exs.
In a “real- world” example we would use different configs like “prod.exs” .. but for this short how to, it should be fine to just use config.exs
config :fuchsbau, :config,
fuchsbau_owner: {:system, "FUCHSBAU_OWNER", default: "Anonymous"},
fuchsbau_street: {:system, "FUCHSBAU_STREET", default: "Somewhere..."},
fuchsbau_phone: {:system, "FUCHSBAU_PHONE", default: 67282929, type: :integer}
Use Distillery and ConfigTuples Provider
Here is the interesting part, you have to add Distillery and configTuples to your application (mix.exs).
defp deps do
[
{:distillery, "~> 2.0"},
{:config_tuples, "~> 0.2.0"}
]
end
At your command line, run the following to get the new dependencies and to init the release (this will create a new directory “/rel” with a config.exs file we need to setup configTuples):
$ mix deps.get
$ mix release.init
To make use of the new config provider, add it to “/rel/config.exs”
release :fuchsbau do
set version: current_version(:fuchsbau)
set applications: [
:runtime_tools
]
# ConfigTuples Provider !
set config_providers: [
ConfigTuples.Provider
]
end
Time for the first Test
Thats all to use Distillery and the ConfigTuples provider (don’t worry we will continue with the Docker stuff in just a couple of minutes..)
Let’s try our release run:
$ mix release
You will see some examples to start the release, just use the one with “foreground”.. and hell yes .. i have to use Windows, forgot my MacBook at work..
After running your release, you should see the defined config values.
To verify that we are able to set environment variables at runtime, try the following:
$ export FUCHSBAU_OWNER=Medium
$ _build/dev/rel/fuchsbau/bin/fuchsbau foreground
This will output “Medium” as owner of the Fuchsbau!
Use Docker to build and run our application
The last step for this how to: We will create a Dockerfile to build our application and to run it.
Create a new file: “Dockerfile” in your project root with the following content:
FROM bitwalker/alpine-elixir:1.7 as build
# Copy the source folder into the Docker image
COPY . .
# Install dependencies and build Release
RUN export MIX_ENV=prod && \
rm -Rf _build && \
mix deps.get && \
mix release
# Extract Release archive to /rel for copying in next stage, please change the application name
RUN APP_NAME="fuchsbau" && \
RELEASE_DIR=`ls -d _build/prod/rel/$APP_NAME/releases/*/` && \
mkdir /export && \
tar -xf "$RELEASE_DIR/$APP_NAME.tar.gz" -C /export
# Deplyment
FROM pentacent/alpine-erlang-base:latest
# Copy and extract .tar.gz
COPY --from=build /export/ .
# Set default entrypoint and command
ENTRYPOINT ["/opt/app/bin/fuchsbau"]
CMD ["foreground"]
This Dockerfile will create a new Image with Alpine as base. Let’s test it with a changed value for our “FUCHSBAU_OWNER” environment variable.
docker build -t fuchsbau .
docker run -e FUCHSBAU_OWNER=FridayIsMyDay fuchsbau
If you want to get the sources for this example, feel free: https://github.com/opHASnoNAME/elixir-docker-envs.
To host your application i would suggest DigitalOcean, works like a charm for my projects.
1st Published at Medium: Visit
Top comments (1)
We use it to support all kind of different OS without the need to compile for every customer.