Deploying Elixir Applications with Distillery

Written by Pete Corey on Dec 26, 2016.

While churning through the exercises in Programming Elixir (affiliate link), I came across a section dedicated to deploying Elixir applications using the Elixir Release Manager (exrm).

Browsing through the Elixir Release Manager project, I noticed that it is being replaced by Distillery:

I would highly recommend using [Distillery] moving forward, as most of my efforts will be put towards that project from now on.

Rather than learning how to use a deprecated tool, I decided it might be a better investment of my time to learn how to deploy Elixir applications using Distillery.

Below is a guide for doing a basic release with Distillery. For the most part, the instructions are very similar to doing a release with exrm, with a few minor differences.

Creating Our Application

Before we start, we’ll need an Elixir project we want to deploy. To keep things simple, we’ll use a bare-bones Phoenix application. We can create our application (called HelloDistillery) with the phoenix.new Mix task:

mix phoenix.new --no-ecto hello_distillery

Once we’ve got our application set up and tested locally (mix phoenix.server), we can start the Distillery deployment process.

Installing Distillery

The first step of deploying an Elixir project with Distillery is to add Distillery as a dependency. In our mix.exs file, add a dependency on :distillery version 1.0:


{:distillery, "~> 1.0"}

Now tell Mix to pull down the new dependency:

mix deps.get

Once installed, Distillery creates a new release Mix task. If we try to run it, we’ll be told that we need to do some initial configuration:

mix release
==> You are missing a release config file. Run the release.init task first

Following that advice, we can generate our initial config file with the release.init Mix task:

mix release.init

Review the newly generated rel/config.exs file. For our purposes, the defaults should be fine.

Configuring Our Release

The last step before we build our first release is to do some final configuration on the environment we’ll be deploying.

In our case, we’ll be deploying the prod environment. If we look in our config/prod.exs file, we’ll see a comment block addressing releases:


# ## Using releases
#
# If you are doing OTP releases, you need to instruct Phoenix
# to start the server for all endpoints:
#
# config :phoenix, :serve_endpoints, true
#
# Alternatively, you can configure exactly which server to
# start per endpoint:
#
#     config :hello_distillery, HelloDistillery.Endpoint, server: true

Following this advice and the advice in the Distillery Phoenix Walkthrough, we’ll add a few configuration options to our HelloDistillery endpoint, and update its url:


config :hello_distillery, HelloDistillery.Endpoint,
  ...
  url: [ ... ],
  server: true,
  root: ".",
  version: Mix.Project.config[:version]

Once we’ve made those configuration changes, we’re ready to build and deploy our release!

Building Our Release

Building our release with Distillery is an easy process.

If we’re deploying a Phoenix application, we’ll need to be sure that we’ve bundled our front-end assets. We can do that with the following command:

brunch build --production

Next, we’ll run a series of Mix tasks. First, we’ll compile our project. Next, we’ll compress and digest all of our static files. Finally, we’ll build our prod release:

MIX_ENV=prod mix do compile, phoenix.digest, release --env=prod

The mix release task builds our release and places it in the _build folder. To make sure everything went well, we can run the release locally using the following command:

PORT=8080 ./_build/prod/rel/hello_distillery/bin/hello_distillery foreground

If the release was successful, we should see our application’s server logs in the console, and we should be able to access your application at http://localhost:8080.

Deploying Our Release

At this point, I’ll assume that you’ve already provisioned the machine you’ll be using for your production environment.

As a side note, I decided to deploy my application to an Amazon EC2 instance running 64 bit Amazon Linux.

Because we’re using the default configuration value of include_erts: false, we’ll need to be sure that Erlang is installed on the machine we’ll be deploying our release to.

Following these instructions, I was able to easily build Erlang from source and install it on my production machine. You may also have luck with a pre-compiled Erlang package.

Be sure to use the same version of Erlang on your production machine as the machine you built your release on. If you do not, you may encounter obtuse errors when trying to run your release.

Once our machine is provisioned and Erlang is installed, we’ll copy our release tarball from our development machine up to our production machine:

scp -i ~/hello_distillery.pem \ 
       _build/prod/rel/hello_distillery/releases/0.0.1/hello_distillery.tar.gz \
       ec2-user@ec2-...amazonaws.com:/home/ec2-user

Be sure to tweak this command to suite your needs. I’m authenticating with a pem file stored in my home directory, and deploying to the home directory of the default ec2-user of my Amazon EC2 instance.

Once our release tarball is pushed up to our production server, we’ll need to extract it and run the release.

On the production server, extract the newly uploaded tarball:

tar -xzf ~/hello_distillery.tar.gz

Now is the moment of truth. Run the release binary using the foreground option:

PORT=8080 ./bin/hello_distillery foreground

If everything went well, we should see our application’s server logs in the console. Additionally, we should be able to access our application at our production machine’s host on port 8080 (granted you’ve properly opened that port).

Now that we know everything works, kill the server process. This time we’ll run the hello_distillery application as a daemon:

PORT=8080 ./bin/hello_distillery start

Once we’ve started the application, we can ensure that it’s running with a ping:

./bin/hello_distillery ping
> pong

And with that, we’ve deployed a basic Phoenix application using Distillery!

Final Thoughts

This was a simple run-through of a happy-path first deployment using Distillery.

I highly recommend you check out Distillery’s documentation, especially the Walkthrough and Phoenix Walkthrough sections. They go into much more detail about the various aspects of deploying with Distillery.

Overall, the process of deploying an application with Distillery was very similar to the Elixir Release Manager process described in Programming Elixir.

If you’d like to see Distillery in action, check out this short webm of entire entire deployment process:

Intentionally Learning Elixir

Written by Pete Corey on Dec 19, 2016.

I’ve been programing computers in one way or another since I was ten years old. This means that I’ve had to teach myself quite a bit over the years.

My usual method of learning new programming concepts is to immerse myself in blog posts, online tutorials, forums, and chat rooms, trying to absorb as much information as I can. Unfortunately, I’ve come to realize that this can be a slow, unfocused method of learning.

When learning from scattered resources, information can come to me in an unideal order and from authors with entirely different outlooks and perspectives on the topics they’re teaching about.

Wanting to fast-track learning Elixir, I decided to try something I’d always shied away from. Reading books!


I’ve spent the past two weeks reading Programming Elixir (affiliate link) by Dave Thomas.

I picked Programming Elixir over the other multitude of books on Elixir because it’s often touted as the best introductory book to the language. After reading it, I’d have to agree that’s it’s a fantastic entry point.

To get the most out of the experience, I decided to read through the book in an intentionally focused way, reproducing most examples on my own machine, and completely (nearly) every exercise.

At the end of the day, I can happily say that the time investment is paying off. While I originally thought I had a grasp on Elixir, I feel significantly more comfortable with all of the nuances of the language after having read the book.


Next, I plan on reading Elixir in Action (affiliate link) by Sasa Juric to get a better handle on OTP and “thinking in processes”.

This experience has shown me that books are an invaluable tool for learning programming concepts. The curated, focused approach of following a single author’s train of thought through a topic really does give the reader a solid understanding of the topic.

If you’re looking for a book on Elixir, I highly recommend starting with Programming Elixir (affiliate link).

How to use MongoDB With Elixir - Revisited

Written by Pete Corey on Dec 5, 2016.

I recently wrote an article on how to use MongoDB with Elixir. Since that article was released, changes have been made to the MongoDB Elixir package.

In many ways, these changes make the package more approachable and flexible for developers, but they left my old instructions outdated and incomplete.


Previous versions of the MongoDB driver (< 0.2) required that you build your own MongoPool module somewhere in your project:


defmodule MongoPool do
  use Mongo.Pool, name: __MODULE__, adapter: Mongo.Pool.Poolboy
end

This MongoPool module set up your connection pooling (using Mongo.Pool.Poolboy) and was the main process you would instantiate to establish a connection with your MongoDB database:


{:ok, _} = MongoPool.start_link(database: "test")

Once the connection was established, you could query the database through the connection pool, without specifying the PID if the pool’s process:


MongoPool
|> Mongo.find("collection", %{ "foo" => "bar" })
|> Enum.to_list

However, with version 0.2 of the MongoDB driver, things have changed.

Now, you instantiate your connection to your MongoDB database by spinning up the Mongo process directly:


{:ok, mongo_pid} = Mongo.start_link(database: "test")

The first argument to Mongo.find/Mongo.insert_one/etc… is now the Mongo process ID:


mongo_pid
|> Mongo.find("collection", %{ "foo" => "bar" })
|> Enum.to_list

Alternatively, you can name your Mongo process to avoid having to pass the mongo_pid around your application:


{:ok, _} = Mongo.start_link(database: "test", name: :mongo)

:mongo
|> Mongo.find("collection", %{ "foo" => "bar" })
|> Enum.to_list

Out of the box, this will establish a single connection to the database. To enable connection pooling, like we had with our old MongoPool, we need to specify how we want our pooling handled when we spin up our Mongo process:


{:ok, _} = Mongo.start_link(database: "test", name: :mongo, pool: DBConnection.Poolboy)

You then need to specify the pool module you’re using when running MongoDB operations:


:mongo
|> Mongo.find("collection", %{ "foo" => "bar" }, pool: DBConnection.Poolboy)
|> Enum.to_list

The heart of these changes is that the mongodb driver package is now using the DBConnection package, instead of wrapping Poolboy itself.

See the changelog and the GitHub documentation and the Hex documentation for more details.