実践で学ぶRuby on rails 〜仮説千本ノック〜

プログラマーとして独立するため日々スキルアップに励んでいます。優れたプログラマは仮説を立てるのがうまい。そこを目指して仮説を立てては検証する日々です!!

AWSを使ったデプロイ〜unicorn起動・アセットファイルのコンパイル〜

アプリケーションサーバunicorn」の起動

EC2で、コードをクローンしたディレクトリに移動した上、

unicorn_rails(ローカルでいう「rails s」)でunicornを起動する。

[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ]
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D

〇bundle exec 〜 

これをつけると、各プロジェクトに設定した通りgemが動作する。

バージョンなどが、想定した通りになる。

 

ただし、これではうまくいきません。

stderrのログを見るように指示が出ています。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D
master failed to start, check stderr log for details

 

INFO、INFOと続き、その次にERRORの行があるので確認しましょう。

するとローカルのmysqlに接続できないとあります。

本番環境のmysqlへの接続したいのに、ローカルの設定のままなのでこのようなエラーが生じます。(database.ymlはローカル設定だが、本番環境のEC2を使っているので、ローカル接続もできない)

よって、database.ymlを本番環境用に設定する。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ less log/unicorn.stderr.log
I, [2016-12-21T04:01:19.135154 #18813]  INFO -- : Refreshing Gem list
I, [2016-12-21T04:01:20.732521 #18813]  INFO -- : listening on addr=0.0.0.0:3000 fd=10
E, [2016-12-21T04:01:20.734067 #18813] ERROR -- : Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/mysql2_adapter.rb:29:in `rescue in mysql2_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/mysql2_adapter.rb:12:in `mysql2_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.3.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:721:in `new_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:765:in `checkout_new_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:744:in `try_to_checkout_new_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:705:in `acquire_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:501:in `checkout'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:364:in `connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:875:in `retrieve_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_handling.rb:128:in `retrieve_connection'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.0.0.1/lib/active_record/connection_handling.rb:91:in `connection'
config/unicorn.rb:36:in `block in reload'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/unicorn-5.1.0/lib/unicorn/http_server.rb:502:in `spawn_missing_workers'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/unicorn-5.1.0/lib/unicorn/http_server.rb:132:in `start'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/unicorn-5.1.0/bin/unicorn_rails:209:in `<top (required)>'
/home/ec2-user/.rbenv/versions/2.5.1/bin/unicorn_rails:23:in `load'
/home/ec2-user/.rbenv/versions/2.5.1/bin/unicorn_rails:23:in `<main>'

 

よって、database.ymlを本番環境用に設定する。

production:
  <<: *default
  database: ~~~(それぞれのアプリケーション名によって異なっています。こちらは編集しないでください)
  username: root
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock

mysql.sock

ソケットに関する設定ファイル。ソケットはmySQLのサーバー、クライアント間通信のインターフェイス

 

今回行ったローカルでの変更を、まずリモートリポジトリへプッシュしましょう。

 

次に、リモートリポジトリ(Github)からサーバ上のアプリへ、その変更を反映させるため、EC2上でリモートリポジトリをpullしましょう。

ローカルでの変更が、リモートリポジトリのmasterブランチに反映されていることが前提。他のブランチへ反映させているなら、masterへマージした上で、pullすること。

[ec2-user@ip-172-31-23-189 <リポジトリ名>] git pull origin master

 

これで、本番環境のMysqlサーバーに接続できるようになったので、EC2上にデータベースを作成(まだ作成してないので、この段階では存在しません)し、マイグレーションまで行います。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ rails db:migrate RAILS_ENV=production

RAILS_ENV=production

 db:create、db:migrateは、モードを指定しないで実行すると開発環境用に動作します。よって、本番環境用のDBを作るには、環境を明示する必要があります。
 
なお、db:createするにはmysqlが動作している必要があります。上記操作でエラーが起きた場合には、mysqlが動作していないことが原因である場合がありますので、
「sudo service mysqld start」コマンドで動かしてみましょう。これで、DBの準備は整いましたので、再度unicornを起動してみましょう。
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D 

 

これで、WEBサーバとしての準備は概ね整いましたので、アクセスしましょう。URLはアドレスとポートを組み合わせて「http://Elastic IP:3000/」となります。

 

ただし、ここではCSSを適用するための準備が整っておらず、CSSが無視された状態でのビューが表示されます。

 

アセットファイルをコンパイルする。

 css、js、imageなど、assetディレクトリの中にある、HTMLの装飾を担当するファイルに対して、アセットパイプラインという仕組みが働いています。

そこで行われる処理は、

 

▫️コンパイル

そのままでは動作しないファイルの拡張子を変換し、ちゃんと動作する形式にする。

.js.cofee→.js

.scss→.css

 

▫️ファイルの連結

開発しやすいように、便宜上分割(便宜上分割していることもアセットパイプラインの仕組みの一部)されていたフォルダに置かれていたファイルを、バラバラだと動作しないため、コンパイル後、一つのファイルに連結する。

 

.jsファイル→application.jsに連結

.cssファイル→aplication.cssに連結

つまり、本番環境では、数ある.jsファイルは、

assets/javascript/〇〇.jsの集合ではなく、

aseets/application.jsとしてまるっと参照されます。

 

開発環境では、フォルダを用途にわけ、ファイルも分割して作成しなければ、とても不便です。

 

逆に、完成してしてしまえば、人間にとっての扱いやすさを維持する必要はなく、動作させやすい形(連結)にするのです。

 

開発環境では、app/assetsの下にある、フォルダ、ファイルが分割されたものが参照され、本番ではpublic/asssets下のフォルダ分けされていないファイルが参照されます。

 

 

 

▫️ファイルの圧縮

予約など、無駄な部分を詰めて容量を減らす

 

 

 

 

▫️ファイルにハッシュ値を付与

上記処理を終えたファイル名にハッシュ値が付与されて長ったらしい名前になる。(編集を加えるたびに異なるハッシュ値が付与されて、別ファイルとして保存されるので、消さないと、古いファイルが増える)なので、画像をコードに書くときの記述方法がかなり開発環境と、本番では異なります。

 

 

開発環境でも、本番環境、どちらでアセットパイプラインは働きますが、開発環境では、HTTPリクエストのたびに仕組みが働き、負荷がかかるので、自動では動かしません。手動で、デプロイ前に実行します。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ rails assets:precompile RAILS_ENV=production

 

つまり、開発環境では、意識しなくても当然にアセットパイプラインが動作して、htmlとcss等が連携して見た目を作ってくれるが、本番環境では、手動で行わない限り、css等は分割されたままで、役割を果たせません。

 

プリコンパイルを実行したら、反映されているか確認するため、サーバーの再起動が必要です。

 

まずは、unicornをプロセスをkillすることで一旦ストップします。

そのために、今動いているプロセスを表示させます。

 

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

 

確認すべきは左から2列目のプロセスIDです。これを指定してkillすることで、ローカルにおけるctr+cと同様に、サーバーを止められます。

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

 

killコマンドでunicornのmasterプロセスを停止させる。

するとmasterから派生したworkerプロセスも停止する。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID>
...

 

コマンド実行しても、このようにmaster、workerプロセスが残っているなら、kill に−9をつけて強制終了する。

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
$ kill -9 [プロセスID]  

 

unicornが停止できたら、再起動しましょう。

このとき、コンパイルしたアセットファイルをRailsが見つけられる(参照)ように、RAILS_SERVE_STATIC_FILES=1を先頭に追加しましょう。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D

 

condig/environments/production.rbに、本番環境における、アセットファイルをRailsがどう参照するのかの設定が書かれています

 

どうやら、デフォルトでは、コンパイルされたアセットファイル(static files)はNGINX等のウェブサーバーが保持するもので、わざわざ、publicフォルダに見にいくものではないとされています。

 

今回は、WEBサーバーにはアセットファイルを持たせておらず、publicディレクトリに持たせているので、Railsがpublicフォルダへファイルを見に行けるようにしたい。

 

コードを見ると、見に行ける場合の条件として、「RAILS_SERVE_STATIC_FILESに値がpresentしている」とある。

 

条件をクリアするために、コマンドで値に1を設定しています。この式の右辺をtrueにしてしまえば、おそらく条件は不要となる。

f:id:Taka0--0:20200522172419p:plain

 

これで、htmlだけでなく、css、js、imageファイルも紐付けた状態でブラウザに表示できるようになっているので、http://Elastic IP:3000/へアクセスする。