Using ASDF with Elixir and Phoenix
By DevOps on Tue 26 March 2019in
For 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.
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
asdf install command reads the file and installs the necessary versions
on your system if necessary.
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.
Use ASDF to install the versions of Erlang, Elixir and Node.js specified
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
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