Rails(Docker)をProductionモードで起動してみる (CI/CDまでの道⑤)
はじめに
前回は本番環境用にdocker-compose.production.yml
を作成して、Nginx
を導入しました。そこでEC2デプロイにすでにチャレンジしてなんとか成功したのですが、そこでRails
のProductionモード
を知り、その設定が必要だったので今回は設定をしていきます。
いまのdocker-compose.production.ymlでは本番環境では動かすことができませんでした。
作成に利用するリポジトリはこちらになります。
CI/CDの道シリーズ
- Rails6+MySQLのDocker環境構築 (CI/CDまでの道①)
- DockerにWebpacker環境構築(jquery, Bootstrap5, Vue) (CI/CDまでの道②)
- Rails(Docker)に必要なGemを追加する (CI/CDまでの道③)
- Rails(Docker)にNginxを導入する (CI/CDまでの道④)
- Rails(Docker)をProductionモードで起動してみる (CI/CDまでの道⑤)
環境
- WSL2 (Ubuntu20.04)
- Docker 20.10.9
- docker-compose 1.29.1
- Git 2.25.1
- VSCode
本番環境で起動するために知るべきこと
まず本番環境で起動するために知っておくべきことをまとめておきます。
DBに関してはRDS
というAWSのデータベースを利用するため本来であればDBコンテナに関するものは一切必要なくなります。ですが、今回はローカルで起動するため、次回削除して実際にRDS
を利用します。また、それにともなって次回database.yml
に修正を加えます。
Webpacker
は本番では利用しません。WebpackerはJavascriptやCSSをコードを書いてくれたらすぐにコンパイルして読み込んでくれる用途で利用しています。ですので本番では開発することはないので最初にRailsのコンパイルコマンドを利用してすべてコンパイルすればそれ以降コンパイルする必要はなくなります。ということで不要となりますのでdocker-compose.production.yml
からは消します。
Nginx
はRailsの前に置くことでアクセス負荷に対応できたり、高速にViewを返したりすることができるため本番環境では必要になります。開発環境(docker-compose.yml)では必要ないので入れていません。
この点を意識してProductionモード
の起動に挑戦します。
ファイルの修正
上で説明した考慮点を踏まえてファイル編集をしていきます。
まずはdocker-compose.production.yml
を修正します。
version: "3.9"
services:
rails:
build: .
container_name: rails
command: bundle exec puma -C config/puma.rb -e production
volumes:
- .:/myapp
- public-data:/myapp/public
- tmp-data:/myapp/tmp
- log-data:/myapp/log
- /myapp/node_modules
env_file:
- .env
depends_on:
- db
user: root
db:
image: mysql:8.0.27
container_name: db
environment:
TZ: Asia/Tokyo
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
ports:
- "3306:3306"
volumes:
- db:/var/lib/mysql
web:
build:
context: containers/nginx
volumes:
- public-data:/myapp/public
- tmp-data:/myapp/tmp
ports:
- 80:80
depends_on:
- rails
volumes:
db:
driver: local
public-data:
tmp-data:
log-data:
修正は大きく4つです。
- Webpacker関連はすべて削除
- Railsのコマンドに
-e production
を追加(Productionモードで起動) - volumesの不要だったものを削除(bundleは不要だったので消しておきます)
- Railsをrootユーザーで起動(コンテナが作成したファイルを編集することがないのでrootにする(compile時のエラー対策))
起動
では実際にProductionモードで起動してみます。
$ docker-compose -f docker-compose.production.yml build
次にコンパイルをproductionモードで行います。最初にこのコンパイルをおこなうことでJavascriptやCSSが読み込めるようになります。
$ docker-compose -f docker-compose.production.yml run rails rails assets:precompile RAILS_ENV=production
# エラーがでたら以下の対処
ここではdocker run
でコンテナ内でコンパイルコマンドを実行しています。これはコンテナ内で実行することも可能ですが、Railsコンテナが立ち上がるときにpublic/packs/
にあるコンパイル済みファイルを読み込むため、コンテナ内でコマンドを実行したら一度落としてから立ち上げる必要があります。それは手間なのでdocker run
を利用しています。
※ コンパイルでエラーが発生したら
以下のようなエラーが発生するかもしれないです。
rails aborted!
ArgumentError: Missing `secret_key_base` for 'production' environment, set this string with `bin/rails credentials:edit`
/myapp/config/environment.rb:7:in `<main>'
/myapp/bin/rails:5:in `<top (required)>'
/myapp/bin/spring:10:in `block in <top (required)>'
/myapp/bin/spring:7:in `<top (required)>'
Tasks: TOP => environment
(See full trace by running task with --trace)
ERROR: 1
productionモードではディレクトリ内にconfig/master.key
とconfig/credentials.yml
というファイルが必要になります。これは鍵と鍵穴のような関係で暗号と複合を行っているファイルです。
以下の記事に詳しい話があるので気になる方はみてください。
【Rails】世界で一番わかりやすい!!「credentials.yml.enc」+「master.key」使い方徹底攻略!
master.key
はgitignore
の対象となるのでgit cloneでは手に入らないです。ですので両方がなくエラーになることもあります。
今回リポジトリからcloneしてきた方は/config/credentials.yml
を削除してから以下の手順でファイル作成を行います。
まずはファイル作成のために開発モードでRailsコンテナを起動します。
docker-compose.production.yml
を一時修正します。
version: "3.9"
services:
rails:
build: .
container_name: rails
# command: bundle exec puma -C config/puma.rb -e production
command: bundle exec puma -C config/puma.rb
(省略)
Railsだけを起動して必要なファイルを生成します。(ローカルにpublic/credentials.yml.enc
、public/master.key
がある場合は削除します)
$ docker-compose -f docker-compose.production.yml up rails
# 別のターミナルを開く
$ docker exec -it rails sh
# ファイルの生成
$ EDITOR="vi" rails credentials:edit
# :wqでvimを抜ける
public/credentials.yml.enc
とpublic/master.key
ができました。このファイルはEC2デプロイに利用しますのでローカルに保存しておいてくださいさい。
コンテナを落とします。
# ctril + Cで落とす
# または
# $ docker-compose -f docker-compose.production.yml down
docker-compose.production.yml
を先ほどの状態に戻します。
version: "3.9"
services:
rails:
build: .
container_name: rails
command: bundle exec puma -C config/puma.rb -e production
失敗したコマンドを再度実行します。
docker-compose -f docker-compose.production.yml run rails rails assets:precompile RAILS_ENV=production
(省略)
Entrypoint mini-css-extract-plugin = *
[0] ./node_modules/css-loader/dist/cjs.js??ref--3-1!./node_modules/postcss-loader/src??ref--3-2!./node_modules/sass-loader/dist/cjs.js??ref--3-3!./app/javascript/stylesheets/application.scss 620 KiB {0} [built]
+ 1 hidden module]
うまくいきました。
DBを作成する
話を戻して環境構築を行っていきます。
まずはproduction
で作成するときのDBの設定を変更します。config/database.yml
のproduction
をいかに修正します。
(省略)
production:
<<: *default
database: myapp_production
username: root # 修正
password: <%= ENV["DB_PASSWORD"] %> # 修正
DB作成をdocker run
で作成します。コンパイルとDB作成のコマンドをあとでshellにまとめてまとめて実行するようにしようと思うのでコンテナの中での実行ではなくdocker run
を利用しています。
# db作成
$ docker-compose -f docker-compose.production.yml run rails rails db:create RAILS_ENV=production
# エラーが発生したら以下
DB作成でエラーが発生したら
私の環境では以下のエラーが発生します。
jinwatanabe@DESKTOP-4DGUR4Q:~/workspace/CICD_Road/chapter05$ docker-compose -f docker-compose.production.yml run rails rails db:create RAILS_ENV=production
Creating chapter05_rails_run ... done
/usr/local/bundle/gems/spring-4.0.0/lib/spring/application.rb:101:in `block in preload': Spring reloads, and therefore needs the application to have reloading enabled.
Please, set config.cache_classes to false in config/environments/production.rb.
(RuntimeError)
from /usr/local/bundle/gems/railties-6.1.4.4/lib/rails/initializable.rb:32:in `instance_exec'
(省略)
ここで注目してほしいのは
Please, set config.cache_classes to false in config/environments/production.rb.
ここの部分です。config/environments/production.yml
のcache_classes
をfalse
にしてくださいと言われています。修正していきます。
require "active_support/core_ext/integer/time"
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = false # 修正
(省略)
config.cache_claseesをtureからfalseに変更しました。
DB作成コマンドを再度実行します。
# 変更をコンテナに適応するためにビルドしなおす
$ docker-compose -f docker-compose.production.yml build
# DB作成
$ docker-compose -f docker-compose.production.yml run rails rails db:create RAILS_ENV=production
成功しました
Created database 'myapp_production'
Productionモードで起動する
それではコンテナを起動していきます。
$ docker-compose -f docker-compose.production.yml up
loclahost/test
にアクセスしてJavascriptやCSSが効いていれば成功です。
私はJavascriptやCSSが効かずにTemplate errorがでて苦戦しました。(/myapp/log/production.ymlでログが見れます)
またproductionモードなのでlocalhost
でyah Ruby on Rails(万歳)
は見れなくなっています。
/test
がIPの後ろに必要になるので注意してください(これでエラーが起きていると誤解しました)
おわりに
作成したものはこちらのリポジトリに用意しています。(cloneして起動する場合はmaster.keyとcredentials.yml.encをpublic/にいれる必要があります)
Productionモードでの起動ができるようになりました。
次回はAWSのインフラを手作業で一から構築してみようと思います。その次には初めてのデプロイの記事を作成する予定です。
Discussion