CloudWatchのカスタムメトリクスでFreeMemoryMBytes、UsedMemoryPercent、LoadAverage、Stealを取得

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CloudWatchで取得できること

CloudWatchはAWSの様々な情報を監視して統計を取ってくれるサービスです。概要については以前ご紹介しました。今回は、標準で提供されていない統計データを登録して取得してみます。いわゆるカスタムメトリクスというやつです。

カスタムメトリクスを取得する方法

今回のカスタムメトリクスで取得する値は以下の4つです。

  • 空きメモリー容量(FreeMemoryMBytes):メモリーが少ないからといってメモリ不足とは限らない
  • メモリー使用率(UsedMemoryPercent):使用メモリーを合計メモリーで割った割合
  • ロードアベレージ(LoadAverage):システムへの平均負荷
  • スチール(Steal):CPUリソースを割り当ててもらえなかった時間の割合

続いて、Linuxコマンドを用いて各種値を取得しましょう

freeコマンド

まずは、freeコマンドから

$ free
             total       used       free     shared    buffers     cached
Mem:        617016     191876     425140          0      11092     145284
-/+ buffers/cache:      35500     581516
Swap:            0          0          0

この標準出力された情報を成型して値を取得します。上記の例ではMemとtotalが交差する値が全メモリー量です。

$ free | grep 'Mem' | tr -s ' ' | cut -d ' ' -f 2
617016

MB(メガバイト)表記にしました。

$ free -m | grep 'Mem' | tr -s ' ' | cut -d ' ' -f 2
602

続いて、メモリー使用率を取得するために空きメモリー量を取得します。

$ free -m | grep 'buffers/cache' | tr -s ' ' | cut -d ' ' -f 4
567

後は計算してあげればメモリー使用率を取得できます。

uptimeコマンド

uptimeコマンドは、本来システムがどの程度連続かどうしているか調べるコマンドですが、ついでにロードアベレージも取得できます。ロードアベレージは、1分前、5分前、15分前までの平均負荷を取る事ができます。今回は1分前を取得します。

$ uptime
 12:18:20 up  6:55,  2 users,  load average: 0.01, 0.05, 0.05

これを成型します。

$ uptime | tr -s ' ' | cut -d ' ' -f 9 | cut -d ',' -f 1
0.01

取れました!

vmstatコマンド

最後にvmstatです。これは、プロセスの状態、メモリの使用状況など幅広い情報を取得できます。vmstatコマンドの結果からsteal値を取得します。stと書いてある列です。

$ vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 426544  11136 145280    0    0     2     1    4    8  0  0 99  0  0

これを成型します。

$ vmstat | tail -1 | tr -s ' ' | cut -d ' ' -f 18
0

これで素材は整いました!

CloudWatchのコマンドラインツール

CloudWatchにメトリクスデータを登録するために、CloudWatchコマンドラインツールを使えるようします。

$ wget http://ec2-downloads.s3.amazonaws.com/CloudWatch-2010-08-01.zip
$ unzip CloudWatch-2010-08-01.zip
$ cd CloudWatch-1.0.12.1
$ cp credential-file-path.template credentials
$ vi credentials

CloudWatchを使うには、AWSのアクセスキーが無いといけません。しかし、むやみやたらとAWSのキーをコピーしたくないです。そこで、IAM(Identity and Access Management)でCloudWatchのみの操作を許可したユーザーを作ってあげればOKです。IAMで作成された制限ユーザーのアクセスキーとシークレットキーを保存しました。

AWSAccessKeyId=AKIasfowmeiuxfgoaiwexf(架空)
AWSSecretKey=lGZ98yLrnXchZ3847xtoiugxosirughxkrsdsgc(架空)

IAMでCloudWatch専用ユーザーを作成する。

IAMでCloudWatchのカスタムメトリクス登録専用のユーザーを作成します。具体的にはIAMでグループを作成し、ポリシーを付与します。そして、そのグループの下にユーザーを追加します。このユーザーがCloudWatchアクセス専用となるわけです。

ここでは、グループ名をCloudWatchPutDataPolicyとしました。

ポリシーの中身は以下です。

{
  "Statement": [
    {
      "Action": [
        "cloudwatch:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

bashで一連の処理を記述する

全ての準備が整いましたので、一連の処理を記述します。

$ cd
$ vi custom_metrics_report.sh

中身は以下です。

#!/bin/bash

export AWS_CLOUDWATCH_HOME=/home/ec2-user/CloudWatch-1.0.12.1
export AWS_CREDENTIAL_FILE=$AWS_CLOUDWATCH_HOME/credentials
export AWS_CLOUDWATCH_URL=https://monitoring.amazonaws.com
export PATH=$AWS_CLOUDWATCH_HOME/bin:$PATH
export JAVA_HOME=/usr/lib/jvm/jre

# get ec2 instance id
instanceid=`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`

memtotal=`free -m | grep 'Mem' | tr -s ' ' | cut -d ' ' -f 2`
memfree=`free -m | grep 'buffers/cache' | tr -s ' ' | cut -d ' ' -f 4`
let "memused=100-memfree*100/memtotal"

loadave1=`uptime | tr -s ' ' | cut -d ' ' -f 9 | cut -d ',' -f 1`
loadave5=`uptime | tr -s ' ' | cut -d ' ' -f 9 | cut -d ',' -f 2`
loadave15=`uptime | tr -s ' ' | cut -d ' ' -f 9 | cut -d ',' -f 3`
steal=`vmstat | tail -1 | tr -s ' ' | cut -d ' ' -f 18`

mon-put-data --metric-name "FreeMemoryMBytes" --namespace "System/Linux" --dimensions "InstanceId=$instanceid" --value "$memfree" --unit "Megabytes" --region ap-northeast-1

mon-put-data --metric-name "UsedMemoryPercent" --namespace "System/Linux" --dimensions "InstanceId=$instanceid" --value "$memused" --unit "Percent" --region ap-northeast-1

mon-put-data --metric-name "LoadAverage" --namespace "System/Linux" --dimensions "InstanceId=$instanceid" --value "$loadave1" --unit "Count" --region ap-northeast-1

mon-put-data --metric-name "Steal" --namespace "System/Linux" --dimensions "InstanceId=$instanceid" --value "$steal" --unit "Percent" --region ap-northeast-1

いやぁ、、、大作ですw。実行権限を与えます。そして実行してみます。

$ chmod 755 custom_metrics_report.sh
$ custom_metrics_report.sh

何もエラーがでなければ成功です。

cronにシェルを登録する

先ほど作ったシェルをcronに登録して自動実行させます。

$ crontab -e

中身はこんな感じ。5分に1回実行する記述です。保存します。

*/5 * * * * /home/ec2-user/custom_metrics_report.sh

登録できているか確認します。

$ crontab -l
*/5 * * * * /home/ec2-user/custom_metrics_report.sh

大丈夫そうです。5分ほど待ってエラーが無いかログも見てみましょう。

$ sudo cat /var/log/cron 
Sep 21 12:05:01 ip-10-146-9-61 CROND[21403]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:05:01 ip-10-146-9-61 CROND[21448]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:10:01 ip-10-146-9-61 CROND[21604]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:10:01 ip-10-146-9-61 CROND[21650]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:15:01 ip-10-146-9-61 CROND[21800]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:15:01 ip-10-146-9-61 CROND[21845]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:20:01 ip-10-146-9-61 CROND[21985]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:20:01 ip-10-146-9-61 CROND[22030]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:25:01 ip-10-146-9-61 CROND[22179]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:25:01 ip-10-146-9-61 CROND[22223]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:30:01 ip-10-146-9-61 CROND[22365]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)
Sep 21 12:30:01 ip-10-146-9-61 CROND[22410]: (ec2-user) CMD (/home/ec2-user/custom_metrics_report.sh)

エラーなく実行してくれていました!

Management Consoleで統計データを確認する

最後の確認です。Management Consoleで統計データを確認します。

ステキです。

カスタムメトリクスのアラートを設定する

自動運用に向けてアラートを設定します。5%を5分超えたらアラートです。今回は検証用に低い値を設定しています。

アラートの宛先はトピックです。このトピックはEメールでの通知となっています。

設定した閾値を超えたという表示です。実際に通知が来ているか確認します。

メールが届いていました。

ALARM: "Memory5%Over" in APAC - Tokyo
You are receiving this email because your Amazon CloudWatch Alarm "Memory5%Over" in the APAC - Tokyo region has entered the ALARM state, because "Threshold Crossed: 1 datapoint (7.5) was greater than or equal to the threshold (5.0)." at "Wednesday 21 September, 2011 12:52:11 UTC". 

View this alarm in the AWS Management Console: 
https://console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#s=Alarms&alarm=Memory5%25Over 

Alarm Details: 
- Name:                       Memory5%Over 
- Description:                
- State Change:               INSUFFICIENT_DATA -> ALARM 
- Reason for State Change:    Threshold Crossed: 1 datapoint (7.5) was greater than or equal to the threshold (5.0). 
- Timestamp:                  Wednesday 21 September, 2011 12:52:11 UTC 

Threshold: 
- The alarm is in the ALARM state when the metric is GreaterThanOrEqualToThreshold 5.0 for 300 seconds. 

Monitored Metric: 
- MetricNamespace:            System/Linux 
- MetricName:                 UsedMemoryPercent 
- Dimensions:                 [InstanceId = i-98320e99] 
- Period:                     300 seconds 
- Statistic:                  Average 
- Unit:                       not specified 

State Change Actions: 
- OK: 
- ALARM: [arn:aws:sns:ap-northeast-1:7456745674567456:mytopic1] 
- INSUFFICIENT_DATA:

まとめ

top/vmstat/uptime/freeなどのおなじみLinuxコマンドの結果を用いて、CloudWatchのカスタムメトリクスを登録できる事が分かりました。このメトリクスにアラートを登録しておけば、通知メールや自動処理を合わせて行う事ができ、EC2インスタンスの運用管理をほとんど任せる事ができるようになるかと思います。CloudWatchのカスタムメトリクスで人力作業をゼロにしましょう!

参考資料

Custom CloudWatch metric for memory? Reporting memory to CloudWatch...

Amazon CloudWatch Command Line Tool