Docker is a great tool to develop and manage your Ruby on Rails applications locally. It allows you to easily isolate your ruby environment, database and other services like cronjob etc. Where as docker-compose file brings together different services to be used by each other. In this guide we’re going to cover:

Creating a new Rails 5 App (Optional)

Setting up the App for dockerizing

Adding Dockerfile and configure docker-compose.yml to run rails server

Pre-reqs

You should have docker for mac installed. You can get it here. Basic knowledge of Docker and Rails is also helpful.

If you are looking to add delayed_job and cron to your dockerized app you can find it here (Add background jobs and cron to your dockerized ruby on rails app).

Step 1 — Create a Rails 5 App

First, we are going to create a Rails 5 API app with Postgres. If you already have an app you can skip this section.

To create a new rails project, type the command below in your terminal:

$ rails -v

Rails 5.2.1 $ rails new rails-docker -d postgresql --api

This should create an app with the folder name rails-docker . Go into the folder and open it in your favorite text editor. I am using sublime text:

$ cd rails-docker

$ subl .

At this point, you can create the database by running rails db:create and do rails s to start the server but you don’t have to do this, as we will be doing it using docker-compose.

Step 2 — Setting up the App for dockerizing

We will make some changes to our app before we dive into creating Dockerfile.

First, we will add dotenv-rails gem in our project. We are using this to maintain environment variables for the App. So add the following line in your Gemfile under development and test group:

gem 'dotenv-rails'

Now open config/database.yml and replace all the content with the following:

development:

url: <%= ENV['DATABASE_URL'].gsub('?', '_development?') %> test:

url: <%= ENV['DATABASE_URL'].gsub('?', '_test?') %> production:

url: <%= ENV['DATABASE_URL'].gsub('?', '_production?') %>

and also create .env file in your project root folder and add the below line in it:

DATABASE_URL="postgres://root:mysecretpassword@db:5432/rails_docker_db_name?encoding=utf8&pool=5&timeout=5000"

Here we are using the same DATABASE_URL env variable and appending environment name to the database name. So for the development environment, database name will be rails_docker_db_name_development .

That's all for the project setup. Let’s move onto the interesting part.

Step 3 — Adding Dockerfile and configure docker-compose.yml

Let's add the Dockerfile to the project root folder with the following content:

FROM ruby:2.4.3 ENV APP_HOME /rails-docker # Installation of dependencies

RUN apt-get update -qq \

&& apt-get install -y \

# Needed for certain gems

build-essential \

# Needed for postgres gem

libpq-dev \

# The following are used to trim down the size of the image by removing unneeded data

&& apt-get clean autoclean \

&& apt-get autoremove -y \

&& rm -rf \

/var/lib/apt \

/var/lib/dpkg \

/var/lib/cache \

/var/lib/log # Create a directory for our application

# and set it as the working directory

RUN mkdir $APP_HOME

WORKDIR $APP_HOME # Add our Gemfile and install gems

ADD Gemfile* $APP_HOME/

RUN bundle install # Copy over our application code

ADD . $APP_HOME # Run our app

CMD RAILS_ENV=${RAILS_ENV} bundle exec rails db:create db:migrate db:seed && bundle exec rails s -p ${PORT} -b '0.0.0.0'

Command breakdown:

FROM ruby:2.4.3 tells Docker to derive our image off of the Ruby image with version 2.4.3.

tells Docker to derive our image off of the Ruby image with version 2.4.3. ENV APP_HOME /rails-docker defines an environment variable that will be available to this instance.

defines an environment variable that will be available to this instance. Next line we are installing all the dependencies needed for our app to run.

RUN mkdir $APP_HOME and WORKDIR $APP_HOME creates a directory and makes it as a working directory. This means we will be in this directory by default.

and creates a directory and makes it as a working directory. This means we will be in this directory by default. Now we are adding Gemfile and Gemfile.lock to our docker directory that we just created and run bundle install to install all the gems.

to our docker directory that we just created and run to install all the gems. Next, we are adding the rest of the project to our app directory and specifying our default command using CMD. If you noticed we are RAILS_ENV and PORT env variables which we will now add in .env file.

Add the following in your .env file:

RAILS_ENV="development"

PORT=3000

We will also add .dockerignore file in the root directory with the following content which will tell the docker to not copy these folders or files to the container whenever we build the image.

.dockerignore

.git

logs/

tmp/

Now we will create docker-compose.yml file which will define our web and db service.

version: '3'

services:

db:

image: postgres

environment:

POSTGRES_USER: root

POSTGRES_PASSWORD: mysecretpassword

volumes:

- pgdata:/var/lib/postgresql/data

web:

build: .

command: bundle exec rails s webrick -b '0.0.0.0'

volumes:

- .:/rails-docker

ports:

- "3000:3000"

depends_on:

- db

tty: true

stdin_open: true

volumes:

pgdata:

Here, we are defining 2 services, First is db service which uses Postgres image from docker hub. Notice we used db service as the host in our DATABASE_URL in the .env file. Second is web service which is built through our Dockerfile and we have provided the command to run this service. We also mapped the port of container to our host port i.e. 3000. And we have mentioned that web is dependent on db service. That’s it, now let's try to build it. Type following in your terminal:

$ docker-compose build

Once the build is complete, you should see the following output: