zabbix外部チェックでcloudwatch連携

[ディップ Advent Calendar](http://qiita.com/advent-calendar/2016/dip-dev) の5日目です。

ようやくQiita初投稿。
普段はインフラエンジニアとしてサーバ構築や日々の運用をしつつ、ansibleでのサーバ管理、fluentdでのログ収集、Kibanaでのログ可視化などに取り組んでいます。
今回はZabbixとCloudWatch連携について書いていきます。

#目的
ZabbixでCloudwatchが取得したリソースデータの蓄積をしていく。
#対象
ELB(ALB)
RDS(Aurora)
ElasticCache(Radis)
※EC2はいくつか記事が出ているため今回はEC2以外での連携を試みました。
#方法
Zabbixの外部チェック機能であらかじめ用意したcloudwatch get-metric-statisticsのシェルを実行し、取得した値をZabbix外部チェック機能でZabbixDBに取り込む。

#外部チェックとは
Zabbixサーバがシェルスクリプトまたはバイナリを実行することで行われるチェックのこと。

構文：`script[<parameter1>,<parameter2>,...]`

|引数 |定義|
|:------|:-----|
|script	|シェルスクリプトまたはバイナリの名前|
|parameter(s) | オプションのコマンドラインパラメータ|


**つまり**

1. 外部チェックのExternalScriptsで指定された/usr/lib/zabbix/externalscripts/以下に、実行したいシェルを設置。
2. Zabbixの設定画面で外部チェックを選択し構文を記載。
3. 1-2が連携しparameter(s)に記載した値を引数としシェル実行を行ってくれるイメージ。

　例.
　設置シェル：`/usr/lib/zabbix/externalscripts/test.sh`
　外部チェック欄での設定構文：`test.sh[host=test,date=20161201]`
　↓
　Linux上での挙動：`/usr/lib/zabbix/externalscripts/test.sh host=test date=20161201`

#スクリプト
- classmethod様の[記事で紹介されていたスクリプト](http://dev.classmethod.jp/cloud/aws/aws-shellscript-summary/#toc-2)を元に作成。
- sort,tail,awkだと特定の項目の抽出を汎用的に行うのが難しかったのでjqコマンドを使用
- 更新間隔は300秒(300秒以下だと有料になってしまうため)
- 統計はAverageを選択(1分毎の直近5分間の平均値が取得できる)
- スクリプト内では固定値だが(`period,start-time,end-time`)の時間によって項目が2個以上出力されてしまう場合があるので、`head -1`で1項目のみ出力するように設定。※後述で記載

■Zabbixサーバ内に設置

```/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 '5 minutes ago'` \
 --end-time `date --iso-8601=seconds --date '0 minutes ago'` | /usr/bin/jq -r ".Datapoints[].Average" | head -1
```

#取得したいリストを検索
1. cloudwatch list-metrics コマンドを使い、取得したい値の情報(ここではRequestCount)を取得
    - --dimensionsオプションはわかればでOK。
- 項目が複数表示されるがほぼほぼどれも同じものなのでどれか一つを選択
    - 細かく言えば意味合いは異なるらしい…

    ```
aws cloudwatch list-metrics --namespace AWS/ApplicationELB --metric-name RequestCount --dimensions Name=LoadBalancer,Value=app/xxxxxxxxx/xxxxxxxxx
    "Metrics": [
        {
            "Namespace": "AWS/ApplicationELB",
            "Dimensions": [
                {
                    "Name": "LoadBalancer",
                    "Value": "app/xxxxxxxxx/xxxxxxxxx"
                }
            ],
            "MetricName": "RequestCount"
        },
        {
            "Namespace": "AWS/ApplicationELB",
            "Dimensions": [
                {
                    "Name": "LoadBalancer",
                    "Value": "app/xxxxxxxxx/xxxxxxxxx"
                },
                {
                    "Name": "AvailabilityZone",
                    "Value": "ap-northeast-1a"
                }
            ],
            "MetricName": "RequestCount"
        },
        {
            "Namespace": "AWS/ApplicationELB",
            "Dimensions": [
                {
                    "Name": "TargetGroup",
                    "Value": "targetgroup/yyyyyyyyyyy/yyyyyyyyyyy"
                },
                {
                    "Name": "LoadBalancer",
                    "Value": "app/xxxxxxxxx/xxxxxxxxx"
                }
            ],
            "MetricName": "RequestCount"
        },
・
・
省略
```
- cloudwatch get-metric-statisticsで選択したデータのdimensionsを指定し値が帰ってくるか確認。
    - 対象のdimensionsが２つ以上ある場合はスペース区切りで複数個記載する必要あり
    
    ```
aws cloudwatch get-metric-statistics --region ap-northeast-1 --period 180  --namespace AWS/ApplicationELB --dimensions Name=LoadBalancer,Value=app/xxxxxxxxx/xxxxxxxxx Name=TargetGroup,Value=targetgroup/yyyyyyyyyyy/yyyyyyyyyyy --statistics  Maximum  --start-time 2016-11-28T16:29:22+0900  --end-time 2016-11-28T16:32:22+0900 --metric-name UnHealthyHostCount
{
    "Datapoints": [
        {
            "Timestamp": "2016-11-28T07:29:00Z",
            "Maximum": 0.0,
            "Unit": "Count"
        }
    ],
    "Label": "UnHealthyHostCount"
}
```
    - この時periodとstart-time~endtimeの時間があっていないと値が２つ以上表示される。

        - periodが60に対し、start-time~endtimeが180秒の場合

        ```
aws cloudwatch get-metric-statistics --region ap-northeast-1 --period 60  --namespace AWS/ApplicationELB --dimensions Name=LoadBalancer,Value=app/xxxxxxxxx/xxxxxxxxx Name=TargetGroup,Value=targetgroup/yyyyyyyyyyy/yyyyyyyyyyy --statistics  Maximum  --start-time 2016-11-28T16:29:22+0900  --end-time 2016-11-28T16:32:22+0900 --metric-name UnHealthyHostCount
{
    "Datapoints": [
        {
            "Timestamp": "2016-11-28T07:31:00Z",
            "Maximum": 0.0,
            "Unit": "Count"
        },
        {
            "Timestamp": "2016-11-28T07:30:00Z",
            "Maximum": 0.0,
            "Unit": "Count"
        },
        {
            "Timestamp": "2016-11-28T07:29:00Z",
            "Maximum": 0.0,
            "Unit": "Count"
        }
    ],
    "Label": "UnHealthyHostCount"
}
```
        - periodが180に対し、start-time~endtimeが360秒の場合

        ```
aws cloudwatch get-metric-statistics --region ap-northeast-1 --period 180  --namespace AWS/ApplicationELB --dimensions Name=LoadBalancer,Value=app/xxxxxxxxx/xxxxxxxxx Name=TargetGroup,Value=targetgroup/yyyyyyyyyyy/yyyyyyyyyyy --statistics  Maximum  --start-time 2016-11-28T16:29:22+0900  --end-time 2016-11-28T16:35:22+0900 --metric-nam
e UnHealthyHostCount
{
    "Datapoints": [
        {
            "Timestamp": "2016-11-28T07:32:00Z",
            "Maximum": 0.0,
            "Unit": "Count"
        },
        {
            "Timestamp": "2016-11-28T07:29:00Z",
            "Maximum": 0.0,
            "Unit": "Count"
        }
    ],
    "Label": "UnHealthyHostCount"
}
```


 

#Zabbixサーバ
- これまでの情報を元に実際にZabbixでのデータ取得とグラフ化を行います。

１. テンプレート作成

![image](https://qiita-image-store.s3.amazonaws.com/0/139461/2807b277-c464-675e-2172-187d197c0c70.png)


２．テンプレートアイテム作成

タイプ：外部チェック
構文：`cloudwatch.sh["-n AWS/ApplicationELB","-d {$DNAME1},{$DVALUE1} {$DNAME2},{$DVALUE2}","-m UnHealthyHostCount","-s Maximum"]`
※ホストによって変えたい部分は変数化しておく`{$DNAME1},{$DVALUE1}`

![WS000043.JPG](https://qiita-image-store.s3.amazonaws.com/0/139461/2d45254b-775d-c482-9f06-356ad815353a.jpeg)



３. ホスト作成
・テンプレートタブ設定
　作成したテンプレートを選択
![WS000044.JPG](https://qiita-image-store.s3.amazonaws.com/0/139461/4ff0b27a-4aec-970a-426e-e3c611a35d85.jpeg)

・マクロタブ設定
外部チェックに記載したいcloudWatch get-metric-statisticsのディストリビューションを記載しておく。
　![image](https://qiita-image-store.s3.amazonaws.com/0/139461/0351a1b8-c7de-c044-92e1-bd5608f5988e.png)

４.グラフの確認
以下の通りグラフに値が出力されていることを確認。
![image](https://qiita-image-store.s3.amazonaws.com/0/139461/56a1b3eb-16e1-3889-0b10-ff6298d1cd9b.png)

###同様の手順で他のALB項目、ElasticCache、RDSの値についても登録を行う。
#####以下それぞれの取得項目
・ELB(ALB)
※CloudWatchの仕様上1回も出力されてない項目はCloudwatchのメトリクスにも表示されないらしく一部値が取れていなかった。
![image](https://qiita-image-store.s3.amazonaws.com/0/139461/aeda3f61-7fa2-54c4-d078-721aa1eaae8c.png)

・ElasticCache(Radis)
![image](https://qiita-image-store.s3.amazonaws.com/0/139461/15ccb1f9-e4ef-8e12-bc39-f05e0d953bf6.png)

・RDS(Aurora)
![image](https://qiita-image-store.s3.amazonaws.com/0/139461/333a344a-200e-44b9-68a7-d26efb8a6d10.png)

#苦労した点
- Zabbix-CloudWatchの連携方法がいくつかありどの方法で取得するのか、またその仕組みについての理解に時間がかかった。(結局一番シンプルそうなAWSCLIのシェル化×Zabbix外部チェックに落ち着いた。)
- ALBのCloudWatchのメトリクスが、以下のように様々に分かれており、取りたい項目によって指定するdimensionsが異なるため、どれを取るか迷った。(メトリクスによって値を示すため意味合いが違うためこのようにわかれているとのこと)
    - 「AppELB 別メトリクス」
    - 「AppELB 別、TG 別メトリクス」
    - 「AppELB 別、AZ 別メトリクス」
    - 「AppELB 別、AZ 別、TG 別メトリクス」
- AuroraのCloudwatch使用可能メトリクス(日本語版ドキュメント)の中で使用されていない項目が記載されていたため、描画ができていなかった。※サポート報告済み
    - Auroraは`FreeStorageSpace`ではなく`Freelocalstorage`を参照しているとの事。英語版では正しい記載になっているが日本版では更新遅れの状態。(2016/12/02現在)
        - [日本語版ドキュメント](
http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Aurora.Monitoring.html)
        - [英語版ドキュメント](
http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Aurora.Monitoring.html#Aurora.Monitoring.Metrics)

#今後の課題
- 外部チェックを使用すると「サーバスペック」、「取得間隔」、「監視ホスト数」によってキューが滞留が発生する可能性があるためサーバのリソース周りの検証を行い監視が停止しないように心掛ける。

以上