Set up Docker for Rails development

by Giang, last updated 04 Feb 2019

Docker is a great tool to synchronize dev envinronment on different machine. This resolves the excuse "not work on my machine". This also helps new devs to quickly set up the project without scratching their head with all the missing libs, mismatch versions, etc.

This article will describe how to setup Docker and Docker Compose for a Rails app that uses Postgresql/MySQL as database, Sidekiq and Redis.

Software versions use in this article

Docker version 18.03.1-ce, build 9ee9f40
docker-compose version 1.21.2, build a133471
Ruby 2.6.1
Rails 5
Postgres 10.6
MySQL 5.7.22
Redis 4.0.9

Table of Contents:

  1. Install Docker and Docker Compose
  2. Dockerfile
  3. Docker Compose file
  4. .dockerignore
  5. Build and run
  6. References

Install Docker and Docker Compose

Installation guides for Docker and Docker Compose are well written in Docker docs.

Dockerfile

FROM ruby:2.6.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /demoapp
WORKDIR /demoapp
COPY Gemfile /demoapp/Gemfile
COPY Gemfile.lock /demoapp/Gemfile.lock
RUN bundle install
COPY . /demoapp

Docker Compose file

version: '3'
services:
  db:
    image: mysql:5.7.22
    volumes:
      - ./tmp/db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=123456
  redis:
    image: redis:4.0.9
    volumes:
      - ./tmp/redis:/data
  web:
    depends_on:
      - db
      - redis
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/demoapp
    ports:
      - 3000:3000
    environment:
      - REDIS_URL=redis://redis:6379/
  sidekiq:
    depends_on:
      - db
      - redis
    build: .
    command: sidekiq -C config/sidekiq.yml
    volumes:
      - .:/demoapp
    environment:
      - REDIS_URL=redis://redis:6379/

If the app uses PostgreSQL instead of MySQL, the DB image will be like follow:

db:
    image: postgres:10.6
    volumes:
      - ./tmp/db:/var/lib/postgresql/data

If the app uses MongoDB:

version: '3'
services:
  mongodb:
    image: mongo
    ports:
      - "27017:27017"
  web:
    ...
    depends_on:
      - mongodb

Then we'll need to update config/database.yml to point to the DB image:

For MySQL

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: 123456
  host: db
development:
  <<: *default
  database: demoapp_development

test:
  <<: *default
  database: demoapp_test

For PostgreSQL

default: &default
  adapter: postgresql
  encoding: unicode
  username: postgres
  password:
  host: db
  pool: 5

development:
  <<: *default
  database: demoapp_development

test:
  <<: *default
  database: demoapp_test

For MongoDB we'll need to update config/mongoid.yml

development:
  clients:
    default:
      database: development
      hosts:
        - mongodb

See more for MongoDB setup and troubleshooting notes here

.dockerignore

We could also add .dockerignore to the root directory of Rails app, this file is optional and it works similarly to .gitignore. This file is useful to declare list of files/directories that should be excluded from Docker build.

For example, since we use ./tmp/ to store database and redis data we should ignore it from Docker build.

./tmp/*

Build and run

For the first time run

docker-compose build

to build neccessary images. Then run

docker-compose up

to start the whole stack.

Since the app is now running in Docker containers instead of your host OS, the regular commands, rake tasks need to be run inside the container as well. For example to create and migrate database for the first time

docker-compose run web rake db:create db:migrate db:seed

Another thing to note is that when Gemfile changed, we need to rebuild web and sidekiq images

docker-compose run web bundle
docker-compose run sidekiq bundle
docker-compose up --build

References