AWS Amazon CloudWatchにカスタムメトリクスを送信・登録するシェルスクリプト(バッチ処理プログラム) ~サーバから取得したLoad Average、空きメモリ容量、メモリ使用率、空きディスク容量、ディスク使用率、Apacheプロセス数、HTTP(80番ポート)・HTTPS(443ポート)接続数、アクティブセッション数などのローカルでの値表示にも対応~

2月 23, 2017AWS,AWS CLI,CloudWatch,EC2,Programming,Shell Script

AWSのAmazon EC2でサーバを運用している場合に定期的にモニタリングするサービスとしてAmazon CloudWatchがあります。

ただ、Amazon CloudWatchで提供されているメトリクスはCPUなど一般的なものはありますが、ロードアベレージ、メモリ使用率、Webサーバの接続数などサーバ上でしか取得できないものをCloudWatchで監視する場合には対象サーバのメトリクスをカスタムメトリクスとして登録する必要があります。

Amazon CloudWatchへのカスタムメトリクスの登録はAWS CLIで可能であり、様々な実装方法があります。

今回はLinuxサーバでAmazon CloudWatchのカスタムメトリクスに登録しておくべき、一般的なメトリクスの取得と送信・登録に加えて、AWSはもちろんですがAWS以外のサーバでも使用できる標準出力でのメトリクス取得にも対応したシェルスクリプト(バッチ処理プログラム)を備忘録として紹介します。

AWS Amazon CloudWatchにカスタムメトリクスを送信・登録するシェルスクリプト(バッチ処理プログラム) ~サーバから取得したLoad Average、空きメモリ容量、メモリ使用率、空きディスク容量、ディスク使用率、Apacheプロセス数、HTTP(80番ポート)・HTTPS(443ポート)接続数、アクティブセッション数などのローカルでの値表示にも対応~

基本方針としては引数に「aws」と入力するかしないかでAmazon CloudWatchにカスタムメトリクスを送信するか、標準出力にするかを判定し、下記のメトリクスを送信・登録もしくは標準出力します。

<取得するメトリクス>

  • Load Average(1分平均、5分平均、15分平均)
  • CPU使用率
  • メモリー空き容量
  • メモリー使用率
  • ディスク空き容量
  • ディスク使用率
  • Apacheプロセス数
  • HTTP(80番ポート)接続数
  • HTTPS(443番ポート)接続数
  • アクティブセッション数(TIME_WAIT等含む)

AWS Amazon CloudWatchにカスタムメトリクスを送信・登録するシェルスクリプト(バッチ処理プログラム)

プログラムの内容はAmazon CloudWatchにカスタムメトリクスを送信するか、標準出力にするかを判定する関数を用意し、その関数にAmazon CloudWatchのリージョン、ネームスペース、インスタンスID、ホスト名、ユニット単位、メトリクス名、メトリクス値、標準出力で使用するオプション値を渡して処理します。

[root@localhost ~]# vim output_custom_metrics.sh
#!/bin/bash

#CloudWatchに送信するか標準出力に表示するかを判定して実行するカスタムレポート関数
output_custom_reports () {
  #各引数の対応付け
  IS_AWS=$1
  REGION=$2
  NAMESPACE=$3
  INSTANCE_ID=$4
  HOST_NAME=$5
  UNIT=$6
  METRIC_NAME=$7
  VALUE=$8
  ADDITIONAL_VALUE=$9

  if [ "${IS_AWS}" = "1" ]; then
    #aws引数があった場合はAWS CLIでCloudWatchにカスタムメトリクスを送信する。
    if [ "${VALUE}" != "" ]; then
      aws cloudwatch put-metric-data --metric-name "${METRIC_NAME}" --namespace "${NAMESPACE}" --dimensions "InstanceId=${INSTANCE_ID}, Hostname=${HOST_NAME}" --value "${VALUE}" --unit "${UNIT}" --region ${REGION}
    fi
  else
    #aws引数がない場合は標準出力にメトリクスの内容を表示する。
    if [ "${ADDITIONAL_VALUE}" != "" ]; then
      #ADDITIONAL_VALUEがあれば文字列を追加して表示する。
      echo "${METRIC_NAME}(${UNIT}): ${VALUE} / ${ADDITIONAL_VALUE}"
    else
      #ADDITIONAL_VALUEがなければメトリクス名、ユニット単位、値を表示。
      echo "${METRIC_NAME}(${UNIT}): ${VALUE}"
    fi
  fi
}

#CloudWatchのリージョンを指定
REGION="ap-northeast-1"
#AWS CLIのaws cloudwatch put-metric-dataで使用するnamespace, instanceId, Hostnameを指定する。
NAMESPACE="YourNameSpace: Custom Instance Metric"
INSTANCE_ID="your-instance-id"
HOST_NAME="your-hostname"

#シェルスクリプトの引数を取得する。
MODE=$1
#取得した引数を全て小文字にする。
MODE=`echo "${MODE}" | tr 'A-Z' 'a-z'`

IS_AWS=0
#引数がawsであればIS_AWS=1にする。
if [ "${MODE}" = "aws" ]; then
  IS_AWS=1
fi

#ロードアベレージの1分平均、5分平均、15分平均を取得する。
LOAD_AVERAGES=`uptime | awk 'BEGIN{FS="load average: "}{print $2}' | sed 's/,//g'`

#ロードアベレージの1分平均を取得する。
LOAD_AVERAGE_1=`echo ${LOAD_AVERAGES} | awk '{print $1}'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Count" "LoadAverage1Minute" "${LOAD_AVERAGE_1}" ""

#ロードアベレージの5分平均を取得する。
LOAD_AVERAGE_5=`echo ${LOAD_AVERAGES} | awk '{print $2}'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Count" "LoadAverage5Minutes" "${LOAD_AVERAGE_5}" ""

#ロードアベレージの15分平均を取得する。
LOAD_AVERAGE_15=`echo ${LOAD_AVERAGES} | awk '{print $3}'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Count" "LoadAverage15Minutes" "${LOAD_AVERAGE_15}" ""

#CPU使用率をvmstatコマンドで取得する。
CPU_UTILIZATION=$((100 - `vmstat 1 2 | tail -n 1 | awk '{print $(NF-2)}'`))
#カスタムレポート関数を実行する。output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Percent" "CPUUtilization" "${CPU_UTILIZATION}" ""

#合計メモリ容量を取得する。
MEMTOTAL=`free -m | grep Mem | awk '{print $2}'`
#空きメモリ容量を取得する。
MEMFREE=`free -m | grep Mem | awk '{print $NF}'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Megabytes" "FreeMemoryBytes" "${MEMFREE}" "${MEMTOTAL}"

#メモリ使用率を合計メモリ容量、空きメモリ容量を元に計算する。
MEMORY_UTILIZATION=`echo "scale=4;$(( ${MEMTOTAL} - ${MEMFREE} )) / ${MEMTOTAL} * 100" | bc -l | sed 's/00$//g'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Percent" "MemoryUtilization" "${MEMORY_UTILIZATION}" ""

#合計ディスク容量を取得する。
DISKTOTAL=`df -m | awk 'NR==2' | awk '{print $2}'`
#空きディスク容量を取得する。
DISKFREE=`df -m | awk 'NR==2' | awk '{print $4}'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Megabytes" "FreeDiskBytes" "${DISKFREE}" "${DISKTOTAL}"

#ディスク使用率を合計ディスク容量、空きディスク容量を元に計算する。
DISK_UTILIZATION=`echo "scale=4;$(( ${DISKTOTAL} - ${DISKFREE} )) / ${DISKTOTAL} * 100" | bc -l | sed 's/00$//g'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Percent" "DiskUtilization" "${DISK_UTILIZATION}" ""

#Apacheプロセス数をpsコマンドで取得する。
NUMBER_OF_PROCESSES=$(( `ps -e | grep httpd | wc -l` - 1 ))
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Count" "NumberOfApacheProcesses" "${NUMBER_OF_PROCESSES}" ""

#80番ポート接続数をnetstatコマンドで取得する。
PORT_COUNT80=`netstat -an | grep :80 | grep ESTABLISHED | wc -l`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Count" "PortCount80" "${PORT_COUNT80}" ""

#443番ポート接続数をnetstatコマンドで取得する。
PORT_COUNT443=`netstat -an | grep :443 | grep ESTABLISHED | wc -l`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Count" "PortCount443" "${PORT_COUNT443}" ""

#80番ポート、443番ポートの全アクティブセッション数(TIME_WAIT等も含む)を取得する。
ACTIVE_SESSION_COUNT=`netstat -alpn | grep -E ':(80|443) ' | awk {'print $5'} | cut -d : -f1 | sort -n | uniq -c | sort -n | awk '{total = total + $1} END{print total;}'`
#カスタムレポート関数を実行する。
output_custom_reports "${IS_AWS}" "${REGION}" "${NAMESPACE}" "${INSTANCE_ID}" "${HOST_NAME}" "Count" "ActiveSessionCount" "${ACTIVE_SESSION_COUNT}" ""


AWS Amazon CloudWatchにカスタムメトリクスを送信・登録するシェルスクリプト(バッチ処理プログラム)の実行例

上記のシェルスクリプト(バッチ処理プログラム)を引数無しで実行した例と「aws」の引数を渡して実行した例を記載します。

[root@localhost ~]# chmod 755 output_custom_metrics.sh
[root@localhost ~]# ./output_custom_metrics.sh
LoadAverage1Minute(Count): 0.05
LoadAverage5Minutes(Count): 0.15
LoadAverage15Minutes(Count): 0.20
FreeMemoryBytes(Megabytes): 13500 / 15000
MemoryUtilization(Percent): 10.00
FreeDiskBytes(Megabytes): 295000 / 300000
DiskUtilization(Percent): 1.66
NumberOfApacheProcesses(Count): 5
PortCount80(Count): 100
PortCount443(Count): 0
ActiveSessionCount(Count): 300
[root@localhost ~]# ./output_custom_metrics.sh aws
~バックグラウンドでAmazon CloudWatchにカスタムメトリクスを送信する~

Reference: Tech Blog citing related sources