Deploying Elixir releases

I have seen great posts about Elixir release deployments lately and I would like to share my experience deploying Elixir releases to production. After testing different approaches (from git cloning code in the target machine to building Docker images), I decided to go with, in my opinion, a simpler approach.

Deployment is critical

Deployment is one of the most important things in a project. It needs to be easy, fast and painless to rollback when things go wrong. Although it’s critical part of a project, it is sometimes overlooked. It’s not hard to find teams that deploy to a production-like environment only when they will release the project to the public, after months of development and thousands of commits.

Delaying a project deployment until you need to expose your project to the world, brings many unnecessary risks, like:

All those risks can be mitigated if the deployment starts early, is automated and it’s performed by everyone throughout the development phase.

Goals

The goals when defining the deployment strategy of this project, was to offer a really simple and fast way of getting a new release shipped. The TODO list while researching and implementing it was:

Development

Development cycle
Development cycle

Before we get into the deployment, I think it’s important to give you some context about the project development cycle, since it has a direct impact on how the deploy is done. The numbers on the image means:

  1. The developer pushes her/his local changes to Github;
  2. CircleCI pulls the changes and run the automated tests. If all tests pass, then an Elixir release is created, using Exrm;
  3. The release is pushed to a AWS S3 bucket.

Some facts about this cycle:

Infrastructure

Infrastructure
Infrastructure

The infrastructure that powers this project is quite standard, but let’s take a look on it into more details:

The infrastructure has its creation and setup automated by Ansible. All the information about the load balancers, web servers, databases, caches, etc are stored and managed by Ansible.

For that reason, using Ansible also for deployments seemed to be a really good fit for our case.

Deploying

For a post about “deployment”, we have spent a considerable amount of time talking about different things, but not really getting into the main topic… deployment.

Deployment
Deployment

As mentioned earlier, we used Ansible for setting all the machines used by this project. Deploying a new version of the project, means running an Ansible Playbook, that contains all the tasks to be applied to the target machines.

That’s the command that someone (developer, web, Slack bot) runs in order to deploy a new version:

  $ ansible-playbook --ask-vault-pass --extra-vars "version=[COMMIT]" -i [ENV] deploy.yml

Let’s break this command down into smaller parts:

When this command runs, several tasks are applied to the machines present in the environment inventory. Using the image above, let’s see what happens in each stage:


Thanks to Elixir releases (and Exrm), the entire deployment process takes less than 30 seconds per machine (when not dealing with long-running migrations) and it’s pretty straightforward.

Are you deploying Elixir to production? What’s your approach? Feel free to send me a message.

You might also like

Free book

Today I released "Versioned APIs with Phoenix" free book. It covers three different strategies on API versioning with Phoenix...

Phoenix API versioning: Accept Header

This is the second part of the API versioning series. This post shows how to achieve API versioning using the Accept header...

Phoenix API versioning: URL

API versioning allows you to response with different content, based on the information sent by the client. Let's see how to do that with Phoenix...

Download free e-book

Learn different strategies on API versioning with "Versioned APIs with Phoenix" free e-book