Setting up a Phoenix 1.3.4 Project With Docker
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.comENV 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 nodejsADD . $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/datavolumes:
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 Y
es 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 --forcemix 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!