DockerDistiller

This package uses Distillery and Docker to create containerized builds of Elixir apps that are small and nimble.

To that end, it uses Alpine Linux as a base container OS and Marlus Saraiva's Great Work on keeping current versions of Erlang and Elixir for Alpine/Docker.

Elixir apps expect Application.get_env to spit out values which by default come from config/*.exs and are environment-specific. Applications like Logger may want to even change their compile-time (macro) behavior based on the settings there and the current configuration set in effect (usually based on Mix.env). Distillery builds for one of these environments but a typical use of Docker is that you build one container for all environments.

There are solutions to this but they all revolve around extra libraries and/or code to be written over the relatively clean and straightforward Mix configuration.

We shove the problem under the rug by building for all environments and dropping all distributions in a single container. This way, we can have our cake and it it, too. We need some conventions to be setup for this to work:

The Installation/Use section has specific instructions on how to set things up.

Installation/Use

If available in Hex, the package can be installed as:

  1. Add docker_distiller to your list of dependencies in mix.exs:
```elixir
def deps do
[{:docker_distiller, "~> 0.1.0"}]
end
```
  1. Run mix release.init to get a Distillery config setup. See the Distillery Docs for details.

    Some changes in rel/config.exs you need to make:

    1. Set default_environment to Mix.env. You usually want this anyway.

    2. Include an environment stanza for every Mix environment you want a build for. We read the list of environments to decide what to build.

  2. Add a target docker_repo setting to your application in mix.exs. Also, your version MUST become Mix environment specific so we can build parallel releases. Change the version setting in mix.exs to something like "0.1.0-#{Mix.env}". The dash and Mix environment are mandatory. You will end up with something like:

    def project do
    [app: :my_app,
    version: "0.1.0-#{Mix.env}",
    docker_repo: "quay.io/my_quay_repo",
    ...
    ]
    end
  3. (Optionally) override the build image. By default, we will use the msaraiva/elixir-dev images for the correct elixir version, but you can override this in the project settings (in case you use a newer Elixir than published, or you can't use public Docker images for security reasons, etcetera):

    def project do
    [...
    build_image: "super.repo.io/myrepo/elixir-dev:1.2.3"
    ...
    ]
    end
  4. Add a template Dockerfile called Dockerfile.deploy.eex. This template will get stuff injected from the build and then written as Dockerfile, overwriting existing things. The following is sent to the template:

    • add_dist_tars: Put an expansion for this in the Dockerfile at the location where you want the ADD (tarball) (appname) lines to land
* `cmd_for_mix_env`: The command to run given an environment of MIX_ENV
An example minimal template:
```
FROM msaraiva/erlang:18.3
# Default version to run. We use MIX_ENV to be compatible
ENV MIX_ENV=prod
<%= add_dist_tars %>
CMD <%= cmd_for_mix_env %> foreground
```
Note that even though the distribution tar contains Erlang, there are packages that
Erlang needs (like the libncurses) so building from a basic Alpine image will most
likely not work.
  1. Run mix publish to build a release and publish it. You can now run your container in different environments by just setting MIX_ENV.