Node.js + forever はアップデートにご注意を
- 今回は、Node.js をアップデートしたら予期せぬトラブルを経験したので対処方法を紹介します。これまで、Node.js アプリケーションをデーモン化(永続化) するため、forever モジュールを使っていました。また、Linux起動時にforever も同時に開始したかったので、systemd でforever を自動起動させていました。
- トラブルのきっかけは、Node.js の脆弱性対策です。Node.js を最新バージョンへアップデート後に以下のWarning メッセージが出力され、Linux起動時にforever が動作しません。
- 原因は、Node.js 14.x 以降にアップグレードすると、forever モジュールに非対応となる様です。
forever: #033[33mwarn#033[39m: --minUptime not set. Defaulting to: 1000ms forever: #033[33mwarn#033[39m: --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms forever: (node:1221) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency forever: (Use `node --trace-warnings ...` to show where the warning was created) forever: (node:1221) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency
ステップ1. forever からsystemd 管理に移行する
- Node.js アプリケーションのデーモン化(永続化) はforever モジュールを使わなくとも、systemd だけで実現できました。
Node.js の停止
- systemd に foreverを開始するための “app.service” サービスを登録していると仮定します。
- Node.js を停止するため、forever コマンドでアプリケーションを停止、systemctl コマンドでサービスを停止します。
# forever stopall # systemctl stop app.service # forever list →「info: No forever processes running」が表示されることを確認する # systemctl status app.service → 「Active: inactive (dead)」が表示されることを確認する
systemd の設定変更
- 以下変更前の systemd のユニットファイルです。
/etc/systemd/system/app.service [Unit] Description=Node.js Application After=multi-user.target systemd-update-utmp-runlevel.service [Service] Type=forking User=root WorkingDirectory=/home/ec2-user/node ExecStart=/usr/bin/forever start app.js KillMode=process Restart=on-failure RestartSec=60s [Install] WantedBy=multi-user.target
# vi /etc/systemd/system/app.service
- 以下変更後の systemd のユニットファイルです。Node.js アプリケーションを常時起動させるため、「Restart=always」を設定します。「Restart=on-failure」を指定しない理由は、Node.js が正常終了した際に起動しないからです。
/etc/systemd/system/app.service [Unit] Description=Node.js Application After=multi-user.target systemd-update-utmp-runlevel.service [Service] Type=simple User=root WorkingDirectory=/home/ec2-user/node/ ExecStart=/usr/bin/node app.js KillMode=process Restart=always [Install] WantedBy=multi-user.target
Node.js の起動
- systemctl コマンドでサービスを起動します。
- サービス起動後、forever プロセスは存在せず、node プロセスが存在することを確認できます。
# systemctl daemon-reload # systemctl start app.service # systemctl status app.service → 「Active: active (running)」が表示されることを確認する # ps aux | grep node | grep -v grep root 3199 2.1 1.0 976220 39280 ? Ssl 06:17 0:00 /usr/bin/node app.js → /usr/bin/node プロセスが存在することを確認する
ステップ2. Node.js を最新にアップデートする
Node.js のアップデート
- libuvのバージョンが 1.43.0 未満の場合、libuvを事前にアップデートします。libuvをアップデート後、バージョンが 1.43.0 以上、取得先のリポジトリが @epel であることを確認します。
- Node.js のアップデートは、yum update nodejs にて行います。Node.js をアップデート後、Node.jsのバージョンが更新されたことを確認します。
# systemctl stop app.service # yum list installed | grep libuv libuv.x86_64 1:1.23.2-1.amzn2.0.2 @amzn2-core # yum update --disablerepo='*' --enablerepo=epel libuv # yum list installed | grep libuv libuv.x86_64 1:1.44.2-1.el7 @epel # node -v v6.17.1 # yum update nodejs # node -v v16.18.1
Node.js の起動
- systemctl コマンドでサービスを起動します。
# systemctl start app.service # systemctl status app.service → 「Active: active (running)」が表示されることを確認する