Rails 6のDocker開発環境構築をEvil Martians流にやってみた

先々月に公開したこちらの翻訳記事の実践編ということで。試行錯誤しているうちにRailsが6.0.1になりました。

クジラに乗ったRuby: Evil Martians流Docker+Ruby/Rails開発環境構築(翻訳)

Docker for Macについて

これまではピュアな環境を求めてParallels Desktop for MacのUbuntu VM上でDockerを使っていたのですが、久しぶりにDocker for Macを使ってみると速度や使い勝手が随分よくなっていて驚きました。

  • Docker for Macの方がUbuntu VMのDockerよりビルドが速い(体感ですが)
    • ただしEvil Martiansの記事にもあるように、docker-composeでボリュームに:cachedを記述しておかないとDocker for Macで遅くなります
  • 今はdmgファイルをダウンロードしてアプリケーションフォルダにドロップするだけでインストール完了できる

Ubuntuだと基本的にsudoを打たないとDockerが使えないのと(回避方法は一応ありますが)、macOSとの間のレイヤが増えるつらみの方が大きくなってきたので、Docker for Macでやることにしました😅。

環境

  • macOS: 10.15.1(Catalina)
  • Docker for Mac
    • Docker: 19.03.4
    • Docker-compose: 1.24.1
    • Dockerhubにログインしておく
    • (既存のDockerがあれば削除しておく)
  • Rails: 6.0.1
  • Ruby: 2.6.5
  • Git: 2.24.0
  • dipをインストールする

本記事でのDocker操作は全面的にEvil Martians謹製のdipを使っています。dipの説明は割愛しますが、とてもよかったので別記事にしたいと思います。

追記(2019/12/04): 書きました↓

docker-composeを便利にするツール「dip」を使ってみた

リポジトリ

今回のサンプルを以下のリポジトリに置きました。

プロジェクトディレクトリ
├── .dockerdev
│   ├── .psqlrc
│   ├── Aptfile
│   └── Dockerfile
├── .env(ダミー)
├── dip.yml
└── docker-compose.yml

変更の方針

  • Evil Martiansの設定からの変更は最小限とし、できるだけ汎用性を高める
    • docker-compose内のimage名は自分のプロジェクトに合わせてリネームし、:1.0.0は残す
  • Evil Martians流でやるとイメージのサイズが1GBになるので軽量化する
    • その代わり基本的なツールは自分で補わないといけない😅
  • SidekiqとRedisは使わないのでdocker-compose.ymlから削除
  • dip.ymlは多少カスタマイズする
  • .psqlrcも入れておく

変更後のDockerfile

ARG RUBY_VERSION
# 後述
FROM ruby:$RUBY_VERSION

ARG PG_MAJOR
ARG NODE_MAJOR
ARG BUNDLER_VERSION
ARG YARN_VERSION

# 依存関係をインストール
# 外部のAptfileでやってる(後ほどお楽しみに!)
COPY .dockerdev/Aptfile /tmp/Aptfile
RUN apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade &&\
    DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends curl gnupg2 &&\
    # ソースリストにPostgreSQLを追加
    curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - &&\
    echo 'deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main' $PG_MAJOR > /etc/apt/sources.list.d/pgdg.list &&\
    # ソースリストにNodeJSを追加
    curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR.x | bash - &&\
    # ソースリストにYarnを追加
    curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - &&\
    echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list &&\
    apt-get update -qq &&\
    DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends\
    build-essential\
    postgresql-client-$PG_MAJOR\
    libpq-dev\
    nodejs\
    yarn=$YARN_VERSION-1\
    $(cat /tmp/Aptfile | xargs) &&\
    apt-get clean &&\
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* &&\
    truncate -s 0 /var/log/*log

# bundlerとPATHを設定
ENV LANG=C.UTF-8\
  GEM_HOME=/bundle\
  BUNDLE_JOBS=4\
  BUNDLE_RETRY=3
ENV BUNDLE_PATH $GEM_HOME
ENV BUNDLE_APP_CONFIG=$BUNDLE_PATH\
  BUNDLE_BIN=$BUNDLE_PATH/bin
ENV PATH /app/bin:$BUNDLE_BIN:$PATH

# RubyGemsをアップグレードして必要なバージョンのbundlerをインストール
RUN gem update --system &&\
    gem install bundler:$BUNDLER_VERSION &&\
    gem install rails &&\
    mkdir -p /app

WORKDIR /app

Dockerfileの変更のポイント

  • イメージをruby:2.6.5からruby:2.6.5-slim-busterに変更
    • イメージが軽くなる代わりに、そのままだとcurlpingなどの基本的なパッケージも入らないので、apt-getでインストールするかAptfileに書いておきます
  • curlを実行するRUNコマンドをまとめてイメージの肥大化を防ぐ
  • gem install railsを追加

これでイメージは1GBから578MBに半減しました。もっと減らしたいならAlpine Linuxベースのイメージを使う手もあります。

Dockerのマルチステージビルドもやってみたかったのですが、手間の割にあまり報われない気がしたのと、Evil Martians流からあまり離れたくなかったので見送りました。

変更後のdocker-compose.yml

version: '3.4'

services:
  app: &app
    build:
      context: .
      dockerfile: ./.dockerdev/Dockerfile
      args:
        RUBY_VERSION: '2.6.5-slim-buster'
        PG_MAJOR: '11'
        NODE_MAJOR: '11'
        YARN_VERSION: '1.19.1'
        BUNDLER_VERSION: '2.0.2'
    image: yourapp_docker:1.0.0
    tmpfs:
      - /tmp

  backend: &backend
    <<: *app
    stdin_open: true
    tty: true
    volumes:
      - .:/app:cached
      - rails_cache:/app/tmp/cache
      - bundle:/bundle
      - node_modules:/app/node_modules
      - packs:/app/public/packs
      - .dockerdev/.psqlrc:/root/.psqlrc:ro
    environment:
      - NODE_ENV=development
      - RAILS_ENV=${RAILS_ENV:-development}
      - DATABASE_URL=postgres://postgres:postgres@postgres:5432
      - BOOTSNAP_CACHE_DIR=/bundle/bootsnap
      - WEBPACKER_DEV_SERVER_HOST=webpacker
      - WEB_CONCURRENCY=1
      - HISTFILE=/app/log/.bash_history
      - PSQL_HISTFILE=/app/log/.psql_history
      - EDITOR=vi
    depends_on:
      - postgres
    env_file: .env

  runner:
    <<: *backend
    command: /bin/bash
    ports:
      - '3000:3000'
      - '3002:3002'

  rails:
    <<: *backend
    command: bundle exec rails server -b 0.0.0.0
    ports:
      - '3000:3000'

  postgres:
    image: postgres:11.1
    volumes:
      - .psqlrc:/root/.psqlrc:ro
      - postgres:/var/lib/postgresql/data
      - ./log:/root/log:cached
    environment:
      - PSQL_HISTFILE=/root/log/.psql_history
    ports:
      - 5432
    env_file: .env

  webpacker:
    <<: *app
    command: ./bin/webpack-dev-server
    ports:
      - '3035:3035'
    volumes:
      - .:/app:cached
      - bundle:/bundle
      - node_modules:/app/node_modules
      - packs:/app/public/packs
    environment:
      - NODE_ENV=${NODE_ENV:-development}
      - RAILS_ENV=${RAILS_ENV:-development}
      - WEBPACKER_DEV_SERVER_HOST=0.0.0.0

volumes:
  postgres:
  bundle:
  node_modules:
  rails_cache:
  packs:

docker-compose.ymlの変更のポイント

  • redisなど、自分の使わないサービスを削除した
  • 認証情報は.envファイルに含め、.gitignoreに追加した
    • そのためenv_file: .envをyamlに2箇所追加した
    • (リポジトリの.envは空にしてあります)
  • credentialの暗号化機能はまだ使っていません

たとえ空であっても本当は.envをリポジトリに入れたくありませんでしたが、すぐ試せるようにしたかったのでした。

補足

このdocker-compose.ymlはローカル開発環境の構築のみを想定しています。Evil Martiansもそのように作っています。

PostgreSQLの接続文字列はdocker-compose.ymlに以下のように丸ごと埋め込まれています↓ので、db/database.ymlを開発用に設定する必要はありませんし、db/database.ymlにdevelopment環境用の設定を加えても効きません(ハマりました😅)。db/database.ymlを設定するのはCIやproductionぐらいになると思います。

  • DATABASE_URL=postgres://postgres:postgres@postgres:5432

docker-compose.ymlのimage名のyourapp_dockerの部分は適宜自分のプロジェクト名に変えてください。

セットアップ

  • dipをインストールする(homebrewでもできます)
gem install dip
  • git clone git@github.com:hachi8833/rails_docker_like_evilmartians.gitでリポジトリをcloneしてディレクトリに移動する

  • docker-compose.ymlのyourapp_dockerは自分のプロジェクト名に変更する(本記事では変更していません)

  • git checkinしてコミット

  • dip compose buildでビルド

$ dip compose build
# 略
Successfully tagged yourapp_docker:1.0.0
  • dip shでコンテナにログインする
$ dip sh
Creating network "rails_docker_like_evilmartians_default" with the default driver
Creating volume "rails_docker_like_evilmartians_postgres" with default driver
Creating volume "rails_docker_like_evilmartians_bundle" with default driver
Creating volume "rails_docker_like_evilmartians_node_modules" with default driver
Creating volume "rails_docker_like_evilmartians_rails_cache" with default driver
Creating volume "rails_docker_like_evilmartians_packs" with default driver
root@7b09aea79b9f:/app#

以下はDockerコンテナ内部での作業です。

  • yarn -vruby -vbundle -vwhich railsが実行できることを確認
  • rails newに好みのオプションを付けて実行

なおbundle execは不要です。

今回は以下のオプションにしました。アプリ名はappで固定されます。Webpackerもまとめてセットアップされます。

rails new . –database=postgresql –skip-active-storage –skip-action-mailer –skip-active-job –skip-action-cable –skip-action-mailbox –skip-action-text –skip-turbolinks –skip-sprockets –skip-spring –skip-bootsnap –webpacker –webpack=vue

root@7b09aea79b9f:/app# rails new . --database=postgresql --skip-active-storage --skip-action-mailer --skip-active-job --skip-action-cable --skip-action-mailbox --skip-action-text --skip-turbolinks --skip-sprockets --skip-spring --skip-bootsnap --webpacker --webpack=vue
# 略
info All dependencies
├─ @vue/component-compiler-utils@3.0.2
├─ consolidate@0.15.1
├─ de-indent@1.0.2
├─ he@1.2.0
├─ merge-source-map@1.1.0
├─ prettier@1.19.1
├─ vue-hot-reload-api@2.3.4
├─ vue-loader@15.7.2
├─ vue-style-loader@4.1.2
├─ vue-template-compiler@2.6.10
├─ vue-template-es2015-compiler@1.9.1
└─ vue@2.6.10
Done in 5.33s.
Webpacker now supports Vue.js 🎉
  • 環境によっては以下も実行して、bundlerの余分なメッセージを抑制する
bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java
  • 使われていないvendorディレクトリをrm -rf vendorで削除
  • exitでDockerをいったん抜ける
  • git checkinする

起動前の設定

  • config/environments/development.rbに以下を追加する
config.hosts << "localhost"
config.web_console.whitelisted_ips = '0.0.0.0/0'

Rails 6からはconfig.hostを明示的に指定する必要があります(ウォッチ20190401)。

また、Dockerで開発する場合はおそらくwhitelisted_ipsの制約も解除が必要になります。


  • dip provisionを実行してdevelopmentとtestの空データベースを作成
    • (dip.yamlをそれ用にカスタマイズしています)
    • データベース名はapp_developmentapp_testで固定
$ dip provision
# (略)
== Preparing database ==
Created database 'app_development'
== Installing dependencies ==
The Gemfile's dependencies are satisfied

== Preparing database ==

== Removing old logs and tempfiles ==

== Restarting application server ==
== Installing dependencies ==
The Gemfile's dependencies are satisfied

== Preparing database ==
Created database 'app_test'

== Removing old logs and tempfiles ==

== Restarting application server ==
  • 念のためdip minitestでminitestを実行
$ dip minitest
Starting rails_docker_like_evilmartians_postgres_1 ... done
Run options: --seed 59169

# Running:



Finished in 0.000523s, 0.0000 runs/s, 0.0000 assertions/s.
0 runs, 0 assertions, 0 failures, 0 errors, 0 skips
  • git checkinでコミット

いよいよ起動

できた!

$ dip rails s
Starting rails_docker_like_evilmartians_postgres_1 ... done
=> Booting Puma
=> Rails 6.0.1 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.0 (ruby 2.6.5-p114), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

後は好きに進めます。dip lsすればdipのサブコマンド一覧が表示されます。

作業が終わったらdocker-compose downでコンテナを終了します。

参考: 後からプロジェクトに参加する人の作業

  • Git、Docker for Mac、git-flow、dipなどをセットアップ
  • リポジトリをgit cloneする
  • dip compose build
  • dip bundle install
  • dip yarn install --check-files
  • .envに秘密鍵を入れるのであれば、.gitignoreに.envを追加する(必須)
  • データベースにseedデータを入れる(略)

Dockerfileを改定した場合は、docker-compose.ymlのimage名のタグにあるバージョン番号を適宜更新します。

おたより発掘

関連記事

クジラに乗ったRuby: Evil Martians流Docker+Ruby/Rails開発環境構築(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ