【Datadog】Amazon AuroraのWriter, Readerロールを表示

# はじめに
AWS Aurora MySQLで複数台のクラスタを組んで構成しています。
この時、DBのCPU使用率(aws.rds.cpuutilization)などのメトリクスをDatadogで表示させているのですが、
クラスタを構成するどのインスタンスがWriter、Readerなのかがわかりません。
なので、それぞれのインスタンスのロールを示すカスタムメトリクスを作りました。
AuroraのMySQLで動かしていますが、PostgreSQLでも同じもので動くはずです。

# 構成
ECS(Fargate)上に建てたDatadogAgent専用のコンテナ上で判別スクリプトを動かし、
それをDatadogへ送信する。という構成です。
参考：[運用しやすい Datadog カスタムメトリクス収集方法](https://qiita.com/spesnova/items/45b8d799d16e42267c4f)
[Datadogドキュメント カスタム Agent チェック](https://docs.datadoghq.com/ja/developers/write_agent_check/?tab=agentv6v7)

CodeCommitにソースを保存して、CodePipelineで反映する構成にしてみました。
+ checks.d/custom_aurora.py
+ conf.d/custom_aurora.yaml
+ buildspec.yml
+ docker-compose.yml
+ Dockerfile
+ requirements.txt

これらをCodeCommitに保存し、CodePipelineでビルドされるように設定します。
CodePipelineやFargateの設定については本記事では省略させていただきます。

## 各ファイル
### checks.d/custom_aurora.py
Auroraの各インスタンスがWriterなのかReaderなのかを知るには[describe_db_clusters](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html#RDS.Client.describe_db_instances)を使います。
レスポンスの中の __IsClusterWriter__ がTrueかFalseかで判断できます。
メトリクス値としては数値しか返せないので、0=Reader, 1=Writer というカスタムメトリクス(custom_aurora.instance.role)を返すことにします。

```python:custom_aurora.py
from checks import AgentCheck
import boto3

class customAurora(AgentCheck):

    CLUSTER = 'クラスタの名前'

    # Datadogエージェントから呼ばれる
    def check(self, instance):
        # インスタンス役割(0=Reader, 1=Writer)    custom_aurora.instance.role
        host_roles = self.__describe_role()
        for host, writer in host_roles.items():
            # print(f"host_role: host={host} writer={writer}")
            self.gauge('custom_aurora.instance.role', writer, tags=[f"hostname:{host}"] + self.instance.get('tags', []))


    ##### custom_aurora.instance.roleのための処理 #####
    # インスタンス役割(0=Reader, 1=Writer)
    def __describe_role(self):
        host_roles = {}  # 例： {host1:1, host2:0}
        # クラスタ情報から配下のインスタンスを取得
        rds = boto3.client('rds')
        res = rds.describe_db_clusters(DBClusterIdentifier=self.CLUSTER)
        members = res['DBClusters'][0]['DBClusterMembers']
        
        for member in members:
            host = member['DBInstanceIdentifier']
            writer = 1 if member['IsClusterWriter'] else 0  # 0=Reader 1=Writer
            host_roles.update({host: writer})
            
        return host_roles
```

### conf.d/custom_aurora.yaml
カスタムメトリクスの取得間隔を設定します。
メトリクス値にtagを付ける場合もここで。

```yaml:custom_aurora.yaml
init_config:

instances:
  - min_collection_interval: 60
```

### buildspec.yml
CodePipeline、CodeBuildに実行させるためのファイルです。
環境変数はCodePipelineで該当する値を設定します。

```yaml:buildspec.yml
version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t ${IMAGE_REPO_NAME}:$IMAGE_TAG .
      - echo docker tag ${IMAGE_REPO_NAME}:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/${IMAGE_REPO_NAME}:$IMAGE_TAG
      - docker tag ${IMAGE_REPO_NAME}:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/${IMAGE_REPO_NAME}:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/${IMAGE_REPO_NAME}:$IMAGE_TAG
      - printf '[{"name":"<container-definition>","imageUri":"%s"}]' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/${IMAGE_REPO_NAME}:$IMAGE_TAG > artifacts.json

artifacts:
  files: artifacts.json
```

### docker-compose.yml
[Amazon ECR Public GalleryのDatadogAgent](https://gallery.ecr.aws/datadog/agent)を取ってきます。

```yaml:docker-compose.yml
version: '3'
services:
  datadog:
    image: public.ecr.aws/datadog/agent:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /proc/:/host/proc/:ro
      - /sys/fs/cgroup:/host/sys/fs/cgroup:ro
    logging:
      driver: 'none'
```

### Dockerfile
上記のcustom_aurora.py、custom_aurora.yamlをDatadogAgentの場所にコピーします。

```
FROM public.ecr.aws/datadog/agent:latest

# Pythonモジュールのインストール
COPY requirements.txt .
RUN pip install --no-cache-dir --trusted-host pypi.python.org -r requirements.txt

# custom_aurora
COPY checks.d/custom_aurora.py /etc/datadog-agent/checks.d/custom_aurora.py
COPY conf.d/custom_aurora.yaml /etc/datadog-agent/conf.d/custom_aurora.yaml
```

### requirements.txt

```txt:requirements.txt
boto3
```

# Datadog
上記でECS(Fargate)にDatadogAgent専用タスクを作り、しばらくするとメトリクス(custom_aurora.instance.role)が送られてきます。
tag:hostnameでどのインスタンスのメトリクスなのかを判別することができます。
ダッシュボードなどに送られてきた値である0 or 1をそのまま表示してもよいのですが、
Reader, Writerといった文字を表示したい場合は、そのような画像を表示させることで対応します。
参考：[[Datadog] 小粒なTips集・ダッシュボード編](https://qiita.com/stanabe/items/e4d9bfcd113294cf57da#query-value%E3%82%A6%E3%82%A4%E3%82%B8%E3%82%A7%E3%83%83%E3%83%88%E3%81%AE%E7%94%BB%E5%83%8F%E8%A1%A8%E7%A4%BA)

# おわりに
Auroraではインスタンスがどちらのロールなのかで、監視すべき点が変わってくることがありますので、
本記事の判別方法を参考にしていただければ幸いです。