Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

追記(2018/07/07)

node バイナリと yarn バイナリのインストールを、nodeの docker image からコピーする方式に改善しました。

参考URL: https://qiita.com/izumin5210/items/cf14a1ea58fb82d36bb2

はじめに

docker-composeを使い、railsを簡単に開発できるテンプレートを作成しました。
webpackerの利用にも対応しています。

特徴は以下の通りです。

  • bundle installをdockerイメージビルドの時でなく、ENTRYPOINTで行います。
    • インストールされたgemがDockerVolumeにキャッシュされるので、Gemfileを更新してもイメージの再ビルドをする必要がありません。
  • webpackerにも対応。webpack-dev-serverが自動で起動されます。

webフロントエンドは違うリポジトリで作るという考え方もありますが、このテンプレートを使うと、herokuにそのままアップロードすることで、フロントエンド、バックエンド双方が一つのサーバーで供給されるようになり、運用が楽になります。

前回との違い

1年前に高速に開発できる Docker + Rails開発環境のテンプレートを作ったで、Docker + railsのテンプレートを紹介しましたが、以下の点が変わっています。

  • webpackerに対応
    • webpackerを動かせるように、Node8の環境とyarnがインストールされています。
    • webpack-dev-serverが自動で起動されます。
  • springコンテナの廃止
    • springコンテナがあることで高速に各種コマンドを実行できていましたが、railsコンテナで十分だということに気づいたため、廃止しました。
    • springコンテナとrailsコンテナを同時に起動すると、bundle installが同時に実行され同じ、bundle pathを共有してみているためエラーが起こることがありました。

公開

ソースコードは、kawasin73/rails_docker_templateで公開しています。

ブランチごとに環境を分けました。
base/ruby-x.x.x-rails-x.x.xは、テンプレートの状態のブランチです。各自の環境でアプリケーションのビルドを行う必要があります。
baseブランチには、全てまとめて、Initial Commitの1コミットしか含まれないようにしました。

git clone https://github.com/kawasin73/rails_docker_template.git .
git checkout origin/base/ruby-2.5.1-rails-5.2.0
git branch -d master && git checkout -b master
script/init && script/bootstrap

docker-compose exec rails bash
# access to http://localhost:3000

ruby-x.x.x-rails-x.x.xは、ビルド済みのテンプレートです。credentials.yml.encを削除した状態でリポジトリにおいてあるので、credentials情報を初期化してから使う必要があります。

git clone https://github.com/kawasin73/rails_docker_template.git .
git checkout base/ruby-2.5.1-rails-5.2.0
git branch -d master && git checkout -b master
# initialize credentials.yml.enc
docker-compose run --rm rails bin/rails credentials:edit
script/bootstrap

docker-compose exec rails bash
# access to http://localhost:3000

現在(2018/04/14)公開しているブランチは以下の通りです。

僕が必要になったら随時追加されていくと思います。

テンプレートの中身

base/ruby-2.5.1-rails-5.2.0-webpackを解説していきます。
前回の高速に開発できる Docker + Rails開発環境のテンプレートを作ったと重複している部分の解説は元記事からコピーします。

  • Dockerfile.dev
  • docker-compose.yml
  • Gemfile
  • .env.dev.sample
  • template/database.yml
  • .gitignore
  • script/init
  • script/bootstrap

Dockerfile.dev

Dockerfile.dev
FROM node:10.6.0 as node
FROM ruby:2.5.1

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

ENV YARN_VERSION 1.7.0

COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/

RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
    && ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg

RUN mkdir /app

WORKDIR /app

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

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

オフィシャルのnodeイメージからnodeバイナリとyarnバイナリをコピーしています。

ファイル名はあえて「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
  webpack:
    <<: *app_base
    command: "bin/webpack-dev-server"
    ports:
      - "3035:3035"
    depends_on:
      - rails
    tty: false
    stdin_open: false
  db:
    image: "postgres:10.3"
    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

webpackコンテナが追加されました。

コマンドは、

docker-compose up -d
docker-compose exec rails bin/rails db:migrate

のように実行できます。

Gemfile

Gemfile
# frozen_string_literal: true
# A sample Gemfile
source 'https://rubygems.org'
ruby '2.5.1'

gem 'rails', '5.2.0'

最初の状態では、gem 'rails', '5.2.0'のみを書きます。後述のscript/initで、rails newすることでGemfileの中身を増やしてくれます。
また、Gemfile.lockはこの時点では必要ありません。

.env.dev.sample

.env.dev.sample
DATABASE_HOST=db
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=password
EDITOR=vim

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

cp .env.dev.sample .env.dev

を実行して利用してください。
EDITOR=vimは、Rails5.2から導入されたrails credentials:editのエディタを指定します。

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
/public/packs
/node_modules

.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 build

docker-compose run --rm rails bundle exec rails new . --force --database=postgresql --skip-turbolinks --skip-git --skip-test --webpack=react

cp -f template/database.yml config/database.yml
sed -i ".bak" -e "s/host: localhost/host: webpack/g" config/webpacker.yml

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

webpack-dev-serverが起動するdockerコンテナのIPは、localhostではないです。

sed -i ".bak" -e "s/host: localhost/host: webpack/g" config/webpacker.yml

development.dev_server.hostには、webpack-dev-serverを稼働させてるコンテナのDockerネットワーク内でのホスト名webpackを設定します。
0.0.0.0を設定しても、webpacker-dev-serverは稼働しますが、HMRが正しく動かなくなるため、ホスト名を指定します。
一方、Docker for Macでは、IPアドレスはホストマシンから127.0.0.1として見えます。そのため、development.dev_server.publicは、デフォルトのlocalhost:3035のまま変更しません。

script/bootstrap

script/bootstrap
#!/usr/bin/env bash

cp .env.dev.sample .env.dev
docker-compose run --rm rails rails db:create
docker-compose run --rm rails rails db:migrate
docker-compose run --rm rails bin/yarn install
docker-compose up -d

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

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

kawasin73
ソフトウェアエンジニアです。東京大学4年Go/Ruby/Swift/Python/Javascript/Java/C
https://kawasin73.hatenablog.com/
dmmcom
総合エンタテイメントサイト「DMM.com」を運営。会員数は2,900万人を突破。動画配信、FX、英会話、ゲーム、太陽光発電、3Dプリンタなど40以上のサービスを展開。沖縄での水族館事業参入、ベルギーでのサッカークラブ経営など、様々な事業を手掛ける。また2018年より若手起業家の支援を強化、「DMM VENTURES」による出資や、M&Aなどを積極的に展開している。
https://dmm-corp.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした