Un nouveau monde parfumé

香り立つ備忘録

node.js with nvm with systemd

先のこたつ記事の補足というか何というか

サラッと Hubot を常駐と書きましたが、当然そのサービスの自動起動には systemd を使いたいですね? 使いたいですね? 使いましょう。

systemd 氏は実行ユーザーなんかも指定できるわけですが、環境変数の設定までは面倒を見てくれないので、そのへんをやっていく必要があります。

nvm でインストールしたお好きなバージョンの node で Unit ファイルを書くと、おおよそ次のような感じになります。

[Unit]
Description=Hoge
Requires=network.target
After=network.target

[Service]
Type=simple
WorkingDirectory=/path/to/application
User=<user>

Environment=ENV=production

ExecStart=/home/<user>/.nvm/versions/node/<version>/bin/node <mainfile>.js

[Install]
WantedBy=multi-user.target

kotatsubot の場合は次のようになっています。

/etc/systemd/system/kotatsubot.service

[Unit]
Description=KotatsuBot
Requires=network.target
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/kotatsu/kotatsubot
User=kotatsu

Restart=always
RestartSec=10

Environment=PATH=/home/kotatsu/.nvm/versions/node/v6.9.1/bin HUBOT_SLACK_TOKEN=hogehoge

ExecStart=/home/kotatsu/kotatsubot/bin/hubot --name kotatsubot -a slack -l kotatsu

[Install]
WantedBy=multi-user.target

Note that, ExecStart の1つめの実行ファイル名に記述できるのはフルパスのみです。$PATH も見てくれないし変数も展開してくれない。甘えるな。.js はフルパスじゃなくて良いの だって WorkingDirectory してるから

/usr/local/nvm なんかにシステムワイドに nvm をインストールしている場合もほぼ同じ方法が取れるはずです。

この方法だと nvm の設定によらずバージョンが固定されてしまうじゃないかという議論*1はあるのですが、僕はむしろ実行バージョンが固定されない方がヤなのでこの方法をとっています。あと ExecStart からラッパースクリプト呼ぶの好きじゃないんですよね(原理主義)。bin/hubot だってラッパーじゃないかと言われると返す言葉がありませんが。

なんなら bin/hubot に1行 . /home/user/.nvm/nvm.sh と書き足すのもいいかと思います。

以上、よき systemd ライフを。