Using Docker for your next Rails project

In this post I will be explaining how to create a new rails project, set up with Docker, for local development. A lot has been written about Docker already. In this post I wont be addressing what Docker is or how to deploy it. I will be focusing on using it for development purposes.

The benefits of using Docker for development

One of the worst things about picking up an existing project is getting the app set up on your local machine. Another common problem for web developers is reproducing a bug on their system but being unable to reproduce it on another developers machine. Docker fixes these problems. When a project has been built using Docker, new developers only needs to run docker build and they will have a container with the app installed along with all of it’s dependencies. If you reproduce a bug, you can share your docker image with others, giving them access to the exact same container.

Starting a new Rails app with Docker

Now on to the main topic of this blog post. You’re sold on the benefits of Docker. You’re creating a new Rails project and you want to use Docker for local development.

1. Install Docker

First, you need to install Docker. You can download it using one of the easy installers, found on docker.com

2. Create a Dockerfile

Next, you’ll need to create a Dockerfile. Here is an example Dockerfile that will get you started on a vanilla Rails app:

# The version of ruby that you want to use for your project
FROM ruby:2.3.1

# The name of the maintainer (not required)
MAINTAINER tomkadwill@gmail.com

# Install apt package manager and update it
# Then install nodejs as it is required for Rails 5
RUN apt-get update && apt-get install -y \
  nodejs

# Configure the main working directory. This is the base
# directory used in any further RUN, COPY, and ENTRYPOINT
# commands.
RUN mkdir -p /app
WORKDIR /app

# Copy the Gemfile as well as the Gemfile.lock and install
# the RubyGems. This is a separate step so the dependencies
# will be cached unless changes to one of those two files
# are made.
COPY Gemfile Gemfile.lock ./
RUN gem install bundler
RUN bundle install

# Copy the main application.
COPY . ./

# Expose port 3000 to the Docker host, so we can access it
# from the outside.
EXPOSE 3000

# The main command to run when the container starts. Also
# tell the Rails dev server to bind to all interfaces by
# default.
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]

This file should be placed in the root directory of your rails project. I’ve tried to provide a useful comment for each line of the Dockerfile. The commands used here are pretty standard so you can google anything that you don’t understand.

3. Build a Docker image

Now that you have Docker installed and you have a Dockerfile you can build it by running:

$ docker build .

This will build a new Docker image. When run, this image will build a Docker container.

4. Run a Docker container

Lastly, you can run your Docker container. To run the container, take the SHA that is returned at the end of docker build . and use that with the docker run command. It should look something like this:

$ docker run -p 127.0.0.1:3000:3000 c23a30d9cb25

As well as docker run I’m also mapping port 3000 on the container to port 3000 on my local machine. This will allow me to access the app in the browser on my machine.

Now you have a fresh install of Rails running inside a Docker container! If you want to get access to the box you can run docker exec with your container id. You can get the container id by runner docker ps:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
fd28739817b0        c23a30d9cb25        "bundle exec rails se"   6 seconds ago       Up 3 seconds        127.0.0.1:3000->3000/tcp   goofy_spence
$ docker exec -i -t fd28739817b0 /bin/bash

This is useful if you want to look at log files or browse the filesystem of a container.

5. Mounting your local file system

Lastly, you’ll probably want to mount your local file system, for development. Otherwise you’ll have to re-build every time you make a code change. Below I’ve modified the docker run command to include -v. This option allows you to map a local directory to a directory in your container.

$ docker run -v ~/Workspace/example/blog:/app -p 127.0.0.1:3000:3000 c23a30d9cb25

Now you’re done! You have a new Rails project running in a docker container, ready for local development.