AWS
CloudWatch

AWS CloudWatchにカスタムメトリクスを追加する方法を考える

はじめに

AWS CloudWatchにカスタムメトリクスを作って監視したい。思い立っていろいろ調べてみたので、
調べついでに覚書を残しておくことにする。CloudWatchは無料枠で10メトリクス、10アラームまで設定できる
ちなみに、設定さえすればオンプレミスなサーバの監視系データももっていける、持っていくメリットはないかもしれないが…

インストール

まず、カスタムメトリクスの追加に使うツールはおなじみのaws-apitools-monのmon-put-dataコマンドなので、これをインストールする。

※ちなみに、後から説明を読んでいて気付いたが、aws-cliでも同じことができる(徒労感が...)

aws cloudwatch put-metric-data [option] [option] [option]

といった感じ、mon-put-dataコマンドで送信に使えるオプションと使えるオプションは一緒。

パッケージ投入

  • MacOSX
brew install aws-mon
  • Debian
sudo apt-get aws-mon 
  • Amazon Linux
sudo yum install aws-apitools-mon
  • CentOS 6.x
sudo yum install perl-DateTime perl-CPAN perl-Net-SSLeay perl-IO-Socket-SSL perl-Digest-SHA gcc -y
sudo yum install zip unzip
sudo yum install cloud-init
curl -L -O http://ec2-downloads.s3.amazonaws.com/CloudWatch-2010-08-01.zip
unzip CloudWatch-2010-08-01.zip
sudo cp -rfp CloudWatch-1.0.20.0 /opt/aws/CloudWatch

※JDKもいるので入ってなければjava-1.8.0-openjdkかoracle jdkの1.8_u171以降を入れてください

sudo yum install java-1.8.0-openjdk
  • CentOS 7.x
sudo yum install perl-Switch perl-DateTime perl-Sys-Syslog perl-LWP-Protocol-https perl-Digest-SHA -y 
sudo yum install zip unzip
curl -L -O http://ec2-downloads.s3.amazonaws.com/CloudWatch-2010-08-01.zip
unzip CloudWatch-2010-08-01.zip
sudo cp -rfp CloudWatch-1.0.20.0 /opt/aws/CloudWatch

※JDKもいるので入ってなければjava-1.8.0-openjdkかoracle jdkの1.8_u171以降を入れてください

sudo yum install java-1.8.0-openjdk
  • その他のLinuxで、依存が解決できない場合は、CloudWatch-Agentのインストールをオススメします
curl -L -O https://s3.amazonaws.com/amazoncloudwatch-agent/linux/amd64/latest/AmazonCloudWatchAgent.zip
unzip AmazonCloudWatchAgent.zip
sudo ./install.sh
  • WindowsはCloudWatch-CLIは難しいので、おとなしくCloudWatch-Agentを入れるといいです
https://s3.amazonaws.com/amazoncloudwatch-agent/windows/amd64/latest/AmazonCloudWatchAgent.zip

Credentialについて

IAMのポリシー許可について、

 CloudWatchActionsEC2Access
 CloudWatchAgentAdminPolicy
 CloudWatchAgentServerPolicy

がついていれば問題ないはずです。ただ、CLI側からPUT以外もしたい場合は一旦

 CloudWatchFullAccess

つけて、アクセス状態を確認してから、徐々に閉じていくのも手かと。

Credentials Fileの書き方

AWS_CLOUDWATCH_HOMEで指定したパス以下にcredentialsファイルを作るのがおすすめです。パーミッションと400、オーナーはシェルやエージェントを実行するユーザにしておきましょう、書式は

credentials
AWSAccessKeyId=<Write your AWS access ID>
AWSSecretKey=<Write your AWS secret key>

Proxy 経由

何らかの事情でPROXYの裏側にサーバがいる場合、PROXYの設定をしてあげる必要があります
Linuxの場合は、/etc/bashrcに設定を書くか、エージェントとして動かすスクリプト側に定義

/etc/bashrc
USERNAME="<USERNAME>"       # 認証が必要なプロキシの場合
PASSWORD="<PASSWORD>"       # 認証が必要なプロキシの場合
HOST="<HOST>"
PORT1="<PORT>"              # 複数のポートがある場合 
PORT2="<PORT>"              # 複数のポートがある場合 

# 認証が必要なプロキシの場合
PROXY1="$USERNAME:$PASSWORD@$HOST:$PORT1"
PROXY2="$USERNAME:$PASSWORD@$HOST:$PORT2"

# 認証が不要なプロキシの場合
PROXY1="$HOST:$PORT1"
PROXY2="$HOST:$PORT2"

# 実際の環境変数の設定(http*/ftpとsocksは排他)
export http_proxy="http://$PROXY1"
export https_proxy="https://$PROXY1"
export ftp_proxy="ftp://$PROXY1"
#export http_proxy="socks5://$PROXY2"
#export https_proxy="socks5://$PROXY2"
#export ftp_proxy="socks5://$PROXY2"

# 大文字バージョンしか認識しないプログラム用(http*/ftpとsocksは排他)
export HTTP_PROXY="http://$PROXY"
export HTTPS_PROXY="https://$PROXY"
export FTP_PROXY="ftp://$PROXY"
#export HTTP_PROXY="socks5://$PROXY2"
#export HTTPS_PROXY="socks5://$PROXY2"
#export FTP_PROXY="socks5://$PROXY2"

# プロキシを利用しないアドレスの指定(CIDR設定はできないがワイルドカード指定はできる)
export no_proxy="10.*.*.*,172.16.*.*,192.168.*.*,*.local,localhost,127.0.0.1"
export NO_PROXY="$no_proxy"

CloudWatchにデータを送り込む

mon-put-dataコマンドで送信によく使うオプション
ほかのオプションは本家のヘルプを見ましょう
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/cli/cli-mon-put-data.html

namespace : カテゴリ(※必須項目)
 ANSIで250文字以内

metric-name : メトリクスの名前(※必須項目)
 ANSIで250文字以内、自由設定可能、ANSIなのでマルチバイトは無理

dimensions : 最大10個設定できるタグ(KeyはANSIで250文字以内、使えるkeyは決まっている)(任意項目)
 key1=value1, key2=value2

unit : メトリクスの単位、数とかパーセンテージとか
 (Micro/Milli)Seconds              : 時間の場合
 (Kilo/Mega/Giga/Tera)Bytes        : 容量の場合(バイト)
 (Kilo/Mega/Giga/Tera)bits         : 容量の場合(ビット)
 Percent                           : パーセント
 Count                             : 単純カウント
 (Kilo/Mega/Giga/Tera)Bytes/Second : 速度の場合(バイト/s)
 (Kilo/Mega/Giga/Tera)bits/Second  : 速度の場合(ビット/s)
 Count/Second                      : 速度の場合(回数/s)

value : 値

コマンドの書き方

mon-put-data --metric-name "メトリクスの名前" --namespace "メトリクスの名前空間" --dimensions "InstanceID=インスタンスのID" --value "値" --unit "Count"

サンプルスクリプト

以下は、EC2にマウントしたストレージの空き%を通知するものです。

disk_use_percent.sh
#!/bin/sh

#コマンドにパスを通す
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/aws/CloudWatch:/opt/aws/CloudWatch/bin

#CloudWatchツールへの環境変数
export AWS_CLOUDWATCH_HOME=/opt/aws/CloudWatch
export AWS_CREDENTIAL_FILE=/opt/aws/CloudWatch/credentials

###PROXY経由時有効にする
#PROXY="USERNAME:PASSWORD@HOST:PORT"  # 認証が必要なプロキシ
#PROXY="HOST:PORT"                    # 認証が不要なプロキシ
#export http_proxy="http://$PROXY"
#export https_proxy="https://$PROXY"
#export ftp_proxy="ftp://$PROXY"
### Proxyを使わないホスト(CIDR不可/ワイルドカード可)
#export no_proxy="10.*.*.*,192.168.*.*,*.local,localhost,127.0.0.1"
#export NO_PROXY="$no_proxy"

#インスタンス名とホスト名を動的に取得
INSTANCEID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
PUBLICNAME=`curl -s http://169.254.169.254/latest/meta-data/public-hostname`
#INSTANCEID=`curl -x "$PROXY" -s http://169.254.169.254/latest/meta-data/instance-id`
#PUBLICNAME=`curl -x "$PROXY" -s http://169.254.169.254/latest/meta-data/public-hostname`

#送るデータ用のコマンド
DISKUSE=`df |grep xvda1|awk '{print $5}'|tr -d '%'`

#エラー:データが100を超えてる場合
if [ ${DISKUSE} -gt 100 ]; then
  echo "Error : Illegal Data : ${DISKUSE}"
  exit 1
fi

#エラー:データが-値の場合
if [ ${DISKUSE} -lt 0 ]; then
  echo "Error : Illegal Data : ${DISKUSE}"
  exit 1
fi

#エラー:データがNullの場合
if [ "x${DISKUSE}" = "x" ]; then
  echo "Error : Illegal Data : ${DISKUSE}"
  exit 1
fi

#データ送信
mon-put-data --metric-name "Disk Use" --namespace "${PUBLICNAME}" --dimensions "InstanceId=${INSTANCEID}" --value "${DISKUSE}" --unit "Percent"

いろいろと紆余曲折がありましたが、一旦はデータがCloudWatchに送られて表示できるようになりました
CloudWatchのコマンドが2010-08-01から更新されてない点とか、本家マニュアルが英語のままとか、いろいろ突っ込みたいけど
将来的には、CloudWatch Agentに集約したいんだろうなという意図が見える感じですね。

以上、だれかの参考になればいいな。