DEV Community

Cover image for Using Docker for your Elixir Phoenix application
Jamie Neubert Pedersen
Jamie Neubert Pedersen

Posted on

Using Docker for your Elixir Phoenix application

A nifty way to setup an Elixir development environment is to use Docker instead of using asdf or installing the Elixir toolchain locally.

Docker has the option to mount a directory into the container which we can exploit to mount whatever folder we are currently in by using the unix command pwd (print working directory).

We can also instruct Docker to expose a port and remove the container once it is stopped. Putting these things together we can get a Elixir environment entirely contained in Docker. The base of the command would be this in bash:

docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir:latest
Enter fullscreen mode Exit fullscreen mode

From this point we can extend it to do whatever we want with Elixir, such as running mix commands.
Although we have to create a Docker image that has these tools contained. Here is an example of a Docker image that you can build with docker build -t elixir-env . in the directory of the Dockerfile:

# Extend from the official Elixir image
FROM elixir:latest

RUN mix local.hex --force \
    && mix archive.install --force hex phx_new \
    && apt-get update \
    && curl -sL https://deb.nodesource.com/setup_lts.x | bash \
    && apt-get install -y apt-utils \
    && apt-get install -y nodejs \
    && apt-get install -y build-essential \
    && apt-get install -y inotify-tools \
    && mix local.rebar --force

ENV APP_HOME /app
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

EXPOSE 4000

CMD ["mix", "phx.server"]
Enter fullscreen mode Exit fullscreen mode

After creating the image and tagging it with elixir-env we can create a Phoenix application by running that container in bash:

docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir-env:latest mix phx.server
Enter fullscreen mode Exit fullscreen mode

But where this becomes really interesting is when you alias it to a function in your shell.
Doing that will give you the base CLI tool and make it just as accessible as having it installed locally.
To alias the function you simply do:

alias mix="docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir:latest mix"
Enter fullscreen mode Exit fullscreen mode

From here we can simply use mix to run any further invocations of that container. Thus we can replace it with the local installation and be oblivious to it running through Docker.

This technique is quite powerful for testing out environments or if you can't get a specific program to run locally on your machine because of conflicting dependencies. Creating a program running in Docker saves you from dealing with global dependencies and allows you the flexibility of a clean installation.

Top comments (4)

Collapse
 
zacky1972 profile image
Susumu Yamazaki

Hi,

I tested it on Docker for Mac 4.3.1 and M1 Mac according to this post.
I created a phoenix project and did mix deps.get as follows after docker build -t elixir-env .:

docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir-env:latest mix phx.new --no-ecto test
cd test
docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir-env:latest mix deps.get
Enter fullscreen mode Exit fullscreen mode

Then, I launched a pax-server as follows:

docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir-env:latest mix phx.server
Enter fullscreen mode Exit fullscreen mode

Though I viewed http://localhost:4000 by a web browser on the host, I can't connect the phx.server.

What wrong?

Collapse
 
eikooc profile image
Jamie Neubert Pedersen

Hi Susumu ( @zacky1972 ). Thanks for your question.
It seems like if you want to generate a new phoenix project you are asked if you want to install dependencies. Docker exits abruptly on that question without adding -it to the run command. Can I get you to try your above example again, but instead do:

docker run -it --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir-env:latest mix phx.new --no-ecto test
cd test
Enter fullscreen mode Exit fullscreen mode

This should allow you to install the dependencies interactively.

But the actual issue is a change that happened to the config/dev.exs file, only allowing access from the same computer. Just change the http in that file to allow access from 0.0.0.0 like so:

# from this:
http: [ip: {127, 0, 0, 1}, port: 4000],
# to this:
http: [ip: {0, 0, 0, 0}, port: 4000],
Enter fullscreen mode Exit fullscreen mode

Then launch the phoenix server again with:

docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir-env:latest mix phx.server
Enter fullscreen mode Exit fullscreen mode

Btw, I liked your talks at Elixir Conf.

Collapse
 
zacky1972 profile image
Susumu Yamazaki

I did it according to your answer and it was done! Thank you so much.

And also, thank you for watching and listening to my talk!

Collapse
 
ottokar profile image
ottokar • Edited

Hi Jamie,
thanks for your tutorial. Unfortunately i just stumble on the second step. After building/tagging the image i got this error msg when i try to run a the command:

docker run --mount type=bind,source=$(pwd),target=/app -p 4000:4000 --rm elixir-env:latest mix phx.server
** (Mix) The task "phx.server" could not be found
Note no mix.exs was found in the current directory

BTW, I'm on macos big sour 11.6.8