SREチームの吉村です。
弊社では主にAmazon Web Service(AWS)を使ってサービスを構築、運用しており、そのサービスの監視にMackerelを利用しています。 Amazon CloudWatchのメトリクスのうち主要なものはfluentd(fluent-plugin-cloudwatch、fluent-plugin-mackerel)を利用してMackerelに登録していますが、量が多くなるとfluentdの設定が煩雑になってしまいます。
そこで、Mackerelへの登録に必要なそれらの設定なしに、CloudWatch Alarmを使ってMackerelのアラートとして発報できる仕組みを作りました。 Mackerelへアラートを発報するようにした理由は、アラートの通知や管理はMackerelで一元管理をしているためです。
今回その仕組みについてご紹介、組み込み手順まで説明したいと思います。
概要
上図はCloudwatch AlarmからMackerelへアラートが上がるまでの流れを表した図です。
CloudWatch Alarmが発火されたら、そのアラームのactionsに設定したAmazon Simple Notification Service(SNS)のtopic1へメッセージが飛びます。 そのメッセージは予めSNS上で登録したサブスクリプションによってcloudwatch-alarm-to-mackerel
関数へ流れていきます。 最後に、メッセージはMackerelへアラートを上げます2。
次に、実際の導入方法を説明します。
導入方法
必要なもの
以下のツールを事前に用意してください。
1. SNSのtopicを作成する
CloudWatch Alarm発火後の通知先に、先に述べたSNSのtopicが必要のため事前に作成します。
$ aws sns create-topic --name sample
2. Mackerelにホストを作成
Mackerelの POST /api/v0/monitoring/checks/report
ではhost idが必要なので、
cloudwatch-alarm-to-mackerel専用のhostをMackerel側に登録します。
$ mkr create sample_host
3. Lambdaの組み込み
cloudwatch-alarm-to-mackerelはapexの利用を想定しています。 以下、apexのディレクトリ階層の例です。
. ├── functions │ └── cloudwatch-alarm-to-mackerel │ ├── function.json │ └── main.go └── project.json
main.goとfunction.jsonを作成します.
- main.go
package main import ( "github.com/kayac/cloudwatch-alarm-to-mackerel" ) func main() { cwa2mkr.ApexRun() }
- function.json
{ "name": "cloudwatch-alarm-to-mackerel", "description": "alert cloudwatch alarm to mackerel", "runtime": "go1.x", "memory": 128, "timeout": 60, "handler": "main", "environment": { "HOST_ID": "mackerelのhost id", "MACKEREL_APIKEY": "mackerel apikey" } }
※ HOST_ID, MACKEREL_APIKEY は適宜正しい値を入力してください。
※ 注意: mackere_apikeyは秘密情報なので、apex deploy --env ...
等で実行時のみ入れるなどの工夫をしたほうが良いです。
- project.json
{ "name": "sample", "description": "sample project", "memory": 128, "timeout": 60 }
この状態で、先のディレクトリ階層の現在位置でapexよりデプロイを実行します。
# dryrunで確認 $ apex deploy --dry-run cloudwatch-alarm-to-mackerel # デプロイ $ apex deploy cloudwatch-alarm-to-mackerel # 登録の確認 & arnのチェック $ aws lambda get-function --function-name sample_cloudwatch-alarm-to-mackerel | jq -r .Configuration.FunctionArn
※ function名に sample_
がつくのはproject.jsonのnameがsampleなためです。
次にSNSサブスクリプションを登録します。
$ aws sns subscribe --topic-arn <topic arn> --protocol lambda --notification-endpoint <lambda arn>
<topic arn>
には1で作成したtopicのarn、<lambda arn>
には先程登録したLambdaのarnを入れます。
4. Cloudwatch Alarmを作成
アラート検知させたいCloudwatch Alarmを作成します。 アラーム設定したいメトリクスを選択肢、登録したトピックを通知先に設定します。
以下、console上でのアラームの通知先設定の画面です。
①ではデータが不足している場合の挙動を設定できます。 画像では現状維持を設定しています。 こちらは適宜設定してください。
②で、通知先のアクションが設定します。 先に作ったsample
のSNSトピックを選択します。
5. 動作確認
登録した Cloudwatch Alarm の閾値を調整して、現在のメトリクス値で適当に発報されるようにconsole上から設定して動作を確認します。 以下の画像のようにMackerel側にアラートが上がるのを確認できます。
criticalアラームの設定
cloudwatch-alarm-to-mackerelは、デフォルトでWarningレベルでアラートを投稿しますが、
alarmのdescriptionの先頭がCRITICAL
という文字列だった場合、Criticalレベルでアラートを投稿します。
以下、設定を変更してCriticalレベルのアラートになるか確認した結果です。
おまけ: PostChecksReports の利用
Mackerelへpostする部分は別パッケージからも利用できるようにしてあります。 このAPIだけ簡単に利用したい場合にどうぞ。
package main import ( "log" "time" "github.com/kayac/cloudwatch-alarm-to-mackerel" ) func main() { now := time.Now().Unix() apiKey = "Your mackerel api key" reports := cwa2mkr.Reports{ Reports: []cwa2mkr.Report{ cwa2mkr.Report{ Source: cwa2mkr.Source{ Type: "host", HostID: "host id", }, Name: "test alarm", Status: cwa2mkr.StatusWarning, Message: "this is a test", OccurredAt: now, }, }, } if err := cwa2mkr.PostChecksReport(apiKey, reports); err != nil { log.Println(err) } }
さいごに
AWSのリソースに対する監視をCloudwatch Alarmの新規作成のみで設定できるようになる点が良いところだと思います。設定が簡単なので、AWSのメトリクスから一旦アラートだけ上げられるようにして、あとから細かく監視を調整していくと行った場合でも便利かと思いました。
-
SNS topicはメッセージを送信、受信するための通信チャネルで、CloudWatch Alarm以外の様々なAWSサービスから利用できます。↩
-
MackerelのアラートにはPOST /api/v0/monitoring/checks/reportを使っています。↩