♻️

.pm2との付き合い方

2023/01/28に公開

これはなに

AWS EC2 インスタンスの上にNode.js Webアプリケーションを構築しました。
Node.jsアプリの起動管理にpm2を採用したけど、.pm2の扱いに工夫が必要だったので知見をメモしておく。

はじめに

はじめにpm2と.pm2について。

pm2とは

PM2 は、アプリケーションを 24 時間 365 日オンラインで管理および維持するのに役立つデーモン プロセス マネージャーです。
https://pm2.keymetrics.io/

PM2自体を永続的に起動し続けるためにはOS側で対応が必要です。

.pm2とは

  • pm2を起動(pm2 start app.js)した時に生成されるpidやログ等が保管されるフォルダ

前提

PM2自体を永続的に起動し続ける手段としてsystemdサービスを採用します。
systemdサービスはpm2 startup systemdコマンドを使って作成します。

本編

PM2を永続化する時の困りごと解決策をセットで記載します。

.pm2の置き場所

.pm2の置き場所について。

仕組みと困りごと

  • pm2を起動(pm2 start app.js)すると.pm2フォルダが作成される
    その中にpidファイルやログが保管される
  • .pm2はpm2コマンドを実行したユーザのホームディレクトリに作成される
    ec2-userでコマンドを実行した場合は/home/ec2-user/.pm2に作成される

pm2で起動したアプリの状態を確認するコマンドとしてpm2 statusがあるが、これはホームディレクトリか環境変数(PM2_HOME)で指定された場所から.pm2ディレクトリを探し、見つけた.pm2ディレクトリに保管されている情報をもとにステータスを表示する。

例えばec2-userユーザでpm2を起動(pm2 start app.js)してログアウト。その後、julietユーザがログインしてpm2 statusを実行しても同じサーバで動いているnodejsアプリは表示されない。

解決策

PM2_HOME環境変数と/etc/environmentを活用する。

.pm2フォルダはPM2_HOME環境変数の中に作成される。
どのユーザでEC2にログインしても共通のPM2_HOME環境変数が設定されている状態を実現すれば解決できる。

具体的な手順は以下の通り。

/etc/environment にPM2_HOMEを定義する。

ここにexport PM2_HOME=/opt/app/.pm2と記載しておけば、どのユーザでログインしても共通の.pm2を参照するためpm2 statusで状況を確認することができる。

同じ機能を提供する/etc/profileもあるが、これはBashなどのシェルを起動した時だけ読み込まれるため、コマンド実行アカウントにより読み込まれない可能性がある。

systemdサービスを作成する pm2 startup

仕組みと困りごと

PM2自体を永続的に起動し続ける手段としてsystemdサービスを採用します。
systemdサービスはpm2 startup systemdコマンドを使って作成します。

pm2 startup の --hp <home-path>について。
pm2 startup--hpに何も指定しないと$HOMEの値を参照する。

例えばこれを起動スクリプト等でrootユーザで実行すると、systemdから起動してくる時の.pm2は/root/.pm2となる。
この値は当初定めた/opt/app/.pm2と異なるため、systemctl restartを実行すると、.pm2を参照することができず起動しない。

解決策

pm2 startupを起動する時は下記例の通り.pm2を削除したパスを指定する。

# $PM2_HOMEは```/etc/environment```で設定済
HOME=$(dirname $PM2_HOME)
pm2 startup systemd -u <user> --hp $HOME

.pm2のアクセス権設定

仕組みと困りごと

.pm2はpm2を起動(pm2 start app.js)したユーザのアクセス権で作成される。
そのため、「.pm2の置き場所」に記載した解決策で複数ユーザがpm2コマンドを実行できるようにした場合pm2 statusでステータスを見ることはできるけど、pm2 restart all等のプロセスを操作するコマンドが権限不足で実行できない。

解決策

pm2を起動(pm2 start app.js)を実行した後、chown -R user:wheel $PM2_HOMEしておく。

例えば、EC2(実際はAuto Scalingで構成する)にpm2を構成する場合は以下の通り。

systemdをセットアップする起動テンプレート(Launch Template)のシェルは以下の通り作成する。

function setupPM2(){
    echo setupPM2

    # PM2_HOME環境変数を読み込んで設定する
    source /etc/environment

    # systemd設定を行う
    # このコマンドでpm2-ec2-user.serviceというサービスが作成&有効化される
    HOME=$(dirname $PM2_HOME)
    pm2 startup systemd -u ec2-user --hp $HOME

    # アプリフォルダに移動
    cd /opt/app
    
    # pm2 startを実行してアプリを起動する
    pm2 start ecosystem.config.js --env $NODE_ENV
    
    # 上記で作成したpm2-ec2-user.serviceは.pm2フォルダの内容を参照して起動する
    # pm2 startした結果を保存する
    pm2 save
    
    # 起動テンプレートはrootユーザで実行されるため、所有者をec2-user:wheelに変更する
    chown -R ec2-user:wheel /opt/app
}

Discussion