CloudWatchAlarmとSNSとChatbotで監視とSlack通知を設定する

やりたかったこと

EC2の監視を外部サービスに依存せず、AWSの機能だけで行いたかったのと通知先はSlackにしたかったので下記を利用して設定した際のメモです。

  • CloudWatch(アラーム、エージェント、メトリクス)
  • SNS
  • AWS Chatbot

結論

先に結論を書くと、今のところ、監視はAWSの仕組みを使わずに外部サービスを使った方が良いかもな〜というのが私の感想です。
CloudWatchで取得できるメトリクスをモニタリング対象にして閾値をこえたら通知させることができるのですが、私が単にやりたかったことはディスクの容量やCPU使用率、メモリ使用率だけのシンプルなものに対して、かなり複数の要素が出てきて中々大変でした。
上記をやるだけならMackerelとかの方が圧倒的に楽です。
もしかしたらもっと良い方法があったのかもしれないですが、とりあえず私がやったことをメモしていきます。

まずはじめにCloudWatchAgentのインストール

設定の流れとしては、EC2にCloudwatchAgentをインストールして、メトリクスを取得する必要があります。
CloudWatchAgentの設定はSSM Managerを使うことでコンソールからエージェントをインストールしたり、共通設定を適用できるようです。
構成管理を行うためコンソールでポチポチではなくAnsibleでやりたいので、最低限の共通設定を下記のように作成して適用するようにしました。

main.yaml

- name: install cloudwatch_agent repo
tags: cwagent
yum:
name: https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
state: present

- name: install cloudwatch_agent
tags: cwagent
yum:
name: amazon-cloudwatch-agent
state: latest

- name: remove default file
tags: cwagent
file:
state: absent
path: /etc/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.d/default
notify: restart cwagent

- name: copy common file
tags: cwagent
copy:
src: files/common
dest: /etc/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.d/common
owner: cwagent
group: cwagent
mode: '0755'
notify: restart cwagent

commonファイル

{
"agent": {
"run_as_user": "cwagent"
},
"metrics": {
"append_dimensions": {
"AutoScalingGroupName": "${aws:AutoScalingGroupName}",
"ImageId": "${aws:ImageId}",
"InstanceId": "${aws:InstanceId}",
"InstanceType": "${aws:InstanceType}"
},
"metrics_collected": {
"cpu": {
"measurement": [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_user",
"cpu_usage_system"
],
"metrics_collection_interval": 60,
"resources": [
"*"
],
"totalcpu": false
},
"disk": {
"measurement": [
"used_percent",
"inodes_free"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"diskio": {
"measurement": [
"io_time",
"write_bytes",
"read_bytes",
"writes",
"reads"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 60
},
"netstat": {
"measurement": [
"tcp_established",
"tcp_time_wait"
],
"metrics_collection_interval": 60
},
"swap": {
"measurement": [
"swap_used_percent"
],
"metrics_collection_interval": 60
}
}
}
}

handler

---
- name: restart cwagent
tags: cwagent
shell: initctl restart amazon-cloudwatch-agent

これを全台に適用すると、CloudWatchのメトリクスが取得できるようになります。
CloudWatchAlarmは、取得できたメトリクスに対してアラーム(メールを送信したりする)を設定することが可能です。

AWS Chatbot

少し前までは、Slackへの通知はLambda連携するのが一般的だったようです。
ただ、今ではSlackへ通知するにはbetaですがAWS Chatbotを使用すると簡単に通知設定できます。

CloudWatchAlarmを設定する際に通知先の設定がありますので、先にChatbotでSlack通知の設定をします。
まず、Chatbotにアクセスして、画面右上よりSlackを選択します。

そうするとアクティブなSlackのポップアップが出るのでそこでアクセスを許可します。

あとは画面に沿って進めるだけです。

SNS

Chatbotが設定できたら、SNSと連携します。
SNSと連携することで、各種AWSの通知先エンドポイントとして設定できるようになります。
Chatbotはサブスクリプションで設定します。

CloudWatchAlarm

最後に監視の設定です。
いわゆる閾値設定をここで行います。
ただ、この設定は中々にハードが高く、例えば、3分間の平均値でCPU使用率90%超えたらSlackに通知するというのを共通のものとしたい場合に、1つの設定を複数台のサーバーへ適用することが出来ません。
そのため、一つの設定をコピーして使用することになり、これがなっかなかに大変です。
そこで調べてみたところ、radiosondeというツールを使っている人が多いことがわかりました。

https://github.com/codenize-tools/radiosonde

これは、Rubyで作られたツールで既存の設定をエクスポート、ドライラン、適用まで必要な機能が備わっているOSSです。
今回はこちらを使用して、基本的な監視設定をコンソールで1台行い、それをエクスポートしてコピーして作るという作業をしました。
本当はここから、うまいことEC2インスタンスの情報を取得して汎用的に設定できるようにしたかったのですが一旦はすべて冗長的に書いて対応することにしました。

結果

下記のようにSlackに通知されるようになりました。

設定してみて

最終的に、AnsibleでCloudWatchAgentはインストールできるようになり、rasiosondeがあればなんとかなるようにはなりましたが中々大変でした。
個人的にはAgentのインストールが一番面倒で、一番最初にインストールした場合、Mackerelのようにデフォルト設定で最低限必要な監視が最初から行われるわけではなく、必要なメトリクスをjsonで書いてあげる必要があります。
これが最初わからなくて、なんでメトリクス取得できないか小一時間悩みました。

また、betaなのでしょうがないのですが、ChatbotからのSlack通知が画像ファイルとして認識されるので、Slackからの通知タイトルが「image 800×400」みたいなサイズだけで、何が通知されてきたのかがわからないのがツライです。
これはカスタマイズできるのか、これから調べてみようと思います。

やはり監視設定にあまり工数をかけたくないというのが正直なところ。
どちらかというと、初期設定よりも、その後の運用がしやすいものが良いなと改めて感じました。
色々学びがあり、とりあえずベースが出来たので良かったです。