追記
続編書きました。
よりスリムになって、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
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
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
# 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
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
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
/log
/tmp
!/log/.keep
!/tmp/.keep
/public/system
.env
.env.dev
/.bundle
/vendor/bundle
/.idea
.DS_Store
ここは各自ご自由に。
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
#!/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
で
tty: true
stdin_open: true
を設定しています。これによって、pumaのサーバーの処理に挿入したbinding.pry
を使えるようになります。
docker ps
コマンドで、railsコンテナのコンテナ名を調べてください。
docker attach xxxx_rails_1 # xxxx_rails_1 は調べたコンテナ名
とすると、binding.pryをDockerの中で使えるようになります。
最後に
以上です。