Ruby on Rails 6のDocker環境構築
参考サイト
-
Quickstart: Compose and Rails | Docker Documentation
- Rails 5までの方法
-
DockerでRuby on Railsの環境構築を行うためのステップ【Rails 6対応】 - Qiita
- Rails 6に対応
-
distributions/README.md at master · nodesource/distributions
- Node.js (LTS)のインストール
-
Installation | Yarn
- Yarnのインストール
1. Dockerfile, docker-compose.ymlを用意する
Rails 6からはwebpackを利用するので、Node.js, Yarnもインストールする必要がある。
FROM ruby:3.0
RUN apt-get update -qq && apt-get install -y postgresql-client
WORKDIR /myapp
# install nodejs(LTS)
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs
# install yarn
RUN npm install --global yarn
# gem
COPY Gemfile* /myapp/
RUN bundle install
# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
# Configure the main process to run when running the image
CMD ["rails", "server", "-b", "0.0.0.0"]
参考:
- Node.jsのインストールコマンド: distributions/README.md at master · nodesource/distributions
PostgreSQLを利用する場合
version: "3.9"
services:
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_USER: # 任意
POSTGRES_PASSWORD: # 必須
POSTGRES_DB: # 任意
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
MySQLを利用する場合
version: "3.9"
services:
db:
image: mysql:8.0
volumes:
- mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 任意
MYSQL_DATABASE: 任意
MYSQL_USER: 任意
MYSQL_PASSWORD: 任意
ports:
- "3306:3306"
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/app
ports:
- "3000:3000"
depends_on:
- db
volumes:
mysql-data: null
2. 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 "$@"
3. Gemfile, Gemfile.lockを生成する
touch Gemfile Gemfile.lock
Gemfileは以下のようにRailsのバージョンを指定する。
source 'https://rubygems.org'
gem 'rails', '~> 6'
コマンドでさくっと。
echo "source 'https://rubygems.org'
gem 'rails', '~> 6'" > Gemfile
4. Railsプロジェクトを作成する
DBはPostgreSQLを利用。
docker-compose run --no-deps web rails new . --force --database=postgresql
※--no-deps
はdocker-compose run
のオプション。依存先のコンテナを起動しない。
MySQLを利用する場合
docker-compose run --no-deps web rails new . --force --database=mysql
APIとして利用する場合は、--api
オプションをつける。APIとして不要なファイルが生成されない。
docker-compose run --no-deps web rails new . --force --database=postgresql --api
5. Dockerイメージをビルド
Gemfileが書き換わったので、Dockerイメージをビルドして作成する。
docker-compose build
6. DB接続情報を設定
config/database.yml
をdocker-compose.yml
で設定したDB情報で書き換える。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ username: <%= ENV["MYSQL_USER"] %>
+ password: <%= ENV["MYSQL_PASSWORD"] %>
+ host: <%= ENV["MYSQL_HOST"] %>
development:
<<: *default
+ database: <%= ENV["MYSQL_DATABASE"] %>
※環境変数へのアクセスは <%= ENV["ENV_NAME"] %>
※ファイルの権限に注意。rootユーザーで作成されているので、通常のユーザーでは書き換える権限がない。VSCodeのRemote Containerでコンテナに入って変更するか、chmod
コマンドで権限を与える(これが適切かどうかは、、、)。
sudo chmod -R o+w .
7. Dockerコンテナを立ち上げる
docker-compose up
以下のようなログが表示されたら、立ち上げ成功。
web_1 | => Booting Puma
web_1 | => Rails 6.1.4.1 application starting in development
web_1 | => Run `bin/rails server --help` for more startup options
web_1 | Puma starting in single mode...
web_1 | * Puma version: 5.4.0 (ruby 3.0.2-p107) ("Super Flight")
web_1 | * Min threads: 5
web_1 | * Max threads: 5
web_1 | * Environment: development
web_1 | * PID: 1
web_1 | * Listening on http://0.0.0.0:3000
web_1 | Use Ctrl-C to stop
8. サーバーに接続する
ブラウザから http://localhost:3000 に接続してRuby on Railsのトップページが表示されたら、OK
Selenium::WebDriver::Error::WebDriverError: Unable to find chromedriver
エラー
システムテストを実行しようとしたら 前提
- minitest (5.15.0)
- capybara (3.36.0)
- selenium-webdriver (4.1.0)
原因
RailsがあるDockerコンテナ内部に ChromeのWebDriverがインストールされていないため。
Dockerfileでインストールしても良いが、システムテスト用のChrome用コンテナを立ち上げることにした。
対応
使用するDockerイメージはselenium/standalone-chrome-debug
にした。
services:
web: # Rails用
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
environment:
MYSQL_USER: huser
MYSQL_PASSWORD: password
MYSQL_HOST: db
MYSQL_DATABASE: app_development
+ SELENIUM_DRIVER_URL: http://selenium_chrome:4444/wd/hub
volumes:
- .:/app
ports:
- "3000:3000"
depends_on:
- db
+ - selenium_chrome
+ selenium_chrome: # システムテスト用
+ image: selenium/standalone-chrome-debug:3.141
+ ports: # ローカルブラウザからアクセスしない場合はポートを開放しなくても良い
+ - "4444:4444"
Seleniumの初期化時にリモートブラウザ(今回用意したコンテナ内部にあるChrome)に接続するように設定する。
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400], options: {
+ browser: :remote,
+ url: ENV.fetch("SELENIUM_DRIVER_URL"),
}
end
いざテストを実行。
rails test test/system/welcomes_test.rb
Capybara starting Puma...
* Version 5.5.2 , codename: Zawgyi
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:40735
[Screenshot Image]: /app/tmp/screenshots/failures_test_-_ページを表示.png
E
Error:
WelcomesTest#test_/_ページを表示:
Selenium::WebDriver::Error::UnknownError: unknown error: net::ERR_CONNECTION_REFUSED
(Session info: headless chrome=94.0.4606.61)
test/system/welcomes_test.rb:6:in `block in <class:WelcomesTest>'
違うエラー。。。(次項へ続く)
Selenium::WebDriver::Error::UnknownError: unknown error: net::ERR_CONNECTION_REFUSED
エラー
システムテストを実行しようとしたら 原因
SeleniumのログをDEBUGレベルに落としてログを確認したところ、ChromeからRailsアプリケーションに接続できていないようであった。
Selenium::WebDriver.logger.level = Logger::DEBUG
先程のテスト実行時のログでは、Puma (アプリケーションサーバー)が127.0.0.1 (つまりRails用コンテナのlocalhost)をlistenしているので、おかしいと気づいた。
Capybara starting Puma...
* Version 5.5.2 , codename: Zawgyi
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:40735
対策
Capybaraにserver_host
というオプションがあり、Capybaraが接続するアプリケーションサーバーのIPアドレスを指定できる。デフォルトのままでは127.0.0.1なので、Chrome用コンテナ内部に接続しようとしてエラーになっていた。(Railsアプリケーションは別のコンテナにある)
# - **server_host** (String = "127.0.0.1") - The IP address Capybara will bind the application server to. If the test application is to be accessed from an external host, you will want to change this to "0.0.0.0" or to a more specific IP address that your test client can reach.
capybara/capybara.rb at master · teamcapybara/capybara
よって、これをRails用コンテナのIPアドレスに指定すればOK。
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400], options: {
browser: :remote,
url: ENV.fetch("SELENIUM_DRIVER_URL"),
}
+ Capybara.server_host = IPSocket.getaddress(Socket.gethostname)
end
これでテストを実行すると、
# rails test test/system/welcomes_test.rb
Capybara starting Puma...
* Version 5.5.2 , codename: Zawgyi
* Min threads: 0, max threads: 4
* Listening on http://172.25.0.4:40833
.
Finished in 2.395570s, 0.4174 runs/s, 0.4174 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
成功!!(Pumaがlistenしているホストも変更されている。)
開発時に便利なツール
Solargraph
コード補完などをしてくれる。
group :development do
# for intellisense
gem 'solargraph'
end
VSCodeの拡張機能は以下。
Ruby Solargraph - Visual Studio Marketplace
bundlerを使っている場合は、設定ファイルに以下を追加。
{
"solargraph.useBundler": true
}
RuboCop
Liner, Formatterツール。
group :development do
# for lint
gem 'rubocop', require: false
gem 'rubocop-rails', require: false
end
VSCodeでは以下のように設定。
{
"ruby.lint": {
"rubocop": true
},
"ruby.format": "rubocop"
}
自動フォーマットを実行するコマンド
rubocop -a
gemがどこにインストールされているのか確認したいとき
下記コマンドで出力される INSTALLATION DIRECTORY
を確認すれば良い。
gem environment