こんにちは,SREのid:cohalzです.
Mackerelの監視設定をバックアップするため,またはどんな変更があったのか把握するために,自動でGitHubリポジトリに管理するものを作りました.
監視設定を変更すると,自動で以下のような変更が即座にGitHubにも反映されます.
また,コミットメッセージには
- 変更の種類(作成・変更・削除)
- 対象の監視設定名
- 変更を行ったユーザ
が記録されます.
自動で実行されるため以下のような利点があります.
- いつ誰がどの監視設定を変更したのか確認できる
- コミットされた時間が監視設定を変更した時間になる
- GitHub上のdiffを用いて監視設定の変更を確認することができる
- そもそも監視設定のバックアップに漏れがなくなる
また,実行するサーバも不要で準備や運用の手間もいらず,すぐに利用することができます.
これらはMackerelでリリースされたばかりの新機能を利用しています.
実装の話
Mackerelでは,mkrコマンドを用いて現在の監視設定を取得することができます.
これを利用して,監視設定をGitHubを用いて変更管理をすることができます.
では実際にGitHubで管理しようとなるといくつか考えることがあります.
- どのサーバーで実行するか
- 監視設定を取得・GitHubにpushするタイミング
これらを解決する方法として,JenkinsなどのCIに任せておくという解決も考えられます.
しかし,Jenkinsでやるにしても初期設定が大変なことや,運用を行う必要が出てきます.
その解決方法を探している際に,Mackerelでは監視ルールの変更があった際にwebhookを飛ばす事ができるということに気が付きました.
webhookが使えるならエンドポイントをAPI Gateway+Lambdaにのイベント駆動にできる上に,サーバも必要なくなるのではないかと考え実装しました.
最終的なアーキテクチャは以下のようになりました.
流れは以下のようになっています.
- MackerelのwebhookからAPI Gatewayのエンドポイントにリクエストが飛ぶ
- API GatewayからLambdaを呼び出す
- LambdaからCodeBuildを呼び出す
- CodeBuildからmkr monitors pullを実行する
- CodeBuildからgit pushを実行する
ポイントとしてはLambdaからCodeBuildを呼び出している部分です.
Lambdaではリクエストを元に何かを処理するという部分は得意ですが,任意のコマンドを実行するという用途には向いていません.
今回の場合では,gitやmkrコマンドをLambda上で実行するための準備が必要になってきます.
逆にCodeBuildはコマンド実行を得意としている上に,必要な環境はDockerイメージで用意するだけで非常にお手軽です.
そのため,Lambdaでは
- 受け取ったwebhookからコミットメッセージを生成
- コミットメッセージを環境変数経由でCodeBuildに渡し,ビルドを実行
ということのみ行い,処理の大部分はCodeBuildに任せています.
実行時間を短縮させる
以上のものを作成し動かしたところ,CodeBuildの実行に時間がかかることがわかりました.
これはCodeBuildの実行するタイミングでmkrコマンドをインストールするようにしており,そのインストールに時間がかかっていたためです.
もしwebhookからmkrコマンドを実行する時間の間に複数の監視設定が同時に更新されてしまうと,1つのコミットに複数の変更がまとめられてしまう動作をしてしまう問題があります.
その問題が起こりにくくなるような対処として,実行時間を短縮させる改善を行いました.
今回の場合,利用するコマンドはgitとmkrだけなので,その2つのコマンドがある小さいイメージを作ることにしました.
mkrコマンドが利用できるオフィシャルDockerイメージを元に,このイメージからgitをインストールしただけのイメージを作成し,利用することにしました.(DockerHubリンク)
さらに,リポジトリが大きいとclone時に時間が掛かってしまうので,cloneをする前にmkr monitors pull
を実行するように順番を変更することも行いました.
これらの改善により,CodeBuildの実行から10秒程度で実行ができるようになりました.
その結果,コミットがまとめられるということもほとんど発生しなくなったことを確認できました.
アプリケーションを利用するには
現在,Serverless Application Repositoryの以下のリポジトリで公開しています.
リポジトリ: serverless-mkr-monitors
リポジトリにアクセスした後,「アプリケーションの設定」からコミットするリポジトリやユーザのPersonal Access Token,MackerelのAPIキーなどを入力しデプロイします.
デプロイ後,CloudFormationのコンソールにて出力(Outputs)の欄にApiEndpointという欄があるのでそのURLをコピーします.
Mackerelのチャンネル設定から以下の様にそのURLを貼り付けます.
以上の設定が完了すると,監視設定が変更されたとき自動でGitHubにpushされるようになります.
発展: mkr monitors pushを用いたマルチマスタの監視設定管理
上で作成したものはMackerelからGitHubリポジトリへの自動同期でした.
ところで,mkrコマンドにはmonitors.json
の内容をMackerel上へ反映させることができるmkr monitors push
というサブコマンドがあります.
リポジトリにCIを用意しコミットごとにこのコマンドを実行すれば,リポジトリに変更があった際に,その内容をMackerel側にも自動で反映させることができます.
つまり上で作ったものとは逆に,GitHubリポジトリMackerelからへの自動同期を行うことができます.
ただ,このCIによってGitHub上のリポジトリが監視設定のマスタになってしまうため.Mackerel上で監視を設定しても,リポジトリ上になければCIのタイミングでその設定が消えてしまうという問題がありました,
しかし,上で作成したものと組み合わせることにより,双方向で自動同期が動くようになり,どちらからでも監視設定を変更ができるマルチマスタ構成を作ることができます.
ちなみに,リポジトリから監視を追加した場合の,動作の流れは以下です.
- (GitHub側) 新規に監視設定設定を追加することでpushを実行
- (Mackerel側) 監視が追加され,pullによりリポジトリにidが付与されるコミットが追加
- (GitHub側)コミットされたことによりpushを実行(変化なし)
ポイントとしては,このようにmkr monitors push/pullの結果を元にwebhookの実行を繰り返すことで,お互いに同じ状態になるまで自律的に同期を行うというところです.
一方がwebhookを実行しないということをもって同期完了となります.
- pushで変化がなければ監視に変更がないということのため,Mackerelからwebhookを実行せず同期を終了
- pullで変化がなければコミットもされないため,GitHubからwebhookを実行せず同期を終了
このようにして,片方を変更してももう一方も反映されるマルチマスタ構成を実現することができます.
最後に
元々は監視設定のバックアップが欲しいという用途で作成しましたが,いつ誰がどのような監視設定をしたのか確認できるというのは非常に使い所があると感じました.
また発展では,CIを利用することによってリポジトリとWebUIをどちらもマスターとすることができ,一方に縛られずどちらからでも監視設定の変更を行えるようになりました.
Serverless Application Repositoryを利用するのは初めてでしたが,公開非公開選べる上に,アカウント単位での共有も可能のため,社内や全世界に公開するアプリケーションを配布するのに非常に便利でした.
ちなみに,今回作成したLambdaやCodeBuildを含むCloudFormationテンプレートは,以下のGitHubのリポジトリで公開しています.