試した際のメモ。
Developmentで動かすことを想定したものなのでProductionは微妙に違うと思う。
試した環境はVMPlayerにインストールしたCentOS7でRubyは2.4.2をrbenvを使ってインストール。
Railsのバージョンは5.1.4でPumaは3.11.0。
起動するアプリは/var/local/rails配下にSampleという名前で設置されているものとする。
1. 起動用のスクリプトの準備
以下のようなファイルを用意する。
ファイル名は何でもいいけど拡張子は.serviceであることに注意。
[Unit]
Description=Puma Application Server
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/var/local/rails/Sample
Environment="RAILS_ENV=development"
Environment="PORT=3000"
ExecStart=/usr/local/rbenv/versions/2.4.2/bin/bundle exec puma -C /var/local/rails/Sample/config/puma.rb
TimeoutSec=300
Restart=always
[Install]
WantedBy=multi-user.target
スクリプトで呼び出すbundleはSampleのbin/bundleではなく、システム側に入っているものをフルパスで指定すること。
Userは今回はrootで試しているけど、必要に応じて変更すること。
2. 起動
OSのsystemctlコマンドを使って起動する。
$ chmod +x /etc/systemd/system/puma.service
$ systemctl start puma.service
$ systemctl status puma.service
● puma.service - Puma Application Server
Loaded: loaded (/etc/systemd/system/puma.service; disabled; vendor preset: disabled)
Active: active (running) since 火 YYYY-MM-DD HH:mm:ss JST; 7s ago
Main PID: 13719 (bundle)
CGroup: /system.slice/puma.service
└─13719 /var/local/rails/Sample/vendor/bundle/ruby/2.4.0/bin/puma -C /var/local/rails/Sample/config/puma.rb
MM DD HH:mm:ss centos7.local systemd[1]: Started Puma Application Server.
3. 遭遇したトラブル
Sampleで使うgemをvender/bundleにインストールしている場合は、上記のスクリプトで問題なかった。
しかしvender/bundleにインストールしていない場合は以下のようなエラーで起動しない。
一瞬だけ起動するが、すぐに落ちるといったほうがいいかも?
$ systemctl status puma.service
● puma.service - Puma Application Server
Loaded: loaded (/etc/systemd/system/puma.service; disabled; vendor preset: disabled)
Active: failed (Result: start-limit) since 火 YYYY-MM-DD HH:mm:ss JST; 1min 20s ago
Process: 13796 ExecStart=/usr/local/rbenv/versions/2.4.2/bin/bundle exec puma -C /var/local/rails/Sample/config/puma.rb (code=exited, status=127)
Main PID: 13796 (code=exited, status=127)
MM DD HH:mm:ss centos7.local systemd[1]: puma.service: main process exited, code=exited, status=127/n/a
MM DD HH:mm:ss centos7.local systemd[1]: Unit puma.service entered failed state.
MM DD HH:mm:ss centos7.local systemd[1]: puma.service failed.
MM DD HH:mm:ss centos7.local systemd[1]: puma.service holdoff time over, scheduling restart.
MM DD HH:mm:ss centos7.local systemd[1]: start request repeated too quickly for puma.service
MM DD HH:mm:ss centos7.local systemd[1]: Failed to start Puma Application Server.
MM DD HH:mm:ss centos7.local systemd[1]: Unit puma.service entered failed state.
MM DD HH:mm:ss centos7.local systemd[1]: puma.service failed.
journalctl -xe
というコマンドを使って原因を調べる以下のようなエラーが出ていた。
MM DD HH:mm:ss centos7.local bundle[13796]: bundler: command not found: puma
MM DD HH:mm:ss centos7.local bundle[13796]: Install missing gem executables with `bundle install`
どうやらpumaを見つけられなくて失敗した模様。
それもそのはずで、vender/bundleにgemをインストールしていればpumaも以下の場所に入るので、おそらくこれを使っていると思われる。
$ ls -al /var/local/rails/Sample/vendor/bundle/ruby/2.4.0/bin/
合計 44
drwxr-xr-x 2 root root 148 MM DD HH:mm .
drwxr-xr-x 9 root root 104 MM DD HH:mm ..
-rwxr-xr-x 1 root root 599 MM DD HH:mm byebug
-rwxr-xr-x 1 root root 599 MM DD HH:mm listen
-rwxr-xr-x 1 root root 611 MM DD HH:mm nokogiri
-rwxr-xr-x 1 root root 587 MM DD HH:mm puma
-rwxr-xr-x 1 root root 593 MM DD HH:mm pumactl
-rwxr-xr-x 1 root root 591 MM DD HH:mm rackup
-rwxr-xr-x 1 root root 605 MM DD HH:mm rails
-rwxr-xr-x 1 root root 587 MM DD HH:mm rake
-rwxr-xr-x 1 root root 599 MM DD HH:mm spring
-rwxr-xr-x 1 root root 617 MM DD HH:mm sprockets
-rwxr-xr-x 1 root root 587 MM DD HH:mm thor
しかしvender/bundleにインストールしていない場合はpumaは存在しないからエラーになる。
4. 対応策
原因はわかったけどじゃあどうすれば良いのかと言うと、起動スクリプトでフルパスで使っているbundleと同じディレクトリにpumaがいるはずなのでそれをフルパスで指定するとうまくいく。
[Unit]
Description=Puma Application Server
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/var/local/rails/Sample
Environment="RAILS_ENV=development"
Environment="PORT=3000"
ExecStart=/usr/local/rbenv/versions/2.4.2/bin/bundle exec /usr/local/rbenv/versions/2.4.2/bin/puma -C /var/local/rails/Sample/config/puma.rb
TimeoutSec=300
Restart=always
[Install]
WantedBy=multi-user.target
pumaをフルパスで指定するように修正して再挑戦。
$ systemctl daemon-reload
$ systemctl start puma
$ systemctl status puma
● puma.service - Puma Application Server
Loaded: loaded (/etc/systemd/system/puma.service; disabled; vendor preset: disabled)
Active: active (running) since 火 YYYY-MM-DD HH:mm:ss JST; 3s ago
Main PID: 13840 (bundle)
CGroup: /system.slice/puma.service
└─13840 puma 3.11.0 (tcp://0.0.0.0:3000) [Sample]
MM DD HH:mm:ss centos7.local systemd[1]: Started Puma Application Server.
MM DD HH:mm:ss centos7.local systemd[1]: Starting Puma Application Server...
MM DD HH:mm:ss centos7.local bundle[13840]: Puma starting in single mode...
MM DD HH:mm:ss centos7.local bundle[13840]: * Version 3.11.0 (ruby 2.4.2-p198), codename: Love Song
MM DD HH:mm:ss centos7.local bundle[13840]: * Min threads: 5, max threads: 5
MM DD HH:mm:ss centos7.local bundle[13840]: * Environment: development
うまくいった模様。
今回のトラブルに関しては、VMplayerを入れているPCの都合上、グローバル(システム側)に入れてあるものを利用するようにしているrailsアプリを、vender/bundleにgemがインストールされていることが前提と思われるスクリプトがそのままでも動くでしょと思ったのが良くなかった。