Setting up a Docker dev environment for Elixir+Phoenix

Benefits

  • One-line setup and bootup: docker-compose up. It creates the database, does the Dialyzer pre-work (if the project has Dialyxer installed), etc.
  • A true development-oriented config: Source code is mounted so that changes in the container appear on the host, and vice-versa.
  • Fast re-builds because the DOCKERFILE is written to help Docker cache the images.
  • Syncing with the Postgres startup delay.
  • All the crappy little dependencies installed.
  • No weird hacks.

Now the three files, followed by instructions and my comments (or jump straight to the GitHub Repo):

version: '3.2'
services:
db:
image: postgres
web:
build: .
volumes:
- type: bind
source: .
target: /app
ports:
- "4000:4000"
depends_on:
- db
command:
- ./run.sh
view raw docker-compose.yml hosted with ❤ by GitHub
# Elixir + Phoenix
FROM elixir:1.6.1
# Install debian packages
RUN apt-get update
RUN apt-get install --yes build-essential inotify-tools postgresql-client
# Install Phoenix packages
RUN mix local.hex --force
RUN mix local.rebar --force
RUN mix archive.install --force https://github.com/phoenixframework/archives/raw/master/phx_new.ez
# Install node
RUN curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh
RUN bash nodesource_setup.sh
RUN apt-get install nodejs
WORKDIR /app
EXPOSE 4000
view raw Dockerfile hosted with ❤ by GitHub
#!/bin/sh
# Adapted from Alex Kleissner's post, Running a Phoenix 1.3 project with docker-compose
# https://medium.com/@hex337/running-a-phoenix-1-3-project-with-docker-compose-d82ab55e43cf
set -e
# Ensure the app's dependencies are installed
mix deps.get
# Prepare Dialyzer if the project has Dialyxer set up
if mix help dialyzer >/dev/null 2>&1
then
echo "\nFound Dialyxer: Setting up PLT..."
mix do deps.compile, dialyzer --plt
else
echo "\nNo Dialyxer config: Skipping setup..."
fi
# Install JS libraries
echo "\nInstalling JS..."
cd assets && npm install
cd ..
# Wait for Postgres to become available.
until psql -h db -U "postgres" -c '\q' 2>/dev/null; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
echo "\nPostgres is available: continuing with database setup..."
# Potentially Set up the database
mix ecto.create
mix ecto.migrate
echo "\nTesting the installation..."
# "Proove" that install was successful by running the tests
mix test
echo "\n Launching Phoenix web server..."
# Start the phoenix web server
mix phx.server
view raw run.sh hosted with ❤ by GitHub

How to Dockerize a Phoenix app

  1. Copy the three config files to the root folder of an existing Phoenix project. Make run.sh executable, e.g.: chmod +x run.sh.
  2. Edit your development database settings to connect to Postgres at host db, username postgres, password is an empty string.
  3. Spin it up with docker-compose up.

The Phoenix app should be up and running at http://localhost:4000. Something like this:

Screen Shot 2018-02-02 at 2.01.43 AM

Now a little about this configuration

It’s the result of several hours spent fine-tuning it and going through the Docker file references. I wanted a “online-liner” container-based dev environment. To get this, I started with a Rails Docker config and got a boost from this excellent post by Alex Kleissner. He had the nice idea of a run.sh script to do some things like synchronize Phoenix and Postgres.

Also available as a GitHub repo. I have a very similar config for my Rails work as well.