The development experience in Elixir is amazing, but deploying to production can still be difficult. Akd was developed to improve this process, and once configured, it makes deployment as easy as
In this walkthrough we will be covering the basics of Elixir deployments and
how we can make them easier with Annkissam's deployment package:
Akd, in its purest form, is a way of executing a list of operations on a remote
(or local) machine. Akd provides a DSL that allows developers to
define a pipeline consisting of a set of these operations. It also allows you to provide corresponding,
remedial operations, in the event that one or more of the pipeline
operations fails. Akd was inspired by the Ruby gem
capistrano, and should feel somewhat familiar to users experienced with that gem.
Akd's primary goal is twofold:
- to provide developers with the ability to easily compose a series of deloyment operations using the Elixir programming language, and
- to standardize the way in which Elixir application deployments (using tools
docker) are performed.
We will talk more about Akd as we proceed through this walkthrough.
How does Akd work?
Hooks form the core functionality for Akd. A
Hook is an abstraction around a
set of sequential operations. These operations
include the commands to be executed within the contexts of both (i) a pseudo-terminal
and (ii) the desired host.
Based on their purpose, each of these operations will fall into one of the following contexts:
main context includes the set of operations that denote the
intended functionality of a hook. For example, members of
main set might
include operations that fetch source code, run migrations, etc.
ensure set of operations should includes those operations which are
to be run after the
main set of operations succeeds. These
operations might include tasks aimed at the tidying up of data, the deletion of
temporary files, etc.
rollback set of operations includes those tasks that should be
executed in the event a deployment process fails. The
rollback set operations
is meant to negate the effects of the
main operations and should include
tasks like rolling back a migration, reverting source code, etc.
Deployment is a structure consisting of a collection of
mix_env specification, and other information about where to build and
publish an app. By default, in order to help better organize deployment logic,
Deployment definition is broken out into multiple phases (pipelines of
hooks). Akd works via the sequential execution of these phases, along with corresponding
transformations of the
Deployment struct itself. The default set of phases
generated by Akd are:
fetch: fetch the source-code which corresponds to a release (deployed app). This can be done by using
init: initialize and configure the libraries required for the rest of the deployment process. For an Elixir app, it can be configuring
build: produce a deployable entity. It can be a binary produced by distillery or source code itself or even a docker image.
publish: publish/deploy the app to the desired destination. This can be done by
stop: stops a previously running instance of the app.
start: start a newly deployed instance of the app.
These phases are generated by Akd by default, however they are completely optional. The phases' sole purpose is to aid in addressing various common deployment use cases; thus, Akd isn't intended to force structure where it isn't needed. Akd should--and indeed, was designed to--work well for applications that require more (or less) robust deployment protocols. As such, it is very easy to define your own phases using Akd's pipeline DSL (which will be covered in more detail, in future walkthroughs). Even Akd's own base hook definitions are built upon Akd's DSL, which should allow for developers to more easily read/modify/duplicate them in ways that best suit their needs.
Taking Akd for a Spin: an example Phoenix App
For this walkthrough, we will use a simple Phoenix application,
The app runs on Elixir 1.6.4 and erlang 20.3.4. It uses Phoenix 1.3.2, with
Ecto and Postgrex. Additionally, as any ordinary Phoenix app, it is configured
npm, by default.
This Phoenix app consists of one table/schema:
products. We will be deploying
this app to a server with ip, 192.168.xx.xx.
The simplest way to run a Phoenix app is to get all the dependencies using
mix deps.get and run it using
mix phx.server. This is a great for
development mode, but the recommended way to use it in production is through a
built release; At Annkissam, our preferred way to release an Elixir application is by using
distillery. Distillery allows us to build and release an Elixir application as
an executable binary, and as such, it isn't necessary for the source code of the
application to exist on the server being deployed to. However,
distillery leaves it up to the developer to manage placing that code into their hosting environment.
The following deployment example is centered around setting
distillery to work together to deploy a Phoenix app.
Setting up the project with Akd and Distillery
One thing to point out here is that
akd generates a mix task which allows us
to deploy an application, but that mix task has to be part of an application.
The simplest thing to do is to add
akd to the app which you are deploying,
but then you would need to
akd as a dependency in all the environments as
it creates a mix task which needs to be compiled in all the environments.
I recommend creating a new app in the root folder named
whose responsibility is to just deploy the app,
<app_name>. In this way, we
don't affect the dependencies of the original app and we could also use the
<app_name>_deployer to deploy applications other than
So, let's create a new mix project in the root folder of the app
by using the command
$ mix new akd_example_deployer and add
akd as a
dependency in the
Once we run the command
$ mix deps.get from
directory, we will have access to
akd's mix tasks.
Once you run the command
$ mix akd.gen.task it will print out the usage
of the task. To keep things simple, let's use all the default hooks and run the task
$ mix akd.gen.task Deploy --with-phx. The
--with-phx flag instructs Akd to generate hooks for use with a Phoenix app. This will generate a mix task by
creating the file
The file will have a lot of autogenerated code, defaults, switches and aliases.
The task has switches for:
name: the name of the built/deployed binary (this is usually the same as the app name).
build_at: the destination where the app/node will be built/released. This is usually given in the format: user@ip:path/to/app
publish_to: the destination where the app/node will be published. This is usually given in the format: user@ip:path/to/app
env: the mix_env/distillery_env of the app being released.
vsn: the version of the app being deployed.
Here's an example usage of the generated task:
$ mix akd.deploy -n app_name -b firstname.lastname@example.org -p email@example.com -e prod -v 0.1.0
NOTE: This command must be ran from the root directory of the deployer app
But that won't work yet, as we haven't set up the task completely and it's verbose to enter the switches every time.
First, we will change the defaults. Replace the autogenerated
Next, we can give the Akd.Fetch.Git hook some parameters to clone the source code of the application. This tells Akd to fetch the source code using git, from a source (usually github) and a branch:
run_ensure flag determines whether ensure commands of a hook should be ran or not. The ensure operations of Githook include deleting the fetched code once deployed. In this case it makes sense for it to be false, so the builddestination doesn't have to fetch the code everytime it wants to deploy.
Next, we can give Akd.Build.Phoenix.Npm and Akd.Build.Phoenix.Brunch hooks their parameters to allow akd to call commands like $ npm install and brunch build:
Now, the app is ready to be deployed! Just run mix akd.deploy from the akd_example_deployer folder and make sure that you have ssh credentials to the server (192.168.xx.xx).
Distillery provides various ways in which a set of migrations can be run on a Phoenix app in this document.
For this walkthrough, we will be creating a migration module which ensures that all the Ecto apps are started and runs the migrations.
In out example app, we can create a new file in lib/akd_example/release.ex, and add the following code to it:
This will allow us to run migrations without having mix in production by using the command $ bin/akd_example command Elixir.AkdExample.Release migrate on the publish server.
Now, using Akd's generators, we'll add that command to the list of hooks in the deploy pipeline.
Generating a Custom Hook
Part of Akd's extensability comes from its transparency. Instead of defining functions and pipelines internally, akd generates them and leaves them open to modification through the use of its DSLs. In order to add a hook which runs migrations, we will cd into akd_example_deployer and use the command, $ mix akd.gen.hook MyHooks.RunMigrations. This will create a file at akd_example_deployer/lib/my_hooks/run_migrations.ex, with the following generated code:
The command to run migrations is added to the migrate_hook function. We can change the server the command will execute on by using the deployment's publish configuration.
To execute the hook, it must be added to the deployment pipeline. For this example, it is has been added as part of the :publish pipeline, after the :start hook.
So, here's our final deploy.ex file:
Now, everytime we deploy migrations will run after the app is started on the publish server.
This example was intended to highlight the basic features of Akd as well as to demonstrate its extensability. Using its generators and DSL, Akd has allowed Annkissam to more swiftly deploy our growing suite of Elixir applications.
Akd is not limited to only deploying Distillery releases. The following are a few additional use cases that Akd is equipped to handle:
- Publish Mix projects
- Package and deploy Docker containers.
- Deploy non-Elixir applications
- A tool to run tasks on a remote server.
We're hoping to publish more about these use cases in the future. We're also eager to hear how Akd has been extended to help with your workflows.
For more information on Annkissam’s Elixir deployment package, akd, click here.