修行のために何かを作る話(最初のページ作成で詰まったことメモ)
この話のうち、苦労した所だけ抽出したメモ。
本番環境でbundle installするとGemfile.lockのPLATFORMSが更新されたり別プラットフォーム向けのnokogiriがインストールされたりする
タイトルの通り。スクショは撮り忘れた。
TL; DR
bundle installする前に以下の設定をしておけ。
$ bundle config set force_ruby_platform true
概説
最初のbundle installで作成されたGemfile.lockには、PLATFORMSは以下の通り記載されていた。
# in Gemfile.lock
PLATFORMS
x86_64-darwin-18
これが何かと言うと、Bundlerの設定でbundle installした環境をPLATFORMSに残してくれている。
これは何が嬉しいのかというと、どうやらプラットフォーム毎にコンパイルしなければいけないような内容を含むgemをインストールするとき、PLATFORMSの記載があると「ビルド済(の実行バイナリを含む)gem」をインストールしてくれるようだ。
多分ビルド時間が不要でbundle installの時間が短くなってくれるのが嬉しいんだろう。
そういったgemはどんな感じでGemfile.lockに残るかというと、Railsのデフォルトでインストールされるnokogiriを見ると分かりやすい。
# in Gemfile.lock
nokogiri (1.11.1-x86_64-darwin)
見ての通りプラットフォームの情報がバージョンの後ろにつく。
このGemfile.lockを持つリポジトリを別の環境、例えばAmazon Linux 2の環境でbundle installするとどうなるかというと、linuxプラットフォーム向けのnokogiriが別途インストールされ、Gemfile.lockには別プラットフォームのnokogiriが追記され、PLATFORMSにlinuxが追記される。
(スクショは撮り忘れた)
こうなってしまうと本番環境と開発環境でバージョン管理として差分が出てしまうので取り扱いが大変になってしまいそう。
で、冒頭に記載の通り、これはbundlerの設定で変更が可能。
$ bundle config set force_ruby_platform true
こうすることでPRATFORMSはrubyとなり、bundle install時に必要な場合はソースコードからコンパイルが走るのであった。
この設定は環境変数BUNDLE_FORCE_RUBY_PLATFORMにtrueを設定しても良い。EC2の方はそうした。
anyenv/rbenvを使った本番環境でpumaをsystemd経由で起動するよう設定しようとしたがrubyやらpumaやらbundlerやらが見つからなくて起動に失敗する
TL; DR
rbenvとかanyenvを使っている場合、initの記載があるログインシェルを使うようpuma.serviceを書け。
ExecStart=/bin/bash -lc "puma"
概説
puma公式によるとpumaを起動するときはsystemd経由にすることで自動復旧などいい面があるのでそうするように書いてある。
上記puma公式repoにあったサンプルのコメントを参考に最初に書いたpuma.serviceは以下の通り。
(これ以降のエラーは全て/var/log/messagesをcatして確認した。systemctlコマンドで起動する際エラーになっても標準出力には何も出てくれない。)
# /usr/lib/systemd/system/puma.service
[Unit]
Description=Puma HTTP Server
After=network.target
[Service]
Type=simple
User=webapp
WorkingDirectory=/var/www/blog
ExecStart=/var/www/blog/bin/puma -C /var/www/blog/config/puma.rb ../config.ru
Restart=always
[Install]
WantedBy=multi-user.target
→bin/pumaがnot foundでエラー。binstubがそもそも作られていなかったのでなかったので作成してリトライ。
→puma: /usr/bin/env: ruby: No such file or directoryでエラー。rubyが見つけられていない…なぜ?
以下に従いrbenvのpathを指定してrbenv exec bundle execにする。実際はanyenv経由なので少しパスが違う。
→rbenv: rbenv: version `2.7.2' is not installed (set by /var/www/blog/.ruby-version)でエラー。なんでだ…。
以下を参考にrbenv下のversions配下のbundleを直接指定する。
→bundle: Install missing gem executables with `bundle install`でエラー。依存関係の解消が変?
どうもpuma/anyenv/rbenv/ruby/bundlerの解決が上手く行っていなさそうで、発端はanyenvで解決するはずの諸々が解決できていない事っぽい。
よく考えてみるとanyenvは~/.bashrc内でinitをしていてこれが利用前提。
$ cat .bashrc
# .bashrc
(略)
# environment variable for anyenv
export PATH="$HOME/.anyenv/bin:$PATH"
eval "$(anyenv init -)"
なのでsystemdからの呼び出しだとここの解決が出来ていないことが問題になっていそう…ということで.bashrcが呼び出されるようログインシェル経由で起動する。
# /usr/lib/systemd/system/puma.service
[Unit]
Description=Puma HTTP Server
After=network.target
[Service]
Type=simple
User=webapp
Group=webapp
WorkingDirectory=/var/www/blog
ExecStart=/bin/bash -lc "puma"
Restart=always
[Install]
WantedBy=multi-user.target
通ったよー!!!めっちゃ疲れた。
# in /var/log/messages
Feb 13 17:05:17 ip-xxx-xxx-xxx-xxx systemd: Reloading.
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx systemd: Started Puma HTTP Server.
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx systemd: Starting Puma HTTP Server...
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] Puma starting in cluster mode...
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Puma version: 5.2.1 (ruby 2.7.2-p137) ("Fettisdagsbulle")
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Min threads: 3
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Max threads: 5
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Environment: production
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Master PID: 8399
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Workers: 2
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Restarts: (✔) hot (✖) phased
Feb 13 17:05:20 ip-xxx-xxx-xxx-xxx bash: [8399] * Preloading application
Feb 13 17:05:21 ip-xxx-xxx-xxx-xxx bash: [8399] * Listening on unix:///var/www/blog/tmp/sockets/puma.sock
Feb 13 17:05:21 ip-xxx-xxx-xxx-xxx bash: [8399] Use Ctrl-C to stop
Feb 13 17:05:21 ip-xxx-xxx-xxx-xxx bash: [8399] - Worker 0 (PID: 8819) booted, phase: 0
Feb 13 17:05:21 ip-xxx-xxx-xxx-xxx bash: [8399] - Worker 1 (PID: 8824) booted, phase: 0