DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack)


(2020.10.28 更新: docker-compose.ymlのvolume最適化、build時間短縮)

はじめに

最新(2020.8.5現在)のRailsチュートリアルではRails 6が使用されており、
これに対応した開発環境構築をDockerでやってみたいと思います。

個人開発アプリの開発環境構築の際に、
私は新しいものが好きだから...とRails 6を導入しました。

ところが...このRails 6からJavaScriptのモジュールバンドラーにWebpackが導入されたことにより、
BootstrapやFontawesomeといったツールの導入、管理方法が変わるだけでなく、
そもそも環境構築の際もRails 5では必要ない手順が必要だったりと、
Rails 6とWebpackの壁に盛大にぶつかることとなりました...

せっかくなので、今回の試みを経て、知識、経験の整理定着を図りたいと思います。

また、実際にRailsチュートリアルを脱線しながら再走し、学びを深められたらと思っています。

関連記事

第一回(当記事)
DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack) - Qiita

第二回
DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ- - Qiita

第3回
DockerでRailsチュートリアルのローカル開発環境構築 - WebpackでBootstrapとFont Awesomeを導入 - - Qiita

第4回
コンテナ上のデバッグ環境構築 - DockerでRailsチュートリアルのローカル開発環境構築 - - Qiita

個人開発アプリ
mdClip <オンラインmarkdownエディタ>

以前Rails 5の環境構築をDockerでやってみた記事
はじめてのDockerでRails開発環境構築 [NGINX + Rails 5 (puma) + PostgreSQL] - Qiita

環境

  • Mac OS (Mojave)
  • Docker for Mac
  • Ruby 2.6.3-alpine
  • Rails 6.0.3
  • PostgreSQL 11.0-alpine

構成ファイル

以下の5つのファイルをワークスペースに用意します
Dockerfile, docker-compose.yml, Gemfile, Gemfile.lock, entrypoint.sh

git clone -b create-docker-files https://github.com/naokit-dev/sample_app_on_docker.git

Dockerfile

  • イメージの軽量化のため"alpine"を使用

  • nodejs, yarnはWebpack導入に必要

  • postgresqlだけでは駄目で、postgresql-devも必要

  • bundle installの-j4オプションでbundle installが高速化される

  • bundle install後、不要ファイル削除はイメージサイズの削減に貢献

FROM ruby:2.6.3-alpine

ENV LANG=ja_JP.UTF-8
ENV TZ=Asia/Tokyo
ENV ROOT=/myapp \
    GEM_HOME=/bundle \
    BUNDLE_PATH=$GEM_HOME
ENV BUNDLE_BIN=$BUNDLE_PATH/bin
ENV PATH /app/bin:$BUNDLE_BIN:$PATH


WORKDIR $ROOT

RUN apk update && \
    apk upgrade && \
    apk add --no-cache \
        gcc \
        g++ \
        libc-dev \
        libxml2-dev \
        linux-headers \
        make \
        nodejs \
        postgresql \
        postgresql-dev \
        tzdata \
        yarn && \
    apk add --virtual build-packs --no-cache \
        build-base \
        curl-dev

COPY Gemfile $ROOT
COPY Gemfile.lock $ROOT

RUN bundle install -j4
# 不要ファイル削除
RUN rm -rf /usr/local/bundle/cache/* /usr/local/share/.cache/* /var/cache/* /tmp/* && \
apk del build-packs

COPY . $ROOT

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["sh", "/usr/bin/entrypoint.sh"]
EXPOSE 3000

docker-compose.yml

  • macでストレージのアクセスが遅い問題に対応するためvolumeに:cahedオプションを追加
  • webpack-dev-serverを別コンテナで起動させて、hot reloadに対応させています. (ファイル構成に変更があった場合にブラウザのリロード、必要に応じてjavascript周りのコンパイルをしてくれる)
  • dbのhost, user, passwordは後で再利用
version: "3.8"

services:
  db:
    image: postgres:11.0-alpine
    volumes:
      - postgres:/var/lib/postgresql/data:cached
    ports:
      - "5432:5432"
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=ja_JP.UTF-8"
      TZ: Asia/Tokyo
  app:
    build: .
    command: ash -c "rm -f tmp/pids/server.pid && ./bin/rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp:cached
      - rails_cache:/myapp/tmp/cache
      - node_modules:/myapp/node_modules:cached
      - bundle:/bundle:cached
    tmpfs:
      - /tmp
    tty: true
    stdin_open: true
    ports:
      - "3000:3000"
    environment:
      RAILS_ENV: development
      NODE_ENV: development
      DATABASE_HOST: db
      DATABASE_PORT: 5432
      DATABASE_USER: postgres
      DATABASE_PASSWORD: password
      WEBPACKER_DEV_SERVER_HOST: webpacker
    depends_on:
      - db
      - webpacker

  webpacker:
    build: .
    command: ./bin/webpack-dev-server
    volumes:
      - .:/myapp:cached
      - node_modules:/myapp/node_modules:cached
    environment:
      RAILS_ENV: development
      NODE_ENV: development
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
    tty: false
    stdin_open: false
    ports:
      - "3035:3035"

volumes:
  rails_cache:
  node_modules:
  postgres:
  bundle:

Gemfile

source 'https://rubygems.org'
gem 'rails',      '6.0.3'

Gemfile.lock

空のファイルで良いのでtouchコマンドのみ

touch Gemfile.lock

entrypoint.sh

#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

手順

Rails 6.0.3をインストールします

docker-compose run app rails new . --force --no-deps --database=postgresql --skip-bundle

Gemfile

Railsチュートリアルに準じて以下のように変更
(Development, test環境でもPostgreSQLを使用するように変更してあります。)

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',      '6.0.3'
gem 'puma',       '4.3.4'
gem 'pg',         '1.1.4'
gem 'sass-rails', '5.1.0'
gem 'webpacker',  '4.0.7'
gem 'turbolinks', '5.2.0'
gem 'jbuilder',   '2.9.1'
gem 'bootsnap',   '1.4.5', require: false

group :development, :test do
  gem 'byebug',  '11.0.1', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  gem 'web-console',           '4.0.1'
  gem 'listen',                '3.1.5'
  gem 'spring',                '2.1.0'
  gem 'spring-watcher-listen', '2.0.1'
end

group :test do
  gem 'capybara',                 '3.28.0'
  gem 'selenium-webdriver',       '3.142.4'
  gem 'webdrivers',               '4.1.2'
  gem 'rails-controller-testing', '1.0.4'
  gem 'minitest',                 '5.11.3'
  gem 'minitest-reporters',       '1.3.8'
  gem 'guard',                    '2.16.2'
  gem 'guard-minitest',           '2.4.6'
end

group :production do
end

# Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります
#gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

Gemfile.lockをアップデート(必要ないかもしれません)

docker-compose run app bundle update

webpackerのインストール

Rails 6ではwebpackerが必要ですが、
このままではインストールされていないためインストールします

docker-compose run app rails webpacker:install

データベースの設定

config/database.yml
host, username, passwordをdocker-compose.ymlと一致させる

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

#省略...

docker-compose build

DockerfileやGemfileを変更する度に'build'が必要です
bundle installも実施されるため少し時間がかかります

docker-compose build

いよいよコンテナを起動

docker-compose up

データベース作成

このままだとDBがないよと言われるので、development環境のDBを作成

docker-compose run app rake db:create

動作確認

docker psで起動しているコンテナ確認
DB, Rails, webpack-dev-serverの3つのコンテナが起動しています。

$ docker ps
CONTAINER ID        IMAGE                            COMMAND                  ...              PORTS                              NAMES
1fb4f53d5652        sample_app_on_docker_app         "sh /usr/bin/entrypo…"   ...    0.0.0.0:3000->3000/tcp             sample_app_on_docker_app_1
ccd40c018d53        sample_app_on_docker_webpacker   "sh /usr/bin/entrypo…"   ...    3000/tcp, 0.0.0.0:3035->3035/tcp   sample_app_on_docker_webpacker_1
74392532098a        postgres:11.0-alpine             "docker-entrypoint.s…"   ...    0.0.0.0:5432->5432/tcp             sample_app_on_docker_db_1

ブラウザでlocalhost:3000にアクセスすると

お疲れさまでした"Yay! You’re on Rails!"

Trouble shoot

check_yarn_integrity関連

コンテナをdocker-compose upで起動したときに出るエラー

app_1        | ========================================
app_1        |   Your Yarn packages are out of date!
app_1        |   Please run `yarn install --check-files` to update.
app_1        | ========================================
app_1        | 
app_1        | 
app_1        | To disable this check, please change `check_yarn_integrity`
app_1        | to `false` in your webpacker config file (config/webpacker.yml).
app_1        | 
app_1        | 
app_1        | yarn check v1.16.0
app_1        | info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.
app_1        | 
app_1        | 
app_1        | Exiting
sample_app_on_docker_app_1 exited with code 1

config/webpacker.yml
以下のように変更します

#...省略

development:
  <<: *default
  compile: true 

  # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
  check_yarn_integrity: false # true -> falseに変更

#省略...

"webpack-dev-server" not found

同じくコンテナをdocker-compose upで起動したときに出るエラー

webpacker_1  | yarn run v1.16.0
webpacker_1  | error Command "webpack-dev-server" not found.
webpacker_1  | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
sample_app_on_docker_webpacker_1 exited with code 1

package.jsonにwebpack-dev-serverが記述されていないはずなので
webpack-dev-serverをインストール

docker-compose run app yarn add webpack-dev-server

おまけ

イメージサイズ 477MB
先人の知恵を多々お借りして軽量化したつもりです。
Dockerを学び始めた頃に作ったのイメージは1.5GBほどありました...

$docker images
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
sample_app_on_docker_app         latest              84aed607a3d2        31 minutes ago      477MB
sample_app_on_docker_webpacker   latest              84aed607a3d2        31 minutes ago      477MB