Most Rails application use similar stack: Rails + Postgres + Redis + worker (Sidekiq, Resque, Delayed::Job).

In this post I want to share and explain my simple Docker Compose setup.

Repository with an example application.

Scripts

Dockerfile:

FROM ruby:2.5.1-alpine

RUN apk add --no-cache --update build-base \
                                postgresql-dev \
                                nodejs \
                                tzdata
ENV APP_PATH /app

# Different layer for gems installation
WORKDIR $APP_PATH
COPY Gemfile Gemfile.lock $APP_PATH/
RUN bundle

docker-compose.yml:

version: '3'
services:
  web:
    image: rails-example
    build: .
    command: bin/docker/web_start
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis
    env_file:
      - dev.env
  worker:
    image: rails-example
    build: .
    command: bin/docker/worker_start
    volumes:
      - .:/app
    depends_on:
      - db
      - redis
      - web
    env_file:
      - dev.env
  redis:
    image: redis:4.0-alpine
    volumes:
      - redis_data:/data
  db:
    image: postgres:alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
  redis_data:

dev.env:

REDIS_URL=redis://redis

bin/docker/web_start:

#!/bin/sh
bundle
rm tmp/pids/server.pid
bin/rake db:migrate || bin/rake db:setup
bin/rails server -p 3000 -b '0.0.0.0'

bin/docker/web_start:

#!/bin/sh
bundle
sidekiq

Details

Important features that distinguish this setup from examples on the internet:

  • Lean Dockerfile.
    • no mkdir /app. WORKDIR automatically creates it.
    • no EXPOSE or CMD. Docker Compose handles it
  • bundle (shorcut for bundle install) executed when starting container. This way you don’t have to rebuild the image every time you change your gems.
  • In docker-compose.yml image build from local directory is marked with its own tag/label using image: rails-example entry. Thanks to this web and worker reuse the same image. If you remove this line the same image is built twice by Docker Compose for no reason.

Test it

I’ve created an example Rails application so you can easily test it yourself.

git clone https://github.com/gogiel/rails-example-app.git
cd rails-example-app
git checkout local-docker 
docker-compose up