Upgrade your Continuous Integration / Continuous Delivery with Elixir using Travis CI and AWS

David Magalhães
Apr 5, 2018 · 4 min read

Nowadays continuous integration and continuous delivery are part of every project, big or small.

In one of our Elixir projects at Coletiv we decided to use Travis CI for our continuous integration and deployment pipeline. There are other solutions like AWS CodeBuild and Circle CI that you can choose from.

Although there are examples on how to deploy an Elixir application to AWS using Travis CI we added some features to our own process. This article explains the problems and the solutions we came up with.

Continuous Integration

There were two things that we wanted in our Travis CI build that were not provided out of the box:

  • Treat warnings as errors
  • Generate code coverage reports.

The first requirement can be accomplished by modifying the mix.exs file adding the aliases property.

Now every warning produced by our code will result in a build failed and must be fixed.

To add the code coverage information we used the excoveralls package. Their readme is self explanatory and you can follow it in order to generate the code coverage report. On .travis.yml we need to replace the mix test with:

This will run the tests and generate the code coverage report. The report displays a list indicating the code coverage per file and the project overall code coverage.

You can configure the excoveralls so that the build fails if the test code coverage is under a certain percentage, in our case we decided that under 80% the build should fail. To do this add the following code to the coveralls.json in the project root folder.

Continuous Delivery

To deploy an Elixir application there are a couple of possible solutions: edeliver, distillery, exrm, relx, etc. We decided to use edeliver because it uses other tools to accomplish the deployment process, it also support to use of hot code swap functionality of Erlang and is the most used by the community.

Travis CI has a functionality to deploy a service to a machine using the deploy tag on the travis yml file. The problem is that this doesn’t work with edeliver because the script runs on another bash environment and doesn’t share the same files.

To fix this issue we need to use after_success to run our own deployment script. Don’t forget to add execution permissions to the script.

The deploy.sh script has the following code. Please change the DEPLOY_BRANCH variable if you use another branch to deploy for your environments.

This script allow us to deploy to a machine, but without the hot code swap. As we are deploying to a test machine we decided not to use this functionality, but shouldn’t be difficult to add if needed.

For deployment, the build machine should have the same Operating System as the deployment machine. We use the stage machine as a build machine to deploy to both stage and production environments.

Since our machines in AWS run Ubuntu (Xenial), we could try to build in Travis CI as it also uses Ubuntu machines but with a different a release (currently Trusty). We need to further investigation in order to check if it is possible or not.

In order to connect Travis CI to the AWS machine (in this case to build and deploy) we first need to allow a SSH connection from Travis CI. We need whitelist each of 8 IP address that Travis CI use. Here is a partial list of the whitelist entries added on our security group in AWS.

AWS Security Group permissions

We also need to provide Travis CI the private key to connect to the machine we want our code to be deployed, and the best way to do this is encrypt it using Travis CI encrypt functionality. Here you can find a tutorial on how to do get it encrypted to be use in Travis CI, and here more information about it.

Here is an example of script. Don’t forget to change the IP of the machine to the machine you want to deploy and the private key file path.

In the first line, we indicate SSH to know what key it needs to use to access the SSH on the stage server. In the second line we decrypt the private key needed to access SSH. And finally, the third line we limit the permission on the private key, needed to access the SSH (normally needed when using with SSH connections).

If you have any suggestions please let me know on the comments section.


Thoughts, dreams and rants about technology and work life from the Coletiv team

Thanks to Tiago Duarte.

David Magalhães

Written by

Software Developer



Thoughts, dreams and rants about technology and work life from the Coletiv team