CloudWatch プロセス数をトリガに動的スケールするEC2 ASG
Contents
概要
- EC2 Auto Scaling構成において、インスタンスOS(Linux) で起動するプロセス数をトリガに、インスタンスをスケールアウトする動的スケーリングポリシーを導入します。
やりたいこと
- 背景は、2023/7/11 のJAWS-UG 名古屋でもお伝えしましたが、高負荷の時間帯(アクセスが多い時間帯)にAuto Scaling Group で起動するインスタンスの性能不足となり、httpサーバーが処理しきれない状態に陥りました。インスタンス内のhttp プロセス数がしきい値(例: 最大値の90%) となった際に、インスタンスの台数を増やす(スケールアウトする)ことが目的です。
- スケーリングポリシーには、CloudWatch アラームを使用します。しかし、標準のCloudWatch メトリクスには、インスタンスOS のプロセス数は取得されません。CloudWatch のメトリクスで、プロセス数を取得するため、OS(Linux) にCloudWatch Agent を導入、Agent のカスタマイズを行いprocstat のカスタムメトリクス取得を設定します。
- また、以前こちらの記事で紹介した方法でもprocstat のカスタムメトリクスが取得できます。しかし、こちらの記事の場合、procstat のカスタムメトリクスはインスタンス単位で取得が行われるため、スケーリングポリシーのトリガには不向きです。理由は、Auto Scaling Group で起動するインスタンスは入れ替わるためインスタンス単位にアラームを設定する方法では実現が難しい(アラームを設定したインスタンスが入れ替わってしまうため)。かつ、仮にAuto Scaling Group の全インスタンスに設定した場合、Auto Scaling Group に所属するインスタンスの台数分、スケールアウトのトリガがキックされます(過剰にキックされ制御できない)
- そのため、インスタンス単位でカスタムメトリクスを取得するのではなく、収集されたCloudWatch のメトリクスをAuto Scaling Group で集約(ロールアップ)することにします。副次効果として、カスタムメトリクスが減ることは、コストの削減にも貢献します。
- 今回のスケールアウトする際の動的スケーリングポリシーは、簡易スケーリングポリシーを使用します。今回はスケールアウトのみ設定しますが、同様の方法でスケールインも設定が可能です。
検証の準備
- 先ず、EC2 インスタンスの権限を確認します。IAM ロールに、AmazonEC2ReadOnlyAccess、CloudWatchFullAccess、AmazonSSMFullAccessのポリシーをアタッチします。
- 次に、Linux にCloudWatch Agent を導入します。
[ec2-user@niikawa-test-webserver ~]$ sudo yum install amazon-cloudwatch-agent
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core | 3.7 kB 00:00
4 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package amazon-cloudwatch-agent.x86_64 0:1.247354.0b251981-1.amzn2 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
amazon-cloudwatch-agent x86_64 1.247354.0b251981-1.amzn2 amzn2-core 45 M
Transaction Summary
================================================================================
Install 1 Package
Total download size: 45 M
Installed size: 201 M
Is this ok [y/d/N]: y
Downloading packages:
amazon-cloudwatch-agent-1.247354.0b251981-1.amzn2.x86_64.r | 45 MB 00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
create group cwagent, result: 0
create user cwagent, result: 0
create user aoc, result: 6
Installing : amazon-cloudwatch-agent-1.247354.0b251981-1.amzn2.x86_64 1/1
Verifying : amazon-cloudwatch-agent-1.247354.0b251981-1.amzn2.x86_64 1/1
Installed:
amazon-cloudwatch-agent.x86_64 0:1.247354.0b251981-1.amzn2
Complete!
CloudWatch にprocstat のカスタムメトリクス取得設定
- CloudWatch Agent の設定をカスタマイズし、procstat のカスタムメトリクス取得を設定します。(json の設定値は後述します)
[ec2-user@niikawa-test-webserver ~]$ cd /opt/aws/amazon-cloudwatch-agent/etc
[ec2-user@niikawa-test-webserver etc]$ sudo vi amazon-cloudwatch-agent.json
- CloudWatch Agent のサービスを起動します。
[ec2-user@niikawa-test-webserver etc]$ sudo systemctl status amazon-cloudwatch-agent
● amazon-cloudwatch-agent.service - Amazon CloudWatch Agent
Loaded: loaded (/etc/systemd/system/amazon-cloudwatch-agent.service; disabled; vendor preset: disabled)
Active: inactive (dead)
[ec2-user@niikawa-test-webserver etc]$ sudo systemctl enable amazon-cloudwatch-agent
Created symlink from /etc/systemd/system/multi-user.target.wants/amazon-cloudwatch-agent.service to /etc/systemd/system/amazon-cloudwatch-agent.service.
[ec2-user@niikawa-test-webserver etc]$ sudo systemctl start amazon-cloudwatch-agent
[ec2-user@niikawa-test-webserver etc]$ sudo systemctl status amazon-cloudwatch-agent
● amazon-cloudwatch-agent.service - Amazon CloudWatch Agent
Loaded: loaded (/etc/systemd/system/amazon-cloudwatch-agent.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2023-07-09 05:30:04 UTC; 2s ago
Main PID: 6862 (amazon-cloudwat)
Memory: 82.9M
CGroup: /system.slice/amazon-cloudwatch-agent.service
mq6862 /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agen...
Jul 09 05:30:04 niikawa-test-webserver systemd[1]: Started Amazon CloudWatch ...
Jul 09 05:30:04 niikawa-test-webserver start-amazon-cloudwatch-agent[6862]: I...
Hint: Some lines were ellipsized, use -l to show in full.
- CloudWatch Agent には、以下の記述を行っています。
- procstat セクションのexe には “httpd" を指定しています。これは指定した文字列と一致するプロセス名のプロセスが選択されます。
- procstat で収集されるメトリクスは、pid_count です。これは、プロセスに関連付けられたプロセス ID の数を表します。procstat セクションの詳細は、こちらのドキュメントを参照ください。
- aggregation_dimensions を指定して、収集したメトリクスを“AutoScalingGroupName" で集約します。
- metrics_collection_interval は必須ではありませんが、継続的にメトリクスを収集するために指定すべきです。
- なお、append_dimensions セクションには、(ドキュメントによれば)この4つ以外の指定はないようです。
{
"metrics": {
"append_dimensions": {
"AutoScalingGroupName": "${aws:AutoScalingGroupName}",
"ImageId": "${aws:ImageId}",
"InstanceId": "${aws:InstanceId}",
"InstanceType": "${aws:InstanceType}"
},
"aggregation_dimensions": [["AutoScalingGroupName"]],
"metrics_collected": {
"procstat": [
{
"exe": "httpd",
"measurement": [
"pid_count"
],
"metrics_collection_interval": 60
}
]
}
}
}
- オプションとして、CloudWatch Agent のsystemd 設定をカスタマイズします。Unitに
After=cloud-final.service
を追記します。 - Auto Scaling Groupでは、cloud-init でホスト名の再設定が行われるかもしれません。CloudWatch Agent のサービスを cloud-init の処理後に起動させる方法です。設定方法は、いくつかあり、詳細は、こちらの別記事を参照ください。
[ec2-user@niikawa-test-webserver ~]$ sudo vi /etc/systemd/system/amazon-cloudwatch-agent.service
[ec2-user@niikawa-test-webserver ~]$ cat /etc/systemd/system/amazon-cloudwatch-agent.service
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT
# Location: /etc/systemd/system/amazon-cloudwatch-agent.service
# systemctl enable amazon-cloudwatch-agent
# systemctl start amazon-cloudwatch-agent
# systemctl | grep amazon-cloudwatch-agent
# https://www.freedesktop.org/software/systemd/man/systemd.unit.html
[Unit]
Description=Amazon CloudWatch Agent
After=network.target
After=cloud-final.service
[Service]
Type=simple
ExecStart=/opt/aws/amazon-cloudwatch-agent/bin/start-amazon-cloudwatch-agent
KillMode=process
Restart=on-failure
RestartSec=60s
[Install]
WantedBy=multi-user.target
[ec2-user@niikawa-test-webserver ~]$ sudo systemctl daemon-reload
[ec2-user@niikawa-test-webserver ~]$ sudo systemctl restart amazon-cloudwatch-agent
CloudWatch カスタムメトリクスを確認する (プロセス数の見える化)
- 今回は、Auto Scaling Group で使用する想定のため、AMI を取得し、起動テンプレートを更新します。起動テンプレート更新後に、インスタンスを起動し直します。
- aggregation_dimensions でメトリクスを集約前は、以下の結果になっていました。インスタンス単位にメトリクスが取得されています。
- aggregation_dimensions でメトリクスを集約後は、以下の結果になります。Auto Scaling Group 単位に集約され、メトリクスが取得されています。
スケーリングポリシーの設定
- それでは、ようやくスケーリングポリシーの設定になります。
- 先ず、アラームを作成します。
- CloudWatch において、メトリクスを CWAgent > AutoScalingGroupName にて選択します。メトリクスの画面から、以下赤丸で示す「アラームの作成」を選択します。
- アラームに設定するメトリクスと、条件を指定します。
- 以下に示す条件のしきい値は今回の検証サンプルです。システムに応じて、適切にしきい値を設定します。特にプロセス数の最大値に対して、上限のしきい値をどこに置くかは重要です。(例: 最大値の90%)
- アクションの設定は行いません。通知は「削除」を選択します。その他は変えません。
- 最後に、アラームの名前を設定します。
- プレビューと作成の画面が表示されます。設定内容を確認し、「アラームの作成」を押します。
- アラームの作成後、CloudWatch のアラームから「すべてのアラーム」を選択し、作成したアラームが存在することを確認します。
- 次に、Auto Scaling Group にスケーリングポリシーを設定します。EC2 のサービスを選択し、Auto Scaling グループを選択します。
- 対象のAuto Scaling グループを選択します。
- 「オートスケーリング」タブを選びます。続いて、「動的スケーリングポリシーを作成する」を選択します。
- ポリシータイプに「シンプルなスケーリング」を選択、スケーリングポリシー名を入力、CloudWatch アラームには先ほど作成したアラームを選択します。
- アクションを実行するに「追加」を選択し、インスタンスを追加する数を指定します。(例: 1 容量ユニット)
- 待機時間を秒数で指定し(例: 600)、「作成」を押します。
- 以下の通り、スケーリングポリシーが作成されました。
スケーリングポリシーをテストする
- 作成した動的スケーリングポリシーをテストします。テスト開始時点では、アラームは OK を示しています。
- インスタンスで動作するプロセス数を追加しました。以下の通り、アラーム条件のしきい値に設定した数を上回ったため、アラーム状態 に変わりました。
- Auto Scaling Group にの「アクティビティ」タブを見て頂くと、Auto Scaling Groupにインスタンスが追加起動されたことが分かります。やった、期待通りの動作ですね!
関連記事