Every alchemist requires good tools, and one of the greatest tools in the alchemist’s disposal is the distillery. The purpose of the distillery is to take something and break it down to its component parts, reassembling it into something better, more powerful. That is exactly what this project does — it takes your Mix project and produces an Erlang/OTP release, a distilled form of your raw application’s components; a single package which can be deployed anywhere, independently of an Erlang/Elixir installation. No dependencies, no hassle.
In this post, I am going to talk about distillery A tool which I’ve been using the last eight months for deploying an Elixir application. Also, we are going to show how to integrate it in a project. For that, we are going to use the phoenix framework
Please, make sure that you have installed elixir and phoenix
Ok, let the show begin.
The first thing that we are going to do is create a phoenix
project without brunch
and ecto
(just for this example). To achieve that, we need to run mix phoenix.new todo --no-ecto --no-brunch
❯ mix phoenix.new todo --no-ecto --no-brunch
* creating todo/config/config.exs
* creating todo/config/dev.exs
* creating todo/config/prod.exs
* creating todo/config/prod.secret.exs
* creating todo/config/test.exs
* creating todo/lib/todo.ex
* creating todo/lib/todo/endpoint.ex
* creating todo/test/views/error_view_test.exs
* creating todo/test/support/conn_case.ex
* creating todo/test/support/channel_case.ex
* creating todo/test/test_helper.exs
* creating todo/web/channels/user_socket.ex
* creating todo/web/router.ex
* creating todo/web/views/error_view.ex
* creating todo/web/web.ex
* creating todo/mix.exs
* creating todo/README.md
* creating todo/web/gettext.ex
* creating todo/priv/gettext/errors.pot
* creating todo/priv/gettext/en/LC_MESSAGES/errors.po
* creating todo/web/views/error_helpers.ex
* creating todo/.gitignore
* creating todo/priv/static/css/app.css
* creating todo/priv/static/js/app.js
* creating todo/priv/static/robots.txt
* creating todo/priv/static/js/phoenix.js
* creating todo/priv/static/images/phoenix.png
* creating todo/priv/static/favicon.ico
* creating todo/test/controllers/page_controller_test.exs
* creating todo/test/views/layout_view_test.exs
* creating todo/test/views/page_view_test.exs
* creating todo/web/controllers/page_controller.ex
* creating todo/web/templates/layout/app.html.eex
* creating todo/web/templates/page/index.html.eex
* creating todo/web/views/layout_view.ex
* creating todo/web/views/page_view.ex
Fetch and install dependencies? [Yn] Y
* running mix deps.get
We are all set! Run your Phoenix application:
$ cd todo
$ mix phoenix.server
You can also run your app inside IEx (Interactive Elixir) as:
$ iex -S mix phoenix.server
Once is finished, we verify that everything is OK by running the server. And we need to see the default phoenix
page.
Now it is time to add distillery
to our project. We modify our mix.exs
file and add it as a dependency.
After that, we update our dependencies and compile the whole project with mix do deps.get, compile
. Next, we proceed to change our config/prod.exs
In this file, we configure the URL
to read the PORT
from the system environment
and we instruct Phoenix
to start
the server
for all endpoints.
Before we create a release package, we need to initialize distillery
❯ mix release.init
Compiling 11 files (.ex)
Generated todo app
An example config file has been placed in rel/config.exs, review it,
make edits as needed/desired, and then run `mix release` to build the release
This command create rel/config.exs
file. In this file, we can find the configuration for building a release. We are going to keep the default configuration
. But, if you want to know more about this you can go to distillery configuration. There you will find a list of config options for releases and environments.
And that’s all, once we are done with this changes we can run MIX_ENV=prod mix release --env=prod
for creating a release.
❯ MIX_ENV=prod mix release --env=prod
==> Assembling release..
==> Building release todo:0.0.1 using environment prod
==> Including ERTS 8.3 from /usr/local/Cellar/erlang/19.3/lib/erlang/erts-8.3
==> Packaging release..
==> Release successfully built!
You can run it in one of the following ways:
Interactive: _build/prod/rel/todo/bin/todo console
Foreground: _build/prod/rel/todo/bin/todo foreground
Daemon: _build/prod/rel/todo/bin/todo start
For testing our release we are going to use the Interactive
approach. Therefore we will execute as stated in command line but will we prefix it with the port PORT=4000
❯ PORT=4000 _build/prod/rel/todo/bin/todo console
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
12:56:03.825 [info] Running Todo.Endpoint with Cowboy using http://localhost:4000
12:56:03.826 [error] Could not find static manifest at "/Users/makingdevs/Documents/todo/_build/prod/rel/todo/lib/todo-0.0.1/priv/static/manifest.json". Run "mix phoenix.digest" after building your static files or remove the configuration from "config/prod.exs".
Interactive Elixir (1.4.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(todo@127.0.0.1)1>
Now we put our ip address
into our browser followed by PORT
and we are going to see the default page as in the begining.
As a bonus, if you enter in interactive mode
. When you hit the URL you will see how the console output update everytime you hit that URL
.
❯ PORT=4000 _build/prod/rel/todo/bin/todo console
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
12:58:48.667 [info] Running Todo.Endpoint with Cowboy using http://localhost:4000
12:58:48.667 [error] Could not find static manifest at "/Users/makingdevs/Documents/todo/_build/prod/rel/todo/lib/todo-0.0.1/priv/static/manifest.json". Run "mix phoenix.digest" after building your static files or remove the configuration from "config/prod.exs".
Interactive Elixir (1.4.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(todo@127.0.0.1)1> 12:58:54.917 request_id=27n3ui1iisialbh41grg9g1btt9d67n8 [info] GET /phoenix/live_reload/socket/websocket
12:58:54.917 request_id=27n3ui1iisialbh41grg9g1btt9d67n8 [info] Sent 404 in 173µs
12:59:34.541 request_id=nmcl910kb02brqb5qsicm5ljl1a9iccj [info] GET /
12:59:34.542 request_id=nmcl910kb02brqb5qsicm5ljl1a9iccj [info] Sent 200 in 238µs
12:59:56.322 request_id=se02ut1a3fl5i9114ueta0f6ab9f44ke [info] GET /phoenix/live_reload/socket/websocket
12:59:56.322 request_id=se02ut1a3fl5i9114ueta0f6ab9f44ke [info] Sent 404 in 165µs
13:00:04.711 request_id=6omlkpefoom2abafgnco8t4tcuqec0c1 [info] GET /
13:00:04.711 request_id=6omlkpefoom2abafgnco8t4tcuqec0c1 [info] Sent 200 in 226µs
In case you have troubles, here is the repository to download this example.
I hope you can find interesting and helpful. Later we will sse how to create an upgrade
for this project.
Good luck and have fun!