DEV Community

Noel Worden
Noel Worden

Posted on • Edited on

Elixir/Phoenix Project: Dockerizing

Goals:

  • Dockerize project
  • Update README with new instructions on launching app with Docker

Dockerize project

Although this is implied with all of my writing, it's especially true with Docker, so it bears to be said explicitly: I am by no means a Docker expert. What I will be talking about in this post are the steps I took to get my project running in Docker from online resources and my past experience. If there is any aspect of what I'm about to talk about that could be improved, I would greatly appreciate any feedback. With that caveat out of the way, here is what I did to build my app in Docker images.

Actually, before I dive into the files, here's a quick refresher on whats what in the world of Docker:

  • A Dockerfile builds an image
  • A container is started from that image
  • docker-compose.yml defines which containers (aka services) make up a complete app

The first step was to create a Dockerfile, which is a file of specifications that Docker uses to build an image. For my Dockerfile I used an image from Docker Hub that I have used in the past, alpine-elixir-phoenix. I have been happy with it, and I'm also familiar with how to setup a Dockerfile with it. I used the image docs as a starting point for my Dockerfile but ended up simplifying it a bit for my needs:

Heres the breakdown of the file:

This is declaring which version of elixir will be used.

This is executing the RUN command to create a new directory ,/app. Then WORKDIR is setting that newly created folder as the working directory.

This is executing the COPY command to move the mix.exs and mix.lock files from the local directory into the image directory, then using RUN to execute a mix command in the image directory.

Similar to the previous command, this is executing COPY to move the necessary assets from the local directory to the image, then RUN to execute an npm install --prefix into the folder on the image.

This copies the rest of the files and folders from the root of the local directory to the root of the image.

Lastly, an execution of CMD to start the server

With the Dockerfile complete, the next step was to create a docker-compose.yml file. Like I said earlier, this file defines the containers that will make up the complete app. There's a good amount of content, so I'll utilize comments in the example code to explain what is what, instead of listing everything out individually:

One last thing that I needed to do before taking this for a test run was to change to the dev.exs file. This change was not on any of the tutorials I used, and it caused me enough trouble that when I found the solution I actually wrote up a standalone post about it. The change is pretty painless, the hostname field of the Repo config needs to be updated from localhost to db to match the name of the container running the database:

With the two docker files created, the update to dev.exs, and Docker for Mac installed an running on my machine, the app is up and running with three commands (I recommend executing in two tabs of the terminal):

  • Terminal Tab 1
    • docker-compose build
    • docker-compose up

Once its spun up, the db container shows the following error:

Although the db container is up and running, the app is looking for the database that is declared in dev.exs, in this case atlas_dev. The third command will take care of this:

  • Terminal Tab 2
    • docker-compose exec web mix ecto.setup

That command uses exec web to execute the mix command in the currently running web container. The ecto.setup command is from the mix.exs file, and runs a list of commands:

Although I don't have any migrations or seeds at the moment, I still use that command, it's mostly a muscle memory thing at this point.

With that command executed in a second tab, the logs in the first tab no longer display an error, and everything is ready to go. The app can now be viewed at localhost:4000. Of course, since I have yet to actually code anything in this new app, it's still the generic Phoenix startup page, but that will change soon.

Update README with new instructions on launching app with Docker

With the project Dockerized, I also updated the README with new instructions on how to spin up the app:


Spinning up project with Docker

  • Install Docker for Mac
  • In one terminal tab:
    • docker-compose build
    • docker-compose up
  • In a second tab, once the two commands in the first tab are completed:
    • docker-compose exec web mix ecto.setup
  • If everything spins up with no errors, site will be live at localhost:4000

It's essentially the steps from above, but I believe that keeping docs updated is important, so it's worth noting as part of my process

Bonus - Ignoring files for a faster Docker build

A file can be created that is similar to what .gitignore does for git, but for Docker. This file is .dockerignore and Docker looks for this file before each build to see if there are files that can be skipped in the execution of the build. Skipping files creates a smaller image and therefore a faster build. I pulled the contents of my .dockerignore from the Distillery hexdocs:

Adding this file was one of my last steps in the process, and I kind of regret that, as the build is noticeably faster with Docker ignoring these files. Adding this earlier in the process would have saved me a lot of time while experimenting with the proper Dockerfile and docker-compose.yml configurations.

Closing thoughts

Docker will be the last devops aspect I am going to setup. I am ready to do some feature coding and get that default Phoenix splash page out of there. But, I am very happy that I have taken the time to set my project up with these tools and make the process as streamlined as possible right out of the gate. From here on out I can basically just concern myself with features and whatever random thing I want to try, and all the checks I have in place will keep my code tidy and easy to deploy.

This is my repo at the end of this block of work.

References


This post is part of an ongoing series. I encourage any critique, feedback, or suggestions in the comments.

Top comments (0)