こんにちは。
vivit で SRE をやっている宮本(https://github.com/tatsuro-m)です!
今回は Datadog で「リリース後にだけ」利用するモニタリングリソースをどうやって作成、運用していったかを書いてみようと思います。
基本的には常時 OFF(ミュート)で、リリース後に ON(アンミュート)になり、1時間後に自動で再度ミュートします。
背景
一般的に、何らかのリリースが起点となって障害が発生することは多いと思います。
vivit では常時 Datadog モニターを利用してエラー率、 SLO の監視をしていますが、タイムウィンドウが1週間と長くなっています。
リリース後の1時間など、もっと小さいタイムウィンドウで突発的なエラー率の上昇を監視したいという要件があり、今回の仕組みを構築しました。
前提知識
モニターにはミュート、アンミュートの機能があり、ある期間のアラートを無視することができる(モニターの管理)
ミュート時にはミュートを解除する時間を指定できる
- アンミュートする際には再度ミュートする時間を指定する機能は存在しない
- Datadog は多くのリソースに対して REST API を提供していて、モニターもある(https://docs.datadoghq.com/ja/api/latest/monitors)
よって、時間経過によって自動で再ミュートする仕組みは自分で構築しなくてはなりません。
アーキテクチャ
順番に解説します。
対象となるモニターは予め作成した上でミュート状態にしておき、 monitor_id
を控えます。 monitor_id
は Datadog 画面から確認できます。
- リリースをトリガーにして1つ目の Cloud Functions を gcloud で呼び出す
- unmute エンドポイントを叩いてミュート解除する
- Cloud Tasks のキューにタスクを積む。この時、起動時刻のオプションで特定時間を設定する
- 指定した時間に HTTP 呼び出しで mute エンドポイントを叩く Cloud Functions を呼び出して再度ミュート
ポイント
トリガーは何でも良いのですが、今回は特定マイクロサービスの本番環境へのリリースです。
vivit では GitOps を採用しているので、Kubernetes マニフェストの更新を検知して GitHub Actions のワークフローが起動するところからスタートできます。
vivit での GitOps については 、
こちらの記事をご参照下さい !!
以下、Cloud Functions で実行される Cloud Tasks キューにタスクを作成する部分のコードです。
ts := ×tamppb.Timestamp{Seconds: time.Now().Add(1 * time.Hour).Unix()} req := &taskspb.CreateTaskRequest{ Parent: queuePath, Task: &taskspb.Task{ ScheduleTime: ts, MessageType: &taskspb.Task_HttpRequest{ HttpRequest: &taskspb.HttpRequest{ HttpMethod: taskspb.HttpMethod_POST, Url: os.Getenv("MUTE_FUNCTION_URL"), AuthorizationHeader: &taskspb.HttpRequest_OidcToken{ OidcToken: &taskspb.OidcToken{ ServiceAccountEmail: os.Getenv("UNMUTE_FUNCTION_SA_EMAIL"), }, }, }, }, }, }
Go で提供されているクライアントライブラリを利用します。
ScheduleTime
に起動時刻を設定することができます。
Cloud Functions の HTTP 呼び出しには認証必須にしているので、 OIDC トークンも忘れずにセットします(ここでハマりました 🤧)。
Datadog は様々な言語の API Client を提供しており、Go のライブラリも存在します(GitHub - DataDog/datadog-api-client-go: Golang client for the Datadog API)。
ただし今回は API Client を使うまでもないと判断したので、Go の標準パッケージで REST API を呼び出しています。
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("https://api.datadoghq.com/api/v1/monitor/%s/unmute", os.Getenv("MONITOR_ID")), nil) req.Header.Set("Content-Type", "application/json") req.Header.Set("DD-API-KEY", os.Getenv("DD_API_KEY")) req.Header.Set("DD-APPLICATION-KEY", os.Getenv("DD_APP_KEY")) if err != nil { return err } resp, err := http.DefaultClient.Do(req)
Datadog の API を呼び出すには、2つの秘匿情報が必要です。
- api key
- app key
これらの情報を Cloud Functions に伝えるために、Secret Manager を利用して環境変数に登録しました。
Using secrets | Cloud Functions Documentation | Google Cloud
「特定時間経過後に Cloud Functions を呼び出したい」という要件だけ聞くと、Cloud Scheduler の利用を検討される方もいると思います。
しかし Cloud Scheduler は Cron を使用する以上、単発の実行には不向きです。
単発で実行したいという理由で、今回は Cloud Tasks の scheduleTime
を利用する構成で作ってみました。
最後に
割と特殊なケースですが、 Datadog API と GCP のサービスを上手く組み合わせることで、このような構成も可能であることが伝われば幸いです。
vivit では一緒に働くエンジニアを大募集しています。
www.wantedly.com
少しでも興味を持って頂いた方は、是非カジュアル面談の応募をお待ちしております!