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)」が表示されることを確認する
お客様のご要望に柔軟に対応いたします。まずはお気軽にご相談ください。
cloudpackは、アイレット株式会社が提供するクラウド支援サービスです。クラウドの導入・構築から運用・保守、技術的な問い合わせまでトータルサポート!
アイレットでは、様々な職種で一緒に働ける仲間を募集しています。
インフラエンジニア、開発エンジニア、クリエイティブ職、営業職など、様々な職種で一緒に働ける仲間を募集しています。アイレットのこと、社員インタビュー、募集職種、福利厚生など、アイレット公式サイト採用情報をご覧ください。