I had some thoughts about deploying Elixir and decided to start putting them together. I like to start off small and see what grows. So there's a tiny sample plug app in lib, the content is in the docs directory, and the sample Dockerfiles are in docker.
I do tend to be a bit opinionated but I'm constantly looking for better ideas, so if there's something that you don't like or think could be better, please open an issue and create a pull request.
Disclaimer: this isn't intended to be a complete copy/paste deployment solution. It's a set of concepts and ideas that you can implement as needed.
Here's the overview of the process:
- Build our app using Distillery to create our release
- The build is going to happen inside a Docker container
- Deploy to a Docker container or VPS/Bare Metal Host
If you're coming from a language like Ruby or Node there are a few differences in deploying an Elixir application. Each of these can cause problems on their own but are easy to work around.
- there's going to be a compile phase (and possibly asset building too),
- that compile/build is going to output an Erlang deployable, and
- the build environment (OS and version) must match the deployment/production environment (OS and version).
I don't cover installing Docker or setting up Distillery, there's a lot of good documentation there already.
[Note: Item #3 is probably going to cause some of you some heartburn because it's not absolutely 100% true. While there are some exceptions, treat it like it's completely true and your life will be much easier. The errors that happen because of mismatches can be rather obtuse and return very few Google hits. Keep things simple, match the build and deploy environments, once that's mastered if there's a requirement outside that scope evaluate it then.]
There are many different ways to build and deploy an Elixir app, many. In fact, there's a whole page of other resources with information on some of those ways. My biases are going to come out, so let me state a few right up front:
- While I've taken an incremental approach here, the goal is to completely automate the whole thing with a CI process,
- To get to a CI process you need to separate you dev environment from your build/test/production environments
- Having spent a few years in the computer security world, I'm not a fan of installing build tools in production environments, so our process will be to install the build tools only in the build environment and deploy prebuilt binaries and assets to production
- This means a separation of dev from build and build from production
- Containers give us a direct way to match our build environment to our production one
Part 1: A Good Begining Part 2: Build it Faster Part 3: Comments and Q&A
See the page of resources
While writing this I came across Elixir Docker Image Builder and Github - PagerDuty/docker_distiller. There's lots of overlapping concepts between what I've done and their build steps. Effectively, I've explained the process a bit and they've automated it. They are a bit opinionated and targeted at creating the smallest runtime docker image possible.
Releasing Elixir/OTP applications to the World Does an excellent job explaining the problem in detail. Lessons from Building a Node App in Docker Github - Bitwalker's Phoenix Dockerfile