Setting up a Phoenix 1.3.4 Project With Docker

Alex Kleissner
4 min readAug 17, 2018

--

All that open sky is your computer’s hard drive without 1000 versions of different languages installed on it.

As a follow up to my original post, I wanted to create a cleaner system for getting phoenix projects up and running.

We’ll set up a container that’s running Phoenix 1.3.4 with Elixir 1.6. It’ll be backed by a postgres database. We’ll do all of this without installing anything on our local machine.

Create a new directory for your project, we’ll call this phoenix-api for now.

$ mkdir ~/projects/phoenix-api

Dockerfile

We’ll go ahead and set up a Dockerfile to build a container, which we can then use to run the commands we'll need to initialize the Phoenix project.

FROM elixir:1.6
MAINTAINER you@gmail.com
ENV HOME=/usr/src/phoenix-apiRUN apt-get update && apt-get upgrade -y && \
apt-get install -y inotify-tools build-essential postgresql-client && \
mix local.rebar --force && \
mix local.hex --force
# Uncomment if you need to use a front-end
#RUN apt-get install -y sudo wget curl zip unzip
# If you plan to run a web interface, you'll want to use the following:
#RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash - && apt-get install -y nodejs
ADD . $HOMEWORKDIR $HOME
EXPOSE 4000

With this done, we can run docker build -t phoenix-api:latest . and get a container for this Dockerfile with the phoenix-api:latest tag.

Compose That API

Next up, we’ll set up our bare bones compose file.

We have two containers that we need, our api server and our database.

Lets create our docker-compose.yml file:

version: '3'services:
api:
build: .
ports:
- "4000:4000"
volumes:
- .:/usr/src/phoenix-api
depends_on:
- db
db:
image: "postgres:9.6.3"
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:

We can now run a compose build with

docker-compose build

Once that builds, we need to get a bash prompt on the container with

docker-compose run --rm api bash

The --rm makes sure that we dispose of our container when we're done, since we don't need it to stick around. We just want to create a new project and then drop it.

With a bash prompt, we can install the phx_new mix task.

mix archive.install --force https://github.com/phoenixframework/archives/raw/master/phx_new.ez
mix phx.new --no-brunch --no-html --app phoenix_api ../phoenix-api

This will then ask you if you are sure since the phoenix-api folder already exists. Say Yes to that and for installing dependencies. I'm sure some people will complain that this circumvents the whole umbrella project thing, but I find that this is what I want most of the time for my own projects. Using the relative directory and having it bound to your local dir prevents the nesting from happening.

Once all that finishes, let’s get our dependencies installed and then exit out of the container.

mix deps.get
... lots of stuff here ...
exit

Setting up the Database

We’ll have to tell Phoenix where our dockerized database lives, so boot up your favorite editor for config/dev.ex.

Find the part that looks like this and change the hostname field to use the name of the db container.

# Configure your database
config :phoenix_aptlist, PhoenixAptlist.Repo,
adapter: Ecto.Adapters.Postgres,
username: "postgres",
password: "postgres",
database: "phoenix_api_dev",
hostname: "db",
port: 5432,
pool_size: 10

To now create the table, lets run docker-compose run --rm api mix ecto.create. Since the api container depends on the db container, that will start up before the api container spins up.

Setting up the Entryfile

Next up, we’ll want to modify our Dockerfile to add an entry file that will boot up our Phoenix service when the container starts.

Open up the Dockerfile and edit the bottom part to look like this:

RUN apt-get update && ...COPY ./docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
ADD . $HOME

The docker-entrypoint.sh is what we care about. But... what does that look like?

Probably something like this (NOTE: you have to have your database container name in the -h flag for this to work properly):

#!/bin/bash# fail if we error out
set -e
# Wait for database to come up
until psql -h db -U "postgres" -c '\q' 2>/dev/null; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
# Ensure we have the basics...
mix local.hex --force
mix local.rebar --force
mix phx.server

We need to allow our entrypoint to be executable:

chmod +x docker-entrypoint.sh

Putting it all Together

Build and run the containers:

docker-compose build
docker-compose up -d

We can see when the server is ready by following the logs:

docker-compose logs -tf api

Once everything is running, you can see an error page at http://localhost:4000. Now you just have to add some API routes.

Congrats on getting a Phoenix project started without installing any Elixir on your computer!

--

--