Ruby
Rails
docker
Rails5

高速に開発できる Docker + Rails開発環境のテンプレートを作った


追記

続編書きました。

よりスリムになって、webpackerにも対応しました。こっちの方を読んでください。

DockerでRails+Webpackerの開発環境を構築するテンプレート


はじめに

docker-composeを使い、railsを簡単に開発できるテンプレートを作成しました。

特徴は以下の通りです。



  • bundle installをイメージビルドのときではなく、ENTRYPOINTで行う


  • springコンテナを用意して高速にrailsコマンドを実行できる

テンプレートは、github にアップロードしています


使い方

テンプレートからプロジェクトを立ち上げる場合は、以下のコマンドです。RubyバージョンやRailsのバージョンを調整できます。

git clone https://github.com/kawasin73/rails_docker_template.git

cd rails_docker_template
script/init && script/bootstrap

雛形から始めたい場合は、以下のコマンドで即座に開発を開始できます。

git clone https://github.com/kawasin73/rails_docker_template.git

cd rails_docker_template
git checkout -b ruby-2.4.0-rails-5.0.1 origin/ruby-2.4.0-rails-5.0.1 && script/bootstrap


テンプレートの内容解説

テンプレートの中身は


  • Dockerfile.dev

  • docker-compose.yml

  • Gemfile

  • .env.dev.sample

  • template/database.yml

  • .gitignore

  • script/init

  • script/bootstrap

です。


Dockerfile.dev


Dockerfile.dev

FROM ruby:2.4.0

ENV LANG C.UTF-8

RUN apt-get update -qq && \
apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
libfontconfig1 && \
rm -rf /var/lib/apt/lists/*

ENV ENTRYKIT_VERSION 0.4.0

RUN wget https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
&& tar -xvzf entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
&& rm entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
&& mv entrykit /bin/entrykit \
&& chmod +x /bin/entrykit \
&& entrykit --symlink

RUN mkdir /app

WORKDIR /app

RUN bundle config build.nokogiri --use-system-libraries

ENTRYPOINT [ \
"prehook", "ruby -v", "--", \
"prehook", "bundle install -j3 --quiet", "--"]


ファイル名はあえて「Dockerfile.dev」にしています。開発環境と本番環境ではDockerfileの中身は変わってくると思うので、Dockerfileは別途作って本番環境用に使うことができます。

ENV LANG C.UTF-8 によって rails consoleの中で日本語の入力をできるようにしています。

最大の特徴は、ENTRYKITだと思います。開発しやすいRails on Docker環境の作り方を参考にしました。

ENTRYPOINT の中で bundle install を行うことでインストールした gem をDocker Volumeの中にキャッシュすることができます。

Dockerfileの中でbundle installをしないので、新しくgemを追加した時に、Dockerイメージを再度ビルドする必要がなく、高速に開発を進めることができます。

開発環境では、ローカルのrailsディレクトリを、Dockerコンテナにマウントして開発します。

そのため、Dockerfile.devでは、COPY . /appをしません。RUN mkdir /app/appディレクトリを作成するだけにとどめます。


docker-compose.yml


docker-compose.yml

version: '2'

services:
rails: &app_base
build:
context: .
dockerfile: "Dockerfile.dev"
command: ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"]
env_file:
- "./.env.dev"
volumes:
- ".:/app"
volumes_from:
- data
ports:
- "3000:3000"
depends_on:
- db
tty: true
stdin_open: true
spring:
<<: *app_base
command: ["bundle", "exec", "spring", "server"]
ports: []
tty: false
stdin_open: false
db:
image: "postgres:9.6.2"
environment:
- "POSTGRES_USER=postgres"
- "POSTGRES_PASSWORD=password"
volumes_from:
- data
ports:
- "5432:5432"
data:
image: "busybox"
volumes:
- "db:/var/lib/postgresql/data"
- "bundle:/usr/local/bundle"

volumes:
db:
driver: local
bundle:
driver: local


ほとんどそのままですが、特徴と言えるのは、springコンテナだと思います。

Railsアプリケーション開発を完全にDocker化するを参考にしました。

docker-compose up -d

した上で、

docker-compose exec spring rails db:migrate

を実行するなどすることで、springを利用することができ各種コマンドを高速に実行することができます。


Gemfile


Gemfile

# frozen_string_literal: true

# A sample Gemfile
source 'https://rubygems.org'

gem 'rails', '5.0.1'


最初の状態は、gem 'rails', '5.0.1'のみを書きます。後述のscript/initで、rails newすることでGemfileの中身を増やしてくれます。


.env.dev.sample


.env.dev.sample

DATABASE_HOST=db

DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=password


データベースの情報は環境変数で railsアプリケーションに渡します。

cp .env.dev.sample .env.dev

で利用することができます。また、パスワードなどの秘密情報を管理したくなると思うので、.env.devはgitignoreに追加します。


template/database.yml


template/database.yml

default: &default

adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch('DATABASE_USER') { 'root' } %>
password: <%= ENV.fetch('DATABASE_PASSWORD') { 'password' } %>
host: <%= ENV.fetch('DATABASE_HOST') { 'localhost' } %>
port: <%= ENV.fetch('DATABASE_PORT') { 5432 } %>

development:
<<: *default
database: app_development

test:
<<: *default
database: app_test

production:
<<: *default
database: app_production


データベースの情報は環境変数で railsアプリケーションに渡します。

cp -f template/database.yml config/database.yml

で、自動生成されるdatabase.ymlを上書きします。


.gitignore


.gitignore

/log

/tmp
!/log/.keep
!/tmp/.keep
/public/system

.env
.env.dev

/.bundle
/vendor/bundle

/.idea

.DS_Store


ここは各自ご自由に。


script/init


script/init

#!/usr/bin/env bash

cp .env.dev.sample .env.dev

docker-compose run --rm rails rails new . --force --database=postgresql --skip-bundle --skip-git --skip-test --api

cp -f template/database.yml config/database.yml

docker-compose run --rm rails bundle exec spring binstub --all


ここまでのテンプレートを用意した上で、このスクリプトを流すと、Railsプロジェクトが作成されます。

APIモードで作っていますが、rails new のオプションは各自ご自由に


script/bootstrap


script/bootstrap

#!/usr/bin/env bash

cp .env.dev.sample .env.dev
docker-compose run --rm spring rails db:create
docker-compose run --rm spring rails db:migrate
docker-compose up -d


script/initを実行して作成済みのプロジェクトを、git cloneしてきた後などに実行します。データベースの作成ができます。

注意点としては、git cloneしてきた直後に docker-compose up -dしてはいけない ということです。

ENTRYPOINTの中でbundle installが行われるのですが、初回はrailsコンテナとspringコンテナの両方で、同時にbundle installが実行されます。

この2つのコンテナのgemを保存するディレクトリ /usr/local/bundle は、Docker Volume でつながっているのでエラーが起こることがあります。一度キャッシュを作ってしまえば、2回目以降は同時に立ち上げても大丈夫です。


開発を進めるには


spring でコマンドを高速実行

spring コンテナーを作成しているので、rails コマンドをspringを利用して高速に実行できます。

例えば、rails db:migrateを実行するには

docker-compose exec spring rails db:migrate

を実行するとdockerコンテナー内で実行されます。


binding.pry を使う

docker-compose.yml


docker-compose.yml

    tty: true

stdin_open: true

を設定しています。これによって、pumaのサーバーの処理に挿入したbinding.pry を使えるようになります。

docker ps

コマンドで、railsコンテナのコンテナ名を調べてください。

docker attach xxxx_rails_1 # xxxx_rails_1 は調べたコンテナ名

とすると、binding.pryをDockerの中で使えるようになります。


最後に

以上です。


参考URL