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 application version must include the Mix environment; this way we build different packages per environment which we can still install in one distribution tree;
- We expect a 1:1 correspondence between Mix and Distillery environments.
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:
- Add
docker_distillerto your list of dependencies inmix.exs:
```elixir
def deps do
[{:docker_distiller, "~> 0.1.0"}]
end
```
Run
mix release.initto get a Distillery config setup. See the Distillery Docs for details.Some changes in
rel/config.exsyou need to make:Set
default_environmenttoMix.env. You usually want this anyway.Include an
environmentstanza for every Mix environment you want a build for. We read the list of environments to decide what to build.
Add a target
docker_reposetting to your application inmix.exs. Also, your version MUST become Mix environment specific so we can build parallel releases. Change theversionsetting inmix.exsto 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(Optionally) override the build image. By default, we will use the
msaraiva/elixir-devimages 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"...]endAdd a template Dockerfile called
Dockerfile.deploy.eex. This template will get stuff injected from the build and then written asDockerfile, 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 theADD (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.
- Run
mix publishto build a release and publish it. You can now run your container in different environments by just settingMIX_ENV.