Install & Deploy Phoenix Apps on Centos7 or RHEL with edeliver

The original gist can be found here

Sometimes you find yourself with a set of requirements that lead in a direction that take you out of your comfort zone. Recently I was tasked with setting up deployment for a Phoenix app on a RHEL server that I wouldn’t be able to directly access for security/compliance reasons. Normally I would use Docker in a situation like this and pass off the credentials and a working Dockerfile, but the ops team on the other end “doesn’t do Docker”. Remembering that Erlang/OTP releases are a great feature of the ecosystem, I decided it was time to learn how to use edeliver, and Distillery.

What follows is adapted slightly from a set of instructions I sent to the ops people responsible for deploying this particular Phoenix app. As such, the formatting and typesetting (can you call it that on the web?) is not great. The instructions are presented mostly as is, and without a lot of explanation. If you’re following along, feel free to email me, or check out the Elixir Forum thread where I was first stumbling through this. Also, if you find any mistakes, let me know so I can fix this post.

Set the environment variables

Install nano(or not if you intend to use vi)

  yum install -y nano

Open ~/.profile with nano ~/.profile and add the following:

  export ERLANG_VERSION="19.1.5"
  export ELIXIR_VERSION="1.4.0"
  export PHOENIX_VERSION="1.2.1"
  export LANG="en_US.UTF-8"
  export LANGUAGE="en_US.en"
  export LC_ALL="en_US.UTF-8"
  export PORT=4000
  export HOSTNAME="YOUR HOSTNAME HERE"
  export GUARDIAN_SECRET="ADD A SECRET FOR GUARDIAN IF YOU USE IT"

This is a good time to set up you ENV vars in general.

Use cmd-shift-o to save and cmd-shift-x to quit nano.

Run source ~/.profile and check env to make sure everything is set.

Begin installing required packages

  yum -y install --setopt=tsflags=nodocs epel-release wget unzip uuid less bzip2 git-core inotify-tools gcc

Install Erlang

  yum -y install https://packages.erlang-solutions.com/erlang/esl-erlang/FLAVOUR_1_general/esl-erlang_${ERLANG_VERSION}~centos~7_amd64.rpm && \
  yum -y install esl-erlang-${ERLANG_VERSION} && \
  yum -y update && \
  yum -y reinstall glibc-common glibc

Install Nodejs and Yarn

  curl --silent --location https://rpm.nodesource.com/setup_7.x | bash -
  wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
  yum -y install nodejs
  yum clean all
  yum install yarn

Download and Install Elixir

  cd /tmp && \
  wget https://github.com/elixir-lang/elixir/releases/download/v${ELIXIR_VERSION}/Precompiled.zip && \
  unzip -d /usr/local/elixir -x Precompiled.zip && \
  rm -f /tmp/Precompiled.zip

Set Elixir on the path Open ~/.bashrc with nano ~/.bashrc and add the following:

  export PATH="$PATH:/usr/local/elixir/bin"

Then reload the profile with source ~/.profile.

Test the install by running iex.

If it works enter ctrl-c twice to exit.

Install Hex and Phoenix

Run the following:

  yes | mix local.hex
  yes | mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new-$PHOENIX_VERSION.ez

Exit the ssh session Enter ctrl-d to return to you system’s terminal.

Clone the Repo

In you desired directory run:

  git clone [email protected]:YOUR_REPO/YOUR_APP.git

If necessary also install Elixir, Erlang, and Phoenix locally following these instructions.

Get and compile the dependencies

  mix deps.get

Check the edeliver config

Make sure edeliver is configured correctly.

  open .deliver/config

Check the following:

  BUILD_HOST="server ip address goes here"
  BUILD_USER="server user name for deployment goes here"

If they have are not correct, set them to the values for the desired server.

Generate a new secret key

Run mix phoenix.gen.secret and copy the output for the next step.

SSH back into the server

Create a production secrets file at /home/$BUILD_USER/build_files/prod.secret.exs

$BUILD_USER is the server’s deployment user.

The file should contain the following

  use Mix.Config

  config :your_app, YourApp.Endpoint,
    secret_key_base: "THE PRODUCTION KEY FROM THE PREVIOUS STEP GOES HERE"

  # Configure your database
  config :your_app, YourApp.Repo,
    adapter: Ecto.Adapters.Postgres,
    username: "DATABASE USERNAME",
    password: "DATABASE PASSWORD",
    database: "your_app_prod",
    hostname: "DATABASE HOST ADDRESS?NAME,
    port: "5432",
    pool_size: 20

Exit the server

  exit

Build the First Release

Run the following:

  mix edeliver build release [--revision=<git-revision>|--tag=<git-tag>] [--branch=<git-branch>]

In my case for staging I run:

  mix edeliver build release --branch=develop --verbose

Use --branch=develop to deploy staging, master is the default.

Visit the edeliver github to view issues and the docs.

I also use a script called deploy for this which looks like:

  #!/bin/bash -ex
  BRANCH=${1:-develop}; #arg 1 or develop
  ENV=${2:-staging}; #arg2 or staging

  mix edeliver build release --branch=$BRANCH --verbose
  mix edeliver deploy release to $ENV --verbose
  mix edeliver start $ENV
  mix edeliver migrate $ENV up --verbose
  mix edeliver ping $ENV

It can take one, two, or no arguments. Make sure to runchmod +x deploy so you can run it.

  ./deploy # this defaults to the branch develop and the env of staging
  ./deploy master production # will deploy master to production

Deploy Your App!

Run the following:

  ./deploy

The last result should look like:

  EDELIVER BEACON WITH PING COMMAND

  -----> pinging staging servers

  staging node:

    user    : YOUR_USER
    host    : YOUR HOST
    path    : YOUR DEPLOY PATH
    response: pong

  PING DONE!

If it does, you’re all set! Otherwise, head over to the Elixir Forum thread mentioned at the beginning, and hit us with a question.


If you enjoyed this post, follow me on twitter @ChaseGilliam, sometimes I'm funny. You can also find me on Github.