おうちでAWS ~Amazon CloudWatch 編~
はじめに
皆様こんにちは、あかいけです。
突然ですが、おうちで AWS を使っていますか?
このブログを見ているということはおそらくあなたは仕事で AWS を利用されている方だと思いますが、
おうちでも AWS を感じたくないですか?(私は感じたいです)
というわけで本シリーズでは、 「AWS をもっと身近に」 をテーマに、おうち(オンプレ)で活用できる AWS サービスを再発見していきます。
第二回目は、Amazon CloudWatch です。
なお本記事のコードは以下リポジトリに格納しているので、
よければこちらを Clone してご利用ください。
Amazon CloudWatch とは?
Amazon CloudWatch は、Amazon Web Services (AWS) リソースと、AWS で実行されているアプリケーションをリアルタイムでモニターリングします。
対応しているサービスは幅広く、大抵の AWS 上で提供されているサービスは、CloudWatch にログやメトリクスを集約することができます。
CloudWatch では様々なサービスが提供されており、
すべて触っていくと記事が超大作になってしまうため、本記事では基本的な以下サービスをオンプレミスと連携して使うことにフォーカスします。
使う方法
前述の通り AWS 上の大抵のサービスは CloudWatch にログやメトリクスを集約することができますが、
オンプレミスなどAWS以外の環境においても、CloudWatch Agent をインストールすることで、
CloudWatch 上にログやメトリクスを集約することができます。
料金について
サービスごとに料金形態が違うので、今回触れるログ / メトリクス / アラームに限定して東京リージョンの料金をご紹介します。
まず毎月の無料枠として以下が存在します。
- ログ
- 5 GB データ (取り込み、ストレージのアーカイブ、Logs Insights クエリによってスキャンされたデータ)
- 1 か月あたり 1,800 分の Live Tail の使用 (約 1 時間/日)
- メトリクス
- 基本のモニタリングメトリクス(AWS サービスから送信されるデフォルトのメトリクス)
- 10 メトリクス (カスタムメトリクスと詳細モニタリングメトリクス)
- 100 万件の API リクエスト
(GetMetricData、GetInsightRuleReport、GetMetricWidgetImage は含まれない)
- アラーム
- 10 アラームメトリクス
(メトリクスを直接リストアップし、Metrics Insights クエリを使用しない標準解像度アラームにのみ適用)
- 10 アラームメトリクス
上記を超える場合は、以下の料金が適用されます。
ログに関連した料金
ログに関しては、データ取り込み料金 と データ保存料金 が主な料金となります。
特にデータ取り込み料金に関しては GB あたりの料金が S3 に比べると高く、
大量のログ出力によって思わぬ利用料金になってしまったことは、誰もが経験されているのではないでしょうか。
ログの管理 | 費用 |
---|---|
データ取り込み スタンダードクラス | USD 0.76/GB |
データ取り込み 低頻度アクセスクラス | USD 0.38/GB |
**データ保存 ** | USD 0.033/圧縮された GB |
メトリクスに関連した料金
まずカスタムメトリクスの数に応じて料金が発生します。
無料枠が 10 個なので、11 個以降は料金が発生します。
範囲 | コスト (メトリクス/月) |
---|---|
最初の 10,000 個のメトリクス | USD 0.30 |
次の 240,000 個のメトリクス | USD 0.10 |
次の 750,000 個のメトリクス | USD 0.05 |
1,000,000 を超えるメトリクス | USD 0.02 |
またメトリクスの送信に CloudWatch の API を用いるのですが、この API へのリクエストにもコストが発生します。
API 名 | 費用 |
---|---|
GetMetricData、GetInsightRuleReport | USD 0.01/リクエストされた 1,000 個のメトリクス |
GetMetricWidgetImage | USD 0.02/リクエストされた 1,000 個のメトリクス |
GetMetricStatistics、ListMetrics、PutMetricData、GetDashboard、ListDashboards、PutDashboard、DeleteDashboards リクエスト | USD 0.01/1,000 件のリクエスト |
CloudWatch Agent では PutMetricData を使ってカスタムメトリクスを送信しているため、
単純に考えると 100 万件以降の API リクエストで料金が発生します。
ただしマネジメントコンソールでのアクセスや AWS CLI などでも API リクエストは発生するため、実際はカスタムメトリクスで 100 万件無料枠が使えることは無いと思います。
アラームに関連した料金
作成したアラームの数や種類によって料金が発生します。
無料枠として 10 個の標準解像度アラームが用意されているため、
11 個以降の標準解像度アラームや、それ以外のアラームで料金が発生します。
標準解像度メトリクスアラーム | 費用 |
---|---|
直接表示されるメトリクスの料金 (/アラーム/月) | USD 0.10/アラームメトリクス |
Metrics Insights クエリの料金 (/アラーム/月) | USD 0.10/分析されたメトリクス |
高解像度メトリクスアラーム | 費用 |
---|---|
直接表示されるメトリクスの料金 (/アラーム/月) | USD 0.30/アラームメトリクス |
実行環境
筆者の環境は以下の通りです。
なお今回は物理サーバーを使っていますが、仮想サーバーでももちろん同じことができるので、お好みのサーバーで実行してください。
また今回は AWS Systems Manager Run Command を利用して CloudWatch Agent を設定するため、対象サーバーへ SSM Agent が導入されている前提となります。
SSM Agent の導入方法については、よければ以下をご参照ください。
作業用 PC
- Terraform - v1.10.0
- Ansible - core 2.18.6
- AWS CLI - 2.16.4
管理対象サーバー
- OS - Ubuntu 24.04 LTS × 6
セットアップ
オンプレインスタンスでのセットアップ手順は以下ドキュメントの通りです。
事前準備
事前準備として AWS 側で以下リソースの作成が必要なため、
Terraform で作成しておきます。
- インスタンス用 IAM ユーザー
- CloudWatch Agent 設定ファイル用パラメーターストア
resource "aws_iam_user" "main" {
name = "cloudwatch-agent-homeserver-user"
}
resource "aws_iam_access_key" "main" {
user = aws_iam_user.main.name
}
resource "aws_iam_user_policy_attachment" "main" {
user = aws_iam_user.main.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
}
resource "aws_ssm_parameter" "secret" {
name = "AmazonCloudWatch-HomeServer-Config"
type = "String"
value = file("${path.module}/amazon-cloudwatch-agent.json")
}
output "iam_user_access_key_id" {
value = aws_iam_access_key.main.id
sensitive = true
}
output "iam_user_access_key_secret" {
value = aws_iam_access_key.main.secret
sensitive = true
}
CloudWatch Agent 設定ファイルについては、以下を参考に作成しています。
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "root"
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/syslog",
"log_group_name": "/var/log/syslog",
"log_stream_name": "{hostname}"
}
]
}
}
},
"metrics": {
"metrics_collected": {
"cpu": {
"measurement": [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_steal",
"cpu_usage_guest",
"cpu_usage_user",
"cpu_usage_system"
],
"resources": [
"*"
],
"totalcpu": true
},
"disk": {
"measurement": [
"used_percent"
],
"resources": [
"*"
]
},
"diskio": {
"measurement": [
"io_time",
"write_bytes",
"read_bytes",
"writes",
"reads"
],
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used",
"mem_cached",
"mem_total"
]
}
}
}
}
terraform apply;
次の手順で利用するIAMユーザーのアクセスキーは、
リソース作成後に以下のコマンドで確認できます。
terraform output -json;
次に作成した IAM ユーザー の アクセスキー をオンプレインスタンスに設定します。
CloudWatch Agent は /root/.aws/credentials 内のデフォルト認証情報(default)か、AmazonCloudWatchAgent セクションの認証情報を利用します。
[default]
aws_access_key_id = XXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXX
[AmazonCloudWatchAgent]
aws_access_key_id = XXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXX
デフォルト認証情報はすでにSSM Agent用の認証情報が設定されているため、
AmazonCloudWatchAgent セクションを追記します。
以下は「/root/.aws/credentials」内に AmazonCloudWatchAgent セクションを追加する Ansible です。
クレデンシャル情報(group_vars/all.yml)は実際に値に置き換えて、使用してください。
---
# AWSクレデンシャル情報
aws_region: "ap-northeast-1"
iam_user_access_key_id: "XXXXXXXXXXX" # TerraformのoutputからIAMアクセスキーIDを取得
iam_user_access_key_secret: "XXXXXXXXXXX" # TerraformのoutputからIAMシークレットアクセスキーを取得
# サーバー接続設定
ansible_user: user # サーバーのユーザー名
ansible_ssh_private_key_file: ~/.ssh/key_name # SSH秘密鍵のパス
ansible_become_pass: password # sudoパスワード
---
- name: Setup AWS credentials for CloudWatch Agent
hosts: home_servers
become: true
tasks:
- name: Create .aws directory if it doesn't exist
ansible.builtin.file:
path: /root/.aws
state: directory
mode: '0700'
owner: root
group: root
- name: Check if AmazonCloudWatchAgent section already exists
ansible.builtin.lineinfile:
path: /root/.aws/credentials
regexp: '^\[AmazonCloudWatchAgent\]'
state: absent
check_mode: true
register: cloudwatch_section_check
changed_when: false
- name: Add AmazonCloudWatchAgent credentials section
ansible.builtin.blockinfile:
path: /root/.aws/credentials
create: true
mode: '0600'
owner: root
group: root
marker: "# {mark} ANSIBLE MANAGED BLOCK - AmazonCloudWatchAgent"
block: |
[AmazonCloudWatchAgent]
region = {{ aws_region }}
aws_access_key_id = {{ iam_user_access_key_id }}
aws_secret_access_key = {{ iam_user_access_key_secret }}
when: cloudwatch_section_check.found == 0
ansible-playbook -i inventory.ini aws_credentials_setup.yml -v;
CloudWatch Agent
CloudWatch Agent インストール
AWS 公式が用意しているコマンドドキュメントの AWS-ConfigureAWSPackage を利用します。
以下はインスタンス ID が「mi-」から始まるもの全てに CloudWatch Agent をインストールする Run Command を実行する AWS CLI です。
aws ssm send-command \
--document-name "AWS-ConfigureAWSPackage" \
--comment "Install CloudWatch Agent" \
--targets "Key=InstanceIds,Values=$(aws ssm describe-instance-information \
--query "join(',', InstanceInformationList[?starts_with(InstanceId, 'mi-')].InstanceId)" \
--output text)" \
--parameters '{"action":["Install"],"name":["AmazonCloudWatchAgent"],"version":["latest"]}' \
--region ap-northeast-1
以下のコマンドで確認して、ステータスが Success になっていれば OK です。
aws ssm list-command-invocations \
--command-id XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX \
--output json | jq -r '.CommandInvocations[] | "\(.InstanceId)\t\(.Status)"'
CloudWatch Agent 設定
AWS 公式が用意しているコマンドドキュメントの AmazonCloudWatch-ManageAgent を利用します。
これも同様にインスタンス ID が「mi-」から始まるもの全てを対象に、 CloudWatch Agent の設定と再起動する Run Command を実行する AWS CLI です。
aws ssm send-command \
--document-name "AmazonCloudWatch-ManageAgent" \
--comment "Configure CloudWatch Agent with predefined config" \
--targets "Key=InstanceIds,Values=$(aws ssm describe-instance-information \
--query "join(',', InstanceInformationList[?starts_with(InstanceId, 'mi-')].InstanceId)" \
--output text)" \
--parameters '{
"action": ["configure"],
"mode": ["onPremise"],
"optionalConfigurationSource": ["ssm"],
"optionalConfigurationLocation": ["AmazonCloudWatch-HomeServer-Config"]
}' \
--region ap-northeast-1
以下のコマンドで確認して、ステータスが Success になっていれば OK です。
aws ssm list-command-invocations \
--command-id XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX \
--output json | jq -r '.CommandInvocations[] | "\(.InstanceId)\t\(.Status)"'
使ってみた
以上で下準備は終わりなので、実際に CloudWatch で転送状況を確認しましょう。
CloudWatch Agentの設定完了から数分で反映されているはずです。
ログ
ちゃんとロググループが作成されており、
オンプレインスタンスごとにログストリームも作成されています。
ログもちゃんと転送されています。
メトリクス
次にメトリクスですが、転送対象が多かったのかすごい数のメトリクスが作成されてしまいました…。
720個だと単純計算で $216/月額 になってしまうので、後で忘れずに CloudWatch Agent をお掃除します。
以下はメモリ使用量のメトリクスですが、正常に取得できています。
アラーム
まずは以下のTerraformでアラームを作成します、
hosts は作成したメトリクス名に合わせて書き換えてください。
なお後でアラーム状態になることを確認するので、閾値は低め(2GB)に設定しています。
variable "hosts" {
default = ["server-01", "server-02", "server-03", "server-04", "server-05", "server-06"]
}
resource "aws_cloudwatch_metric_alarm" "mem_used_alarm" {
for_each = toset(var.hosts)
alarm_name = "mem_used_${each.key}"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "mem_used"
namespace = "CWAgent"
period = 60
statistic = "Average"
threshold = 2e+09
alarm_description = "Memory usage alarm for ${each.key}"
dimensions = {
host = each.key
}
actions_enabled = false
}
terraform apply;
Terraform実行後、正常に作成されています。
ちょっとわかりづらいですが、
赤線がアラームの閾値で、青いウニョウニョした線が実際のメトリクスです。
最後にちゃんとアラーム状態になるか、メモリに負荷をかけて確認してみます。
以下はメモリを2GB占有するコマンドです。
実行後はenterを押すか、CTRL + C を押すまで占有し続けます。
python3 -c "a = bytearray(2 * 1024**3); input('Press Enter to free memory...')"
数分後にアラーム状態になっているので、問題なく設定できています。
お掃除
最後にお片付けをしましょう。
CloudWatch Agent アンインストール
AWS公式コマンドドキュメントの AWS-ConfigureAWSPackage でアンインストールできるので、
こちらを利用します。
以下はインスタンス ID が「mi-」から始まるもの全てを対象に CloudWatch Agent をアンインストールする Run Command を実行する AWS CLI です。
aws ssm send-command \
--document-name "AWS-ConfigureAWSPackage" \
--comment "Uninstall CloudWatch Agent" \
--targets "Key=InstanceIds,Values=$(aws ssm describe-instance-information \
--query "join(',', InstanceInformationList[?starts_with(InstanceId, 'mi-')].InstanceId)" \
--output text)" \
--parameters '{"action":["Uninstall"],"name":["AmazonCloudWatchAgent"],"version":["latest"]}' \
--region ap-northeast-1
CloudWatch Agent 認証情報削除
CloudWatch Agent用のIAMユーザーのアクセスキー情報を削除しておきます。
---
- name: Remove AWS credentials for CloudWatch Agent
hosts: home_servers
become: true
tasks:
- name: Remove AmazonCloudWatchAgent credentials section
ansible.builtin.blockinfile:
path: /root/.aws/credentials
marker: "# {mark} ANSIBLE MANAGED BLOCK - AmazonCloudWatchAgent"
state: absent
ansible-playbook -i inventory.ini aws_credentials_remove.yml -v;
Terraform リソース削除
作成した Terraform リソースを削除します。
これで本記事で作成したすべてのリソースの設定値戻し、および削除が完了しました。
terraform destroy;
さいごに
以上、おうち de AWS ~Amazon CloudWatch 編~でした。
本記事では Amazon CloudWatch の一部機能にしか触れていませんが、それでも統合的な監視ツールとして利用できる強力さを感じることができました。
そしてエージェントや設定は簡単にできるので、思いついたらすぐできるのもいいなぁ…と思いました。
これを機に、皆さんもおうちに転がっているサーバーに CloudWatch Agent を入れて AWS にログやメトリクスをAWS上に集約してみてはいかがでしょうか。
また今後も定期的におうちで活用できる AWS サービスを模索してブログにしてきますので、
その際はまた見ていただければ幸いです。