zabbix cloudwatch連携

#目的
Steal値もCPU使用率に含めるCloudWatchを使いたい。Cloudwatchが取得したリソースデータを2週間以上蓄積してドリルダウンしたい。などの要件に応える。（監視だけで言うと個人的にはzabbixのCPU idle timeでいいと思う）

#環境
AWS
zabbix2.2
#方法
cloudwatch get-metric-statisticsを使用し、取得した値をZabbix外部チェック機能でZabbixDBに取り込む。

#設定
Zabbixサーバは、外部スクリプトの場所として定義されたディレクトリを調べて、そのコマンドを実行する。
Fluentdで取得する方法もあるが、td-agentがストールした際、ログ収集と監視の両機能が使えなくなる可能性があるので、見送り。


```bash
$ sudo cat /etc/zabbix/zabbix_server.conf | grep externalscripts
# ExternalScripts=${datadir}/zabbix/externalscripts
ExternalScripts=/usr/lib/zabbix/externalscripts
```
##スクリプト作成
* classmethodさんの[記事で紹介されていたスクリプト](http://dev.classmethod.jp/cloud/aws/aws-shellscript-summary/#toc-2)を利用させてもい、少し変更を入れました。
* --period 300というのは期間の長さで300は秒数(デフォルトは60)
    * 60秒だと課金が発生する(5分の統計までは無料)
*  StartTimeおよびEndTimeでは、統計に関連する全体の時間長を決定(デフォルトは過去1時間)
    *  StartTimeを6分前、EndTimeを1分前にしておくことで、実質60秒毎の統計が得られる。
*  [公式サイト](https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CW_Support_For_AWS.html)にある名前空間・メトリックス・ディメンジョンをパラメータで指定することで目的の値を取ることが出来る。
*  浮動小数点でないとZabbixが認識できないため、jqで整形します。

```bash:/usr/lib/zabbix/externalscripts/cloudwatch.sh
#!/bin/bash

while getopts n:d:m:s: OPT
do
  case ${OPT} in
    n) NAMESPACE=${OPTARG} ;;
    d) DIMENSIONS=${OPTARG} ;;
    m) METRIC=${OPTARG} ;;
    s) STATISTICS=${OPTARG} ;;
    *) exit 1 ;;
  esac
done

### example
# ./cloudwatch.sh -n AWS/[EC2,RDS] -d Name=[InstanceId,mydbinstance],Value=[instanceID,mydbinstance] -m CPUUtilization -s Maximum

aws cloudwatch get-metric-statistics --region ap-northeast-1 --period 300 \
 --namespace ${NAMESPACE} \
 --dimensions ${DIMENSIONS} \
 --metric-name ${METRIC} \
 --statistics ${STATISTICS} \
 --start-time `date --iso-8601=seconds --date '6 minutes ago'` \
 --end-time `date --iso-8601=seconds --date '1 minutes ago'` | jq -r ".Datapoints[].Maximum"
```


##Zabbix
* アイテムキーの構文
    * [サイト](https://www.zabbix.com/documentation/2.2/manual/config/items/itemtypes/external)にも記述があるように外部チェック機能を使用するとZabbixサーバのCPU使用率が上昇するので、バースト機能をもったt2タイプではなく、CPUをフルに使える最適化されたC4タイプのインスタンスを使用するべきです。

```text
script[<parameter1>,<parameter2>,...]
```
###例
* ZabbixServerのCPU使用率を取得

```bash
cloudwatch.sh["-n AWS/EC2","-d Name=InstanceId,Value=i-*****","-m CPUUtilization","-s Maximum"]
```

* 5分毎にピークが記録されていきます。

![Screenshot from 2016-02-18 12:05:58.png](https://qiita-image-store.s3.amazonaws.com/0/58788/631f32f9-c3bb-6b9f-7277-9d2525cf8115.png)
####補足1
* 外部チェックの更新間隔を60秒、Refresh unsupported itemsを30秒に設定しAPIを叩いてみると、値を取った2分後に値が取れなくなり、値が取れなくなってから3分後にまた値が取れ始めるようになるというサイクルがログに出力されていた。これだと、グラフ化した際にピークとピークがつながらず、グラフ線が途切れ途切れになってしまうため、外部チェックの更新間隔は300秒、Refresh unsupported itemsを180秒に設定する。

```bash:/var/log/zabbix/zabbix_server.log
became supported
4481:20160208:110734.416
became not supported
4481:20160208:110934.468
became supported
4482:20160208:111234.564
became not supported
4484:20160208:111434.630
became supported
4482:20160208:111734.773
became not supported
4481:20160208:111934.865
became supported
4484:20160208:112234.967
```

####補足2
* awscliを実行するにはIAMユーザもしくはIAMロールで実行許可されている必要がある。EC2に実行許可のポリシーがアタッチされたロールが付与されている場合はそのまま実行できるが、IAMで権限が管理されている場合は対応が必要になる。
    * rootのみawscliが実行できる設計の場合、/root/.aws/credensialに用途に分けてIAMユーザのKeyを定義することが多いので、スクリプトの中でどれを使用するかをセキュリティの観点からkeyを書かずに--profileで指定する。
    * zabbixユーザがスクリプト実行時にパスワードを求められないようにsudoersにも記述する

```bash:/root/.aws/credensial
[default]
aws_access_key_id = **************
aws_secret_access_key = ***********************
[s3]
aws_access_key_id = **************
aws_secret_access_key = ***********************
[clowdwatch]
aws_access_key_id = **************
aws_secret_access_key = ***********************
[rds]
aws_access_key_id = **************
aws_secret_access_key = ***********************
```

```bash:/usr/lib/zabbix/externalscripts/cloudwatch.sh
#!/bin/bash

while getopts n:d:m:s: OPT
do
  case ${OPT} in
    n) NAMESPACE=${OPTARG} ;;
    d) DIMENSIONS=${OPTARG} ;;
    m) METRIC=${OPTARG} ;;
    s) STATISTICS=${OPTARG} ;;
    *) exit 1 ;;
  esac
done

### default EC2 metric
# CPUCreditBalance,CPUCreditUsage,CPUUtilization,DiskReadBytes,DiskReadOps,DiskWriteBytes,DiskWriteOps,NetworkIn,NetworkOut,StatusCheckFailed,StatusCheckFailed_Instance,StatusCheckFailed_System 

### example
# ./cloudwatch.sh -n AWS/[EC2,RDS] -d Name=[InstanceId,mydbinstance],Value=[instanceID,mydbinstance] -m CPUUtilization -s Maximum

sudo aws cloudwatch get-metric-statistics --profile clowdwatch --region ap-northeast-1 --period 300 \
 --namespace ${NAMESPACE} \
 --dimensions ${DIMENSIONS} \
 --metric-name ${METRIC} \
 --statistics ${STATISTICS} \
 --start-time `date --iso-8601=seconds --date '6 minutes ago'` \
 --end-time `date --iso-8601=seconds --date '1 minutes ago'` | jq -r ".Datapoints[].Maximum"
```

```bash:/etc/sudoers.d/zabbix
zabbix ALL=(ALL) NOPASSWD:/usr/bin/aws cloudwatch
```