Using ASDF with Elixir and Phoenix
By DevOps on Tue 26 March 2019
inFor simple deployments, we can install Erlang and Elixir from binary packages. Instead of using the packages that come with the OS, which are generally out of date, you should use the packages from Erlang Solutions.
One disadvantage of the OS packages is that we can only have one version installed at a time. If different projects have different versions, then we have a problem. Similarly, when we upgrade the Erlang or Elixir version, we should first test the code with the new version, moving a version through dev and test environments, then putting it into production. If anything goes wrong, we need to be able to roll back quickly. To support this, we need to precisely specify runtime versions and keep multiple versions installed so we can quickly switch between them.
This is mainly useful for dev and build environments. For production, use releases. Releases bundle the VM with the code, so we don't need to install Erlang on the prod machine at all. We just install the release and it includes the matching VM that we tested with.
The ASDF version manager lets us manage multiple versions of Erlang, Elixir and Node.js. It is a language-independent equivalent to tools like Ruby's RVM or rbenv.
ASDF is safe to install on your machine beside the Erlang packaged with your OS. It won't conflict with anything else, that's its whole reason for existing. You can, however, also use it to install a default global version.
It uses the .tool-versions
file in your project to automatically set the
path to use specific versions. The file looks like this:
erlang 21.3
elixir 1.8.1
nodejs 10.15.3
The asdf install
command reads the file and installs the necessary versions
on your system if necessary.
Install ASDF
These instructions assume that you are running macOS on your dev machine and Linux on your prod machine.
This script automates the process of installing ASDF on macOS. Following are step by step commands with explanation.
First, get the ASDF code:
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.7.1
Add commands to your shell startup scripts:
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bash_profile
echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bash_profile
The above commands installed from git to be more consistent with the Linux side.
You can also install via Homebrew:
brew install asdf
echo -e '\n. $(brew --prefix asdf)/asdf.sh' >> ~/.bash_profile
echo -e '\n. $(brew --prefix asdf)/etc/bash_completion.d/asdf.bash' >> ~/.bash_profile
After installing ASDF, log out of your shell and log back in to activate the scripts.
See the ASDF docs for more details.
Next, install the ASDF plugins for Elixir and Phoenix:
asdf plugin-add erlang
asdf plugin-add elixir
asdf plugin-add nodejs
Install build dependencies
ASDF builds Erlang from source, so it needs to have some build tools and libraries installed. Other packages like Node.js have dependencies as well.
On macOS, first install Homebrew, then run:
# Install common ASDF plugin deps
brew install coreutils automake autoconf openssl libyaml readline libxslt libtool
# Install Erlang plugin deps
brew install unixodbc wxmac
# Install Java. It's optional, but installing it avoids popup prompts.
# If you already have Java installed, you don't need to do this
brew cask install java
# Install Node.js plugin deps
brew install gpg
# Import node gpg keys
# This can be flaky, as it depends on network connections to the GPG key servers
# You may need to run it multiple times
bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring
See the ASDF Erlang docs for more options.
Install tools
Use ASDF to install the versions of Erlang, Elixir and Node.js specified
in the .tool-versions
file:
asdf install
You might need to run this twice.
Install Elixir libraries into the ASDF dir for the specific Elixir version you are running:
mix local.hex --if-missing --force
mix local.rebar --if-missing --force
# Install the Phoenix archive (optional), so that you can run e.g. `mix phx.new`
# mix archive.install hex phx_new 1.4.2
Confirm that it works by building the app the normal way:
mix deps.get
mix deps.compile
mix compile
You should be able to run the app locally with:
mix ecto.create
# Webpack (the new hotness)
(cd assets && npm install && node node_modules/webpack/bin/webpack.js --mode development)
# Brunch (old and busted)
(cd assets && npm install && node node_modules/brunch/bin/brunch build)
iex -S mix phx.server
open http://localhost:4000/
Install ASDF on Linux
Following are scripts to install ASDF in a build/CI environment:
Install on Ubuntu 18.04
First, set up the base system and utils:
echo "==> Initialize package manager and install basic utilities"
export DEBIAN_FRONTEND=noninteractive
echo "===> Updating package repos"
apt-get update -qq
echo "===> Installing locale $LANG"
LANG=C apt-get -qq install locales
locale-gen "$LANG"
echo "===> Updating system packages"
apt-get -qq upgrade
echo "===> Installing apt deps"
apt-get -qq install dialog apt-utils
echo "===> Installing utilities"
apt-get -qq install wget curl unzip make git
Next, install build deps:
echo "==> Install ASDF plugin dependencies"
echo "===> Installing ASDF common plugin deps"
apt-get -qq install automake autoconf libreadline-dev libncurses-dev libssl-dev \
libyaml-dev libxslt-dev libffi-dev libtool unixodbc-dev
echo "===> Installing ASDF Erlang plugin deps"
apt-get -qq install build-essential libncurses5-dev libwxgtk3.0-dev libgl1-mesa-dev \
libglu1-mesa-dev libpng-dev libssh-dev unixodbc-dev xsltproc fop
echo "===> Installing ASDF Node.js plugin deps"
apt-get -qq install dirmngr gpg
Install on CentOS 7
First, set up the base system repo and utils:
echo "==> Initialize package manager and install basic utilities"
echo "===> Installing EPEL repository"
wget --no-verbose -P /tmp https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum install -q -y /tmp/epel-release-latest-7.noarch.rpm
echo "===> Updating package repos"
yum update -y -q
echo "===> Updating system packages"
yum upgrade -y -q --enablerepo=epel
echo "===> Installing utilities"
yum install -y -q wget curl unzip make git
Next, install build deps:
echo "==> Install ASDF plugin dependencies"
echo "===> Installing common ASDF plugin deps"
yum install -y -q automake autoconf readline-devel ncurses-devel openssl-devel \
libyaml-devel libxslt-devel libffi-devel libtool unixODBC-devel
echo "===> Installing ASDF Erlang plugin deps"
groupinstall -y 'Development Tools' 'C Development Tools and Libraries'
yum install -y -q wxGTK3-devel wxBase3 openssl-devel libxslt \
java-1.8.0-openjdk-devel libiodbc unixODBC erlang-odbc
echo "===> Installing ASDF Node.js plugin deps"
yum install -y -q install gpg perl perl-Digest-SHA
Install ASDF
Finally, install ASDF, same for Ubuntu and CentOS:
echo "==> Install ASDF and plugins"
if [ ! -d "$HOME/.asdf" ]; then
echo "===> Installing ASDF"
git clone https://github.com/asdf-vm/asdf.git "$HOME/.asdf" --branch v0.7.1
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc
echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bashrc
fi
source "$HOME/.asdf/asdf.sh"
if [ ! -d "$ASDF_DIR/plugins/erlang" ]; then
echo "===> Installing ASDF erlang plugin"
asdf plugin-add erlang
fi
if [ ! -d "$ASDF_DIR/plugins/elixir" ]; then
echo "===> Installing ASDF elixir plugin"
asdf plugin-add elixir
fi
if [ ! -d "$ASDF_DIR/plugins/nodejs" ]; then
echo "===> Installing ASDF nodejs plugin"
asdf plugin-add nodejs
echo "===> Importing Node.js release team OpenPGP keys to main keyring"
# This can be flaky
bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring
fi
Install build deps
Finally, install Erlang, Elixir, etc. You would generally put it in the "build" phase
of your scripts so the .tool-versions
file in git controls the versions.
echo "===> Installing build deps with ASDF"
asdf install
# Run it again to make sure all the plugins ran, as there have been issues with return codes in the past
asdf install