Railsで始めるsystemd入門

6 min read読了の目安(約5500字

pumaから-dオプションが消されて

puma使っていますか?

pumaから-dオプションが消されて1年以上経ちますが(新参者なので当時のことは知らない)、今まではpuma-daemonを使って起動をしておりました。

ですが、今日からはsystemdを使って起動しようと思います。

そもそもなぜ削除されたか

https://github.com/puma/puma/issues/1938
https://github.com/puma/puma/issues/1983

どうやらdeamonオプションでの起動がうまく行かないケースがあるらしい。
pumaのコマンド実行後、デーモン化が完了する前にSIGHUPを送信してしまっており、そのおかげでデーモン化しようとしていたプロセスが中断されている。

みたいな感じ。

こんな原因で、削除されたわけですが、当然そこらのコマンドを愛用していた方々はたくさんいたわけでそれに対してpuma-daemonなんていう-dオプションを復活できる(実際にはpuma.rbでdemonaizeメソッドが使えるようになる)gemが作成されたわけでしょう。

でも、daemon化なんて環境に依存するんだからそれぞれでやったほうが良いでしょう。

https://github.com/puma/puma/blob/master/docs/systemd.md

systemdを使ってみよう

必要なのは設定ファイルとsd_notifyというGEMだけなので気軽に作ってみよう。

設定ファイルを準備

/etc/systemd/system/puma.service
[Unit]
Description=Puma HTTP Server
After=network.target

[Service]
Type=notify
WatchdogSec=10
# 実行ユーザー
User=app-user
# 実行ディレクトリ
WorkingDirectory=/var/www
# 環境変数。必要なものを突っ込む
Environment="PUMA_DEBUG=1"
# Railsに必要なパス達の例。環境に合わせて調整しましょう。
Environment="PATH=/usr/bin:/usr/local/sbin:/root/.rbenv/shims:/root/.rbenv/bin:/root/.nvm/versions/node/v12.16.2/bin:/root/.local/bin:/root/bin"
# 起動コマンド
ExecStart=/home/app-user/.rbenv/shims/bundle exec puma -e production
Restart=always

[Install]
WantedBy=multi-user.target

GEMインストール

sd_notifyはsystemdへ起動完了通知を行うために必要です。様々な言語で存在するようです。
入れていないといつになってもstartコマンドが終わりません。

Gemfile
gem "sd_notify"

起動コマンドたち

# 設定ファイルの再読み込み
systemctl daemon-reload

# 自動起動設定
systemctl enable puma.service

# 起動
systemctl start puma.service

# ステータス確認
systemctl status puma.service

# 再起動
systemctl restart puma.service

# 停止
systemctl stop puma.service

注意点①

systemdで実行する場合、ユーザーを指定しても.bash_profileなどは読み込まれないので必要なものは設定ファイルの`[Service]に書き込む必要がある。

注意点②

環境変数のダブルクオートの場所
NGは感覚的に行けそうだなーと思いそうだけどうまく行かなかった。必要なければくくらなければOK。

NG

Environment=REDIS_PATH="hoge.fuga.ng.0001.apne1.cache.amazonaws.com"

OK

Environment="REDIS_PATH=hoge.fuga.ng.0001.apne1.cache.amazonaws.com"

起動してみる

start->status->stop->status を実行したときの出力です。

$ sudo systemctl start puma.service
$ sudo systemctl status puma.service
● puma.service - Puma HTTP Server
   Loaded: loaded (/etc/systemd/system/puma.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2021-05-02 16:59:37 JST; 4s ago
  Process: 5563 ExecStop=/bin/kill -TERM $MAINPID (code=exited, status=0/SUCCESS)
 Main PID: 5570 (bundle)
   CGroup: /system.slice/puma.service
           ├─5570 puma 5.2.2 (unix:///var/www/app/tmp/sockets/puma.sock) [app]
           ├─5600 puma: cluster worker 0: 5570 [app]
           └─5601 puma: cluster worker 1: 5570 [app]

May 02 16:59:32 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] *  Max threads: 5
May 02 16:59:32 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] *  Environment: production
May 02 16:59:32 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] *   Master PID: 5570
May 02 16:59:32 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] *      Workers: 2
May 02 16:59:32 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] *     Restarts: () hot () phased
May 02 16:59:32 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] * Listening on unix:///var/www/app/tmp/sockets/puma.sock
May 02 16:59:32 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] Use Ctrl-C to stop
May 02 16:59:37 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] - Worker 0 (PID: 5600) booted, phase: 0
May 02 16:59:37 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5570]: [5570] - Worker 1 (PID: 5601) booted, phase: 0
May 02 16:59:37 ip-10-1-100-152.ap-northeast-1.compute.internal systemd[1]: Started Puma HTTP Server.
$ sudo systemctl stop puma.service
$ sudo systemctl status puma.service
● puma.service - Puma HTTP Server
   Loaded: loaded (/etc/systemd/system/puma.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

May 02 17:10:21 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5863]: [5863] * Listening on unix:///var/www/app/tmp/sockets/puma.sock
May 02 17:10:21 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5863]: [5863] Use Ctrl-C to stop
May 02 17:10:24 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5863]: [5863] - Worker 0 (PID: 5893) booted, phase: 0
May 02 17:10:24 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5863]: [5863] - Worker 1 (PID: 5894) booted, phase: 0
May 02 17:10:24 ip-10-1-100-152.ap-northeast-1.compute.internal systemd[1]: Started Puma HTTP Server.
May 02 17:10:33 ip-10-1-100-152.ap-northeast-1.compute.internal systemd[1]: Stopping Puma HTTP Server...
May 02 17:10:33 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5863]: [5863] === puma shutdown: 2021-05-02 17:10:33 +0900 ===
May 02 17:10:33 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5863]: [5863] - Goodbye!
May 02 17:10:33 ip-10-1-100-152.ap-northeast-1.compute.internal bundle[5863]: [5863] - Gracefully shutting down workers...
May 02 17:10:34 ip-10-1-100-152.ap-northeast-1.compute.internal systemd[1]: Stopped Puma HTTP Server.

うまくいった。
よかったね!

まとめ

普段何も考えずに systemctl start nginx.service とか使っていたわけですが多少理解が進んだのでよかったです。
設定ファイルいくつか準備すれば環境別にもできるしGood!

daemonの語源

ちなみにdaemonってなんとなーく、女神転生のインキュバスみたいなのをいっつもイメージして目に見えないなんかが動作しているからデーモンなのかなーって思ってたけど、元は「マクスウェルの悪魔」という物理学の思考実験が由来らしい。

https://gigazine.net/news/20180206-unix-linux-daemon/

マクスウェルの悪魔についてわかりやすく解説してた動画が面白かった。

https://www.youtube.com/watch?v=AFx6CqYtbwQ