Metric MathでLambdaを使わず CloudWatch Alert を任意時間帯のみ通知したり画面でON/OFFする方法


LambdaやAWS CLIを使わず、CloudWatch Alert を特定時間帯のみ通知や、
画面で有効・無効を切り替える方法を発見しました。

普段サーバレスな, 小西 啓介(@komikoni) です。
Qiitaは、アドベント・カレンダー2016を初めて書いて以来です。

# 背景

AWSに構築したシステムの監視として、CloudWatch Metricsで、
しきい値を超えたときなどに通知に使うのが、CloudWatch Alertです。

その、CloudWatch Alertで悩ましいのが、深夜時間帯等に通知をしないようにしたり、
システムメンテナンスの時に手動で通知しないようにする(いわゆる静観?)設定です。

悩ましい理由としては、以下のようなものがあります。

* CloudWatch AlertやSNS(Simple Notification Service)には、時間等で通知をフィルタリングする機能がない
* CloudWatch AlertやSNSには、画面(AWS Management Console)で、有効・無効を切り替える機能がない(AWS CLIとかAPIでは出来る)
* **コードを書きたくない！** ~~**(インフラ屋さんに多い?)**~~  

それでも通知をしたくないので、打開策として、
これまで、以下の方法がよく行われていました。（記事もいっぱいある）

* CloudWatch EventからLambdaを呼び出し、CloudWatch AlertのEnable/Disableを切り替える
  * [運用作業を行うのでCloudWatchのアラーム設定を無効化させたい | Developers.IO](https://dev.classmethod.jp/articles/ops-cloudwatch-alarm-invalidation/)
  * [CloudWatch Alarmアクションの無効をスケジューリングしてみた - Qiita](https://qiita.com/kapioz/items/f2de33075d7f88f00ffe)
 * [CloudWatchアラームに定時ダウンタイム設定をいれる - Qiita](https://qiita.com/tonishy/items/4b975bdc3b182f2f31e2)

* AWS CLI等を使い、手動で CloudWatch AlertのEnable/Disableを切り替える
 * [AWS CLIでCloudWatchのアラームを制御する - t-sanoブログ](http://ubw.hatenablog.com/entry/2016/11/23/193111)
 * [アマゾンウェブサービス-特定の時間帯にAWS CloudWatchアラームを一時停止/無効化できますか？ - stackoverflow](https://stackoverflow.com/questions/24737359/can-aws-cloudwatch-alarms-be-paused-disabled-during-specific-hours)
 * [アラームアクションの有効化と無効化 - AWS SDK for Ruby](https://docs.aws.amazon.com/ja_jp/sdk-for-ruby/v3/developer-guide/cw-example-alarm-actions.html)

# 概要解説
今回、追加で利用するのは、以下の３つです。

* CloudWatch Event
* CloudWatch Metrics (及び、Metric Math機能)
* CloudWatch Logs

です。つまり、CloudWatch だけしか使いません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/78fb6b86-28cf-dab1-f70d-8461010e221c.png)


### CloudWatch Eventの利用

CloudWatch Eventは、普段、CloudWatch Eventは、Lambdaを起動したりするのに使いますが、
今回は、スケジュールを組んで監視をしたい時間帯に、CloudWatch Logsのロググループをターゲットにイベントを発行します。
欲しいのは、メトリクスなので、別に、CloudWatch Logsで無くても良いんですが、CloudWatch Eventは、
何らかターゲットが必要なので、一番お金のかからなさそうな、CloudWatch Logsをターゲットにします。

### CloudWatch Metricsの利用

上記のCloudWatch Eventでイベントを発行すると `AWS/Events` の
 `Invocations` メトリクス(`m1` とする)が出来ます。
この`m1`メトリクスと、実際に、監視をしたいメトリクス(`m2`とする)を選択して、**[Metric Math](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/using-metric-math.html)** 機能によって、
`m1 * m2` のように掛け算した、新たなメトリクスを作成します。(カスタムメトリクスではないので、お金はかからない(はず))
この、新たなメトリクスを、CloudWatch Alertで監視するのです。

ようは、メトリクスといっても、数値なので、通知を出す(0)か出さない(1)かを表すメトリクスを用意して、
監視したいメトリクスと掛け算すれば、通知を出すときは、元のメトリクスを元に監視できるし、
通知を出したくない時には、0を書けるので、通知が出ないということです。

### まとめ

これにより、以下を実現できます。

1. 監視をしたい時間帯のみ、CloudWatch Alertで通知をすることが可能
2. CloudWatch Eventの画面(AWS Management Console)で、通知の有効・無効の切り替えが可能
3. **Lambda等のコーディング、デプロイが一切不要！！**
4. コードが無いから、CloudFormation化も簡単！？

　2. は、副次的なメリットですが、普段は、通知したい時間帯だが、システムメンテナンス等で、
監視をやめたい（静観）場合もコマンドの実行等が不要というのは、良いですよね！（もちろんコマンドでも出来る）

# 実施手順

## CloudWatch Eventでの手順
1 . CloudWatch Eventで[ルールを作成する](https://ap-northeast-1.console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#rules:action=create) を開く
2 . 「スケジュール」を選択し、任意のCron式を入力  (参考 : [Schedule Expressions for Rules - Amazon CloudWatch Events](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html#CronExpressions))
  下の例では、「0/5 0-9 ? * MON-FRI *」を入力 (月曜から金曜,日本時間の9:00～17:55まで5分毎)
3 . 「ターゲット」の追加にて、「CloudWatchロググループ」を選び、任意のロググループ名を設定し、「設定の詳細」を押す
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/617363cc-59c7-b86a-4c33-42a0c5fede17.png)

4 . ルールの定義で、「名前」を入力し、「ルールの作成」を押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/fcf23ae9-5cf7-2a11-d88c-33577bf11584.png)

## CloudWatch Metricsの手順

5 . CloudWatch [Metricsを開く](https://ap-northeast-1.console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#metricsV2:graph=~())
6. 検索欄に４．で入れた「名前」を入力して検索　 (４．が１度以上実行されていないと出てきません)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/d3332bca-2a6e-2ef6-532a-04aad39e6059.png)

7 . 「呼び出し(Invocations)」を選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/e4ab6576-8321-0d9f-6d54-6124ae7412e1.png)


8 . （実際に）監視したいメトリクスを追加で選択
9 . 「グラフ化したメトリクス」を選び、「Math Expression」を押して、「Start with empty expression」を選択

 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/8eab89a6-5c2e-ea6f-8a01-4d40c293f54a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/afcc4e6e-cc9a-3e7e-abef-aca5dd4ee1b2.png)

10 . 上部のタイトル、ラベルに任意の名称を入れ、詳細に**「m1 * m2」(ここが肝！)**を入力 
11 . チェックボックスで先頭のみを選択し、「統計」を「合計」に変更し（キャプチャーでは漏れてました）アラームのアクションを押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/c48348b8-1422-040a-21d4-040dc6176ca2.png)

## CloudWatch Alertの手順

12 . Cloudwatch Alerm の画面が開かれるので、任意のしきい値を入力し「次へ」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/7e9e5358-6f9a-02f4-a759-4470428933ec.png)

13 . SNSの設定をして「次へ」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/4fa2dc5e-c0c1-4a31-8c31-821f085f6d78.png)

14 . アラーム名を入れて「次へ」を押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/a5d56039-29d4-e1a5-f5fe-e9983d05ccab.png)

15 . プレビューを確認して「アラームの作成」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/2af639b2-677a-5acd-686e-232288fbe607.png)


# お断り

* 本手法は、実際のシステム等では、まだ利用しておらず、十分な検証をしていません。
* 本手法の適用は、読まれた方ご自身の責任において行われるものとし、筆者は一切の責任を負いません。
* 本記事は、筆者の所属企業とは、一切関係なく、個人としての執筆となります。
* Cloudwatch alertの設定や、SNSの設定は適当な部分があります。
* Cloudwatch logsのロググループは、無期限で作成されます。ログ自体は使用しないので、任意の保管期限に変更して下さい。
* 2019年05月29日現在、似たような記事は確認できなかったので、世界初!?かな？。

# 余談

今回、ノン・コーディングで実装したいと思って、当初 CloudWatch Alertと連携できるEventBdrigeを使い、
EventBrigeのコンテンツフィルタリングで `time` 属性で `["T10","T11"・・]` などとフィルタリング出来るかと
おもったのですが、contain関数が無く、実現できませんでした。その後、考えたのがこれです。

でも、今までCloudWatch系は、Logsがメインで、あまり使ったことなかった機能ばかりだったので、色々勉強になりました。