I’ve been looking at job postings, and saw that Elixir has picked up a fair bit of traction. It’s not hard to see why, syntax similar to Ruby, functional constructs like Scala, and running on top of the Erlang VM… sounds like a whole lot of winning in the rush to do more with APIs and use fewer resources.
Given the prevalence of docker for development environments, and the prospect of not having to locally install any of the Elixir/Erlang cruft on my local machine, I set out to do a small project using Phoenix 1.3 in Docker. A lot of the information I found online dealt with Phoenix 1.2 or older. Hopefully this will help others save 15–90 minues of head scratching if they followed a different tutorial.
Setting up the initial Dockerfile.
We will be going with the following software versions:
- Elixir 1.5
- Phoenix 1.3
- PostgreSQL 9.6.3
Go to your base project directory, and fire up your editor of choice. We’ll be creating a Dockerfile that looks like this:
MAINTAINER YOUR_NAME_HERERUN apt-get update && apt-get install --yes postgresql-clientADD . /appRUN mix local.hex --force
RUN mix archive.install --force https://github.com/phoenixframework/archives/raw/master/phx_new.ezWORKDIR /app
There are a few important things in this. First, we’re adding the postgresql client, which will allow Phoenix to nicely talk to the database. The second, is the bit after the
local.hex mix call, which installs the Phoenix commands on the container. The last bit, is a little weird, instead of running
CMD ["mix", "phx.server"] as our entry command, we’re instead going to run a bash file to bring up the server. I’ll explain why, after we’ve created our new Phoenix project. Before we run this, let’s set up our docker-compose file so that we can get used to running commands through that.
Setting up your docker-compose file:
We know that we’ll want a database running that the Phoenix project can talk to, so we set up a simple
docker-compose.yml file. Boot up that editor of yours and create the following file:
- db db:
This sets up two services,
db. Web is our Phoenix application, and db is… well our database. Now that we have that squared away, lets initialize our Phoenix application.
Setting up your Phoenix project:
From your project directory, run a command to initalize the project:
$ docker-compose run --rm web mix phx.new --no-brunch --no-html YOUR_PROJECT_NAME
Let’s connect the database through the config, set up our
run.sh file and boot up the project. In your editor, open up
config/dev.exs. Find the database configuration part, and modify it to look something like this:
# Configure your database
config :phoenix_aptlist, PhoenixAptlist.Repo,
The hostname needs to match the “name” of the service we defined in the
docker-compose.yml file, in this case,
Putting it all together:
run.sh command that we’re using instead of just running the server directly? The main reason for that is our postgres instance. When postgres boots up, it does a fast shutdown and then reboots again with the non-root user. I tried to get around this using the
heartbeat functionality in docker-compose, but never had success with it. For now, the annoying workaround is adding a sleep before we boot up the server. Create the
run.sh file, looking something like this:
# With help from https://dogsnog.blog/2018/02/02/a-docker-based-development-environment-for-elixirphoenix/set -e# Wait for Postgres to become available.
until psql -h db -U "postgres" -c '\q' 2>/dev/null; do
>&2 echo "Postgres is unavailable - sleeping"
Make sure that you add executable properties to your run.sh file.
chmod +x run.sh
Now, we can boot up all of our services with:
You should see a bunch of output that initializes the database and runs migrations (which we shouldn’t have any). Your Phoenix server should now accept connections. If you ended up doing a basic server with no html, you can test if it’s up by going to the root page http://localhost:4000 and you should see something about a route not existing.
Congrats! Now it’s time to build out your API or application.