Discord のボイスチャンネルに人が集まったら Slack に通知する Bot を作りました。
この記事では、その Bot を systemd で常駐させて24時間動かす方法を書きます。プログラムの詳細は GitHub に置いてあるので、よければ見てください。
はじめに
node.jsはjavascriptの実行環境であり、これを使うことで簡単にプログラムを動作させることができます。しかし、ただnode ~.jsと実行するだけでは、そのターミナルを開いているときしか実行されません。
そこで、systemdを用いることで、24時間365日動かす方法を説明していきます。
他の候補との比較
代表的な3つを比べます。
| 方法 | ログアウトで消えない | 再起動で復活 | クラッシュで復活 | 追加インストール |
|---|---|---|---|---|
node bot.js のまま |
× | × | × | 不要 |
| Docker | ○ | ○ | ○ | 要(Docker) |
| systemd | ○ | ○ | ○ | 不要(標準搭載) |
node bot.js をそのまま実行
一番素朴な方法です。プログラムを書いたら誰もが最初にやる動かし方ですが、ターミナルを閉じたり SSH を切ったりすると止まります。サーバーを再起動しても上がってこず、クラッシュしても復帰しません。常駐には向きません。
Docker
アプリを実行環境ごとコンテナに閉じ込めて動かす仕組みです。コンテナには実行に必要なものが全部入っているので、どのマシンに持っていっても同じように動きます。
ただし今回は、1台のサーバーで Bot を常駐させたいだけで、いろいろな環境に持ち運びたいわけではありません。Docker の一番の強みを使わないので、この用途ではあまり役には立たないでしょう。さらに、Docker 自体のインストールも必要になります。
systemd
今回使った方法です。Linux に最初から入っている仕組みなので追加インストールが要りません。ログアウトでも再起動でもクラッシュでも復帰し、ログも自動で集約されます。Linux サーバーで常駐 Bot を1個動かすなら、これが一番手軽だと思います。
具体例
systemd に常駐させたいプログラムを教えるには、「ユニットファイル」という設定ファイルを書きます。今回は次のような vc-mihari.service を用意しました。
[Unit]
Description=vc-mihari - Discord voice channel headcount to Slack
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/vc-mihari
ExecStart=/usr/bin/node --env-file=.env bot.js
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
各行が何をしているかを見ていきます。
[Unit] セクション(サービスの説明と起動順序)
-
Description=… サービスの説明。systemctl statusなどで表示される名前です。 -
After=network-online.target… ネットワークが使えるようになった後に起動する、という順序の指定です。この Bot は Discord に接続するので、ネットワークより先に起動すると失敗します。 -
Wants=network-online.target… ネットワークの準備を要求します。After=と組で使います。
[Service] セクション(何をどう動かすか)
-
Type=simple… 起動したプロセスがそのまま本体、という一番基本の型です。 -
User=your-user… このユーザーの権限でプロセスを動かします。 -
WorkingDirectory=/path/to/vc-mihari… このディレクトリに移動してからコマンドを実行します。--env-file=.envの.envはここからの相対パスで探されます。 -
ExecStart=… 実際に実行するコマンドです。nodeを絶対パス(/usr/bin/node)で書いている点に注意してください。 -
Restart=always… プロセスが死んだら必ず再起動します。 -
RestartSec=10… 再起動するまで10秒待ちます。
[Install] セクション(自動起動の設定)
-
WantedBy=multi-user.target…systemctl enableしたときに、通常のサーバー起動状態でこのサービスを有効にする、という指定です。これがあることで、サーバーを再起動しても自動で立ち上がります。
User と WorkingDirectory、ExecStart のパスは自分の環境に合わせて書き換えてください。node のパスは which node で確認できます。
ここで説明したのは一部だけです。各項目にはもっと多くの選択肢があり、詳しくは man systemd.service や man systemd.unit で読めます。
実行例
書いたユニットファイルを systemd に設置して、動かしていきます。
起動方法
ユニットファイルを systemd が読む場所(/etc/systemd/system/)にコピーします。
sudo cp vc-mihari.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now vc-mihari
-
cp… ユニットファイルを所定の場所に置きます。 -
daemon-reload… 新しく置いた(または変更した)ユニットファイルを systemd に読み直させます。これを忘れると変更が反映されません。 -
enable --now… サービスを有効化して、同時に起動します。enableは「サーバー起動時に自動で立ち上げる設定」、--nowは「今すぐ起動する」という意味です。この2つは別で、startだと今回だけ起動、enableだけだと次回起動時から、になります。
確認方法
ちゃんと動いているかを確認します。
systemctl status vc-mihari
journalctl -u vc-mihari -f
-
systemctl status vc-mihari… サービスの状態を表示します。active (running)と緑色で出れば動いています。設定ミスなどで起動に失敗しているとfailedと赤字で表示されます。 -
journalctl -u vc-mihari -f… このサービスのログを表示します。-uでユニットを指定し、-fで新しいログが出るたびに追記表示します(tail -fと同じ動きです。Ctrl+Cで抜けても、サービスは止まりません)。
ログについては後の「ログ」の節でもう少し詳しく触れます。
終了方法
止め方には2種類あります。
1つ目
sudo systemctl stop vc-mihari # 今動いているプロセスを止める
-
stop… 今動いているサービスを止めます。ただしこれは一時停止で、サーバーを再起動すると自動で立ち上がってきます。
2つ目
sudo systemctl disable vc-mihari # 自動起動をやめる
-
disable… 自動起動を無効にします。今動いているプロセスはそのままです。
完全に止めたいなら両方必要です。
まとめて行う disable --now もあります。
sudo systemctl disable --now vc-mihari
さらにサービス自体を消すなら、ユニットファイルを削除して読み直します。
sudo systemctl disable --now vc-mihari
sudo rm /etc/systemd/system/vc-mihari.service
sudo systemctl daemon-reload
まとめ
いかがでしたでしょうか。
.serviceの書き方やsystemctl関連のコマンドは覚えにくく、見るだけでもいまいちわかりにくいので、保存用としてこの記事を書きました。これを読んでくれた方のなんらかの助けになれば嬉しいです。
参考文献
