How to create a Elixir release and use environment variables configured at runtime.
Tags: elixir, erlang, docker
Published: 2019-01-27 06:23:29

---
title: How to create a Elixir release and use environment variables configured at runtime.
published: true
description: Tutorial on how to use distilery with configTuples provide 
tags: Elixir, Erlang, Docker
---

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](https://elixir-lang.org/) 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](https://www.docker.com/).

## 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..

![Elixir Release](https://thepracticaldev.s3.amazonaws.com/i/wzvbydxj97fhro2f1rf5.PNG)

After running your release, you should see the defined config values.

![Elixir running release](https://thepracticaldev.s3.amazonaws.com/i/lom3xonirpy22mum5f4y.PNG)

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!

![elixir](https://thepracticaldev.s3.amazonaws.com/i/c3cl2oebfy9dagppe9bh.PNG)

## 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
```


![Elixir Docker](https://thepracticaldev.s3.amazonaws.com/i/phpks1o2xv6qwz9lv0i1.PNG)

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](https://m.do.co/c/d155e881c080), works like a charm for my projects.

1st Published at Medium: [Visit](https://medium.com/@ophasnoname_44358/how-to-create-a-elixir-release-and-use-environment-variables-configured-at-runtime-dbb2580ba42d)