EC2に構築したNode.jsアプリの起動時間をスケジューリングする
社内サービス(EC2とNode.js)を作ったはいいのですが、業務時間外もサービスを起動したままだと、無駄なコストとなってしまう場合が、多々あると思います。そんな時のために、EC2インスタンスの起動時間をスケジューリングして、EC2インスタンスの起動時にNode.jsアプリを自動起動させる方法をメモりました。
全体的なイメージはこんな感じになります。
AmazonEventBridgeでEC2インスタンスを自動起動•自動停止
まず、EC2インスタンスの起動時間をスケジューリングします。EC2の自動起動・停止には色々な方法が考えられますが、今回は、AmazonEventBridgeのスケジューラーを使って実装しました。
EventBridge用IAMロールの作成
EventBridgeがSystemsManagerを操作するための権限、を与えるIAMロールを作成します。
-
IAM
>ロール
>ロールを作成
を選択 - 信頼されたエンティティを選択にて
カスタム信頼ポリシー
を選択
- カスタム信頼ポリシーを入力
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "scheduler.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
- 許可を追加にて、許可ポリシー
AmazonEC2FullAccess
を付与
- 名前、確認、および作成にて、ロール名を設定。今回はわかりやすく
ec2-start-stop-role
とする。
-
ロールを作成
でEventBridge用IAMロール作成完了です。
EventBridge起動用ルールの作成
ここからはEventBridgeで、EC2自動起動用のルールを作成します。今回は、月~金曜日の10:00にEC2を起動するルールを想定しています。
-
EventBridge
>ルール
>ルールを作成
を選択
- ルールの詳細を定義
- 名前 :
ec2-start
- ルールタイプ :
スケジュール
- 名前 :
- スケジュールの詳細の指定
- 頻度 :
定期的なスケジュール
- スケジュールの種類 :
cronベースのスケジュール
- cron式 :
0
分10
時間?
日付*
月Mon-Fri
曜日*
年 - フレックス :
オフ
- 頻度 :
- ターゲットの選択
- ターゲットAPI :
StartInstances
入力に対象となるEC2インスタンスのIDを記載します
- ターゲットAPI :
{
"InstanceIds": [
"i-****",
"i-****"
]
}
6. 設定
+ アクセス許可 : 既存のロールを使用
を選択し、先ほど作成したIAMロールを選択
7. スケジュールを作成
を選択して完了です。
同様の手順で停止時のルールを作成します。これで、EC2インスタンスが自動起動・停止するようになりました。試しにアプリのURLにアクセスしてみると、停止時には504エラー、起動時には502エラーが返されるようになりました。
EC2インスタンス起動時にsystemdのサービスファイルでNode.jsアプリを起動
EC2インスタンスのスケジューリングの設定は完了しましたが、そのままだと、EC2インスタンスの起動時にNode.jsアプリは起動せず、502エラー等が返されてしまいます。サービス起動時に実行したい処理を記述するファイルとして、rc.local
がありますが、仕様として少し古いようです。CentOS7からサービス起動の管理がrc.local
から、systemd
が採用されているようで、rc.localファイルに自動実行のコマンド等を書いても、そのままだと動かないようです。rc.local
を使い続ける方法もあるようですが、今回は仕様にのっとって、systemd
を採用していきます。
- まず、SSHで、ログインしてrootに切り替えます。環境は、AmazonLinux2です。
// SSHログイン
ssh -i ~/.ssh/***.pem ec2-user@00.00.00.00
// root切り替え
sudo -i
-
/etc/systemd/system
の下に、拡張子.serviceのテキストファイルを作り、以下の内容を書きます。
// サービスファイルの新規作成
vi /etc/systemd/system/mydaemon.service
▼ サービスファイル(mydaemon.service)
[Unit]
Type=simple // プロセスの起動タイプ。
Description=【詳細】 // サービスの説明。
[Service]
WorkingDirectory=/home/ec2-user/***/ // 実行したいプログラムのディレクトリ
ExecStart=/root/.nvm/versions/node/v16.9.1/bin/node server.js // 実行したいプログラム
Restart=always // プロセスが落ちても自動的に復帰
[Install]
WantedBy=multi-user.target // どのターゲットで動かすか(マルチユーザー)
サービスファイルについてもう少し詳しく知りたい方
- 作成したサービスファイルの自動起動を有効化し、一覧表示して、作成したサービスが
enabled
になっているのを確認します。
// 自動起動有効化
systemctl enable mydaemon.service
// 一覧表示
systemctl list-unit-files
...
microcode.service enabled
mydaemon.service enabled
nfs-blkmap.service disabled
...
試しに、サービスを開始すると、プログラムが実行されるので、期待通りNode.jsアプリが動いているか確認できます。
// サービス開始
systemctl start mydaemon.service
サービスファイルを書き換えた時には、再読み込みを行います。
// サービスファイル再読み込み
systemctl daemon-reload
- サービスを再起動して、Node.jsアプリが動いているか確認できれば完了です。
// 再起動
reboot
これで、スケジューリング通りに、EC2インスタンスが起動した時、Node.jsアプリが自動で起動するようになりました。
Discussion