Share
Embed
自動生成を活用した、運用保守コストを抑える Error/Alert/Runbook の一元集約管理 / Centralized management of Error/Alert/Runbook to minimize operational costs using automated code generation
DevOpsDays TOKYO 2024 の登壇資料です。
Shota Iwami
April 15, 2024
Transcript
44 slides
-
自 動 生 成を活 用 した 運 用 保守コストを抑える Error/Alert/Runbook
の 一 元集約管理 株式会社サイバーエージェント AI事業本部 岩 見 彰太 GitHub:@BIwashi X: @B_Sardine DevOpsDays Tokyo 2024 -
自己 紹介 岩 見 彰太 / Iwamin 株式会社サイバーエージェント ৽ଔೖࣾ "*ࣄۀຊ෦ڠۀϦςʔϧϝσΟΞ%JW
খചاۀͷΞϓϦ։ൃ @BIwashi @B_Sardine -
1 .はじめに 2 .エラー検知の重要性 3 .アラートの重要性と注意点 4 .「アラートが来た!」で終わらせず 行 動に繋げるには
5 . 自 動 生 成による情報の集約 6 .エラー検知で終わらせずに進捗を追う 7 .まとめ -
ターゲット:以下の問いにドキッとした 方 へ • エラーに対して適切にアラートを設定していますか? ただひたすらよく分からないエラーが垂れ流されている Slack チャンネルはありませんか? •そのアラートの内容、みんながある程度把握できていますか? 実装者しか把握できない内容になっていませんか?
•そのアラートが来た時、どのような 行 動をすればいいかすぐわかりますか? •そのアラート対応、誰がやっていますか?もしくは誰も対応されず放置され ていませんか?その情報を追えていますか? -
エラー検知の重要性 • 開発を進めていく中で適切なエラー検知は不可 欠 適切なハンドリングを 行 うことで、エラー発 生 から修正までの時間 を最
小 化できる • より正確で詳細な情報を事前に仕込むことが重要 • Sentry や Datadog Error Tracking など、エラーの種類 を適切に振り分けらられるような仕組みを利 用 Tag Stack Trace Custom Logger Log Level Error Message Status Code -
アラートの重要性と注意点 • エラーを適切に検知してアラートを設定する仕組みは重要 エラーを垂れ流しているだけでは気づけない • アラート流せばいいというものではない アラートを闇雲の流しすぎると狼少年化してしまう 本当に重要なアラートを逃してしまう • アラートの内容がわかる
人 が属 人 化されないようにする必要がある アラートが発 生 される際は基本的に異常時で何かしら対処が必要なはず 対処 方 法、 行 動を把握できる 人 は増えるに越したことはない -
アラートの属 人 化 エラーメッセージ スタックトレース ログリンク etc. エラー内容 分かる 人
エラー内容 分からない 人 エンジニア じゃない 人 あーこれは対処しなくていいやつだ。 一 旦放置! よく通知されるけどどこのエラーなんだ…?何が起き てるんだ…?対処する必要あるのか?ちゃんと調査し たほうがいいのかな… なんかヤバそうな雰囲気はあるけど何も分からん。〇〇さ ん(エラー内容分からない 人 )に聞いてもよく分からない と 言 われた。アラートチャンネルはもう 見 るのやめよう😇 #hoge_alert -
アラートの属 人 化 エラーメッセージ スタックトレース ログリンク etc. エラー内容 分かる 人
エラー内容 分からない 人 エンジニア じゃない 人 あーこれは対処しなくていいやつだ。 一 旦放置! よく通知されるけどどこのエラーなんだ…?何が起き てるんだ…?対処する必要あるのか?ちゃんと調査し たほうがいいのかな… なんかヤバそうな雰囲気はあるけど何も分からん。〇〇さ ん(エラー内容分からない 人 )に聞いてもよく分からない と 言 われた。アラートチャンネルはもう 見 るのやめよう😇 そもそもこれは アラートすべきではない #hoge_alert -
どう 行 動に移すか • ひたすらエラー内容が流れてくるだけで誰もみていないチャンネル… それはアラートを流している意味がない • アラートするからには… 何か伝えたいことがある それに応じて
行 動すべきことがあるはず • アラート内容をもとに次の 行 動に繋げていく必要がある 具体的な 行 動 手 順があるとすぐに 行 動できる アラートは エラー →対処 を動かすためのトリガー -
どう 行 動に移すか 手 順書のない世界 何すればいいかわからん! どこから 手 をつければええんや! えっと…
手 順書によるとこれをすればいいのか…! まずはここの値を調査して、XXXしてみるか。 手 順書のある世界 手 順書 Runbook Playbook 手 順書があるとアラートに対してより詳細な情報を付与できる →すぐに 行 動に移せる/ 行 動できる 人 を増やせる -
手 順書(Runbook/Playbook) • アラートへの対処法や調査すべき項 目 などをあらかじめ記載しておく 想定外のエラーが出ても調査にとっかかりやすくなる 想定できうるエラーであれば 手 順書を明記しておくことで、認知コストを下げられる
• 手 順書はアラートとの紐付けとメンテナンスが肝 メンテナンスされておらず古い情報… 記載場所が決まっておらず同じような 手 順書が複数 見 つかる… 手 順書のどこを 見 ればいいかわからない… खॱॻʢrunbookʣΞϥʔτ͕དྷͨ࣌ʹࣗ͘͢ͷਐΉ͖ํΛࣔ͢ૉΒ͍͠ํ๏Ͱ ͢ɻ ڥ͕ෳࡶʹͳͬͯ͘ΔͱɺνʔϜͷ୭͕֤γεςϜͷ͜ͱΛ͍ͬͯΔΘ͚Ͱͳ͘ͳ Γɺखॱॻ͕ࣝΛΊΔΑ͍ํ๏ʹͳΓ·͢ɻ by ೖࢹ -
情報の分散(Custom Code で紐づける例) Custom Code を埋め込む実装と Runbook が分離してしまう 参照するのもメンテナンスするのもコストがかかる エラーメッセージ
スタックトレース ログリンク etc. + Custom Code Runbook with Custom Code エラーにCustom Codeを埋め込む Notion Con fl uence Github Wiki etc … Custom Code で紐づける エラー内にある Custom Code から Runbook を検索して内容を確認して 行 動に移す -
情報集約のモチベーション • Custom Code と Runbook によるアプローチはいいが保守コストが 高 い できるだけ集約してそこだけをみれるようにしたい
• アラート通知の内容をできるだけ誰でもわかるようにしたい エラー内容によってアラート 文 をリッチに変えるようにしたい • リッチな Runbook をログに埋め込むとログ量が増えてしまうため避けたい Custom Code で連携するというアプローチではいきたい そもそもアラートが Runbook にもなっていればいいのでは…? アラートメッセージを Custom Code に応じて出し分ければいいのでは…? -
Go Generate!! The Go gopher was designed by Renée French.
Created using gopherize.me -
Protoc Plugin • Protocol Bu ff ers に記述された情報を使 用 して
自 動 生 成などを 行 う • Extend を使 用 して message や fi eld に情報を 追加したり拡張することができる • 今回は protoc plugin をサクッと書ける protoc-gen-star(PG*)を使 用 Go Conference mini 20 23 Winter in KYOTO -
enum ReasonCode { RC00000 = 0 [(ext.reason_code) = { message:
[ "hoge͕ൃੜ͠·ͨ͠", "`http://example.com` Λࢀরͯ͠ϦιʔεΛ", ”֬ೝ͍ͯͩ͘͠͞", "fooͩͬͨ߹foo͍ͯͩ͘͠͞" ] }]; RC00001 = 1 [(ext.reason_code) = { message: [ "piyo͕μϯ͍ͯ͠·͢", "PMͱ࿈ܞͯ͠piyoʹ࿈ܞ͍ͯͩ͘͠͞" ] }]; } Reason code proto fi le -
enum ReasonCode { RC00000 = 0 [(ext.reason_code) = { message:
[ "hoge͕ൃੜ͠·ͨ͠", "`http://example.com` Λࢀরͯ͠ϦιʔεΛ", "֬ೝ͍ͯͩ͘͠͞", "fooͩͬͨ߹foo͍ͯͩ͘͠͞" ] }]; RC00001 = 1 [(ext.reason_code) = { message: [ "piyo͕μϯ͍ͯ͠·͢", "PMͱ࿈ܞͯ͠piyoʹ࿈ܞ͍ͯͩ͘͠͞" ] }]; } Reason code proto fi le • Reason Code • 実装側とRunbookを紐づける独 自 の code • 後に Datadog のモニタリングを設定する際 に重要 -
enum ReasonCode { RC00000 = 0 [(ext.reason_code) = { message:
[ "hoge͕ൃੜ͠·ͨ͠", "`http://example.com` Λࢀরͯ͠ϦιʔεΛ", "֬ೝ͍ͯͩ͘͠͞", "fooͩͬͨ߹foo͍ͯͩ͘͠͞" ] }]; RC00001 = 1 [(ext.reason_code) = { message: [ "piyo͕μϯ͍ͯ͠·͢", "PMͱ࿈ܞͯ͠piyoʹ࿈ܞ͍ͯͩ͘͠͞" ] }]; } Reason code proto fi le • Message(Runbook) • その Reason Code に紐づく Runbook • 実際に管理したい Runbook の内容を 入 れて おく -
// Code generated by protoc-gen-go-reason-code. type ReasonCode string const (
RC00000 ReasonCode = "RC00000" // Message: hoge͕... RC00001 ReasonCode = "RC00001" // Message: piyo͕... ) // Custom Error type Error struct { error ... reasonCodes []ReasonCode ... } func WithReasonCode(rc ReasonCode) Option { return func(e *Error) { e.reasonCodes = append(e.reasonCodes, rc) } } Application Code • Custom Error に Reason Codes を 入 れられるようにする • 定数の Reason Code を 自 動 生 成する • 自 動 生 成されたものをエラーハンド リングしている箇所で 入 れる -
{ "error": { "reason_codes": [ "RC00000" ], ... "message": "hoge
error" } } Error JSON • 構造化ログの error に reason codes を出しておく • 後に Datadog を使 用 する際に重要 -
Datadog Monitors • エラーが発 生 した際にアラートを 飛 ばすモニタリングアラートを設定 Error Tracking
Base で設定 • Datadog の Message (アラート内容)では独 自 の条件付き変数が利 用 できる これを利 用 して reason code によって message (Runbook)を分岐する -
is_match によるMessage分岐 • Datadog のMessageでは log.attributes で構造化されたログのフィールド の値を取得できる • error
に埋め込んだ reason_codes を is_match で検知して、 message(runbook)を表 示 する -
is_match によるMessage分岐 • Datadog のMessageでは log.attributes で構造化されたログのフィールド の値を取得できる • error
に埋め込んだ reason_codes を is_match で検知して、 message(runbook)を表 示 する 配列フィールドの場合、以下のよう に検知されるため ”” で囲っている “RC00000”,“RC00001”, … -
{{!-- Monitor generated by protoc-gen-go-reason-code and terraform. DO NOT EDIT.
--}} {{ log.message }} {{#is_match "log.attributes.error.reason_codes" "\"RC00000\"" }} reason_code: `RC00000` ``` hoge͕ൃੜ͠·ͨ͠ `http://example.com` Λࢀরͯ͠ϦιʔεΛ ֬ೝ͍ͯͩ͘͠͞ fooͩͬͨ߹foo͍ͯͩ͘͠͞ ``` {{/is_match}} {{#is_match "log.attributes.error.reason_codes" "\"RC00001\"" }} reason_code: `RC00001` ``` piyo͕μϯ͍ͯ͠·͢ PMͱ࿈ܞͯ͠piyoʹ࿈ܞ͍ͯͩ͘͠͞ ``` {{/is_match}} > `{{{ log.attributes.error.file }}}` > **{{{ log.attributes.error.message }}}** - [Log Link]({{log.link}}) - Issue ID: [{{[issue.id].name}}](https://app.datadoghq.com/logs/error-tracking/issue/ {{[issue.id].name}}) - Version: {{log.attributes.version}} {{#is_alert}} @${notification_alert_channel} {{/is_alert}} Terraform による管理 • Datadog の Monitors は Terraform 管理可能 • proto に記述した内容を元に reason code による分岐と message(Runbook)を 生 成する application_error_alert.pb.md -
resource "datadog_monitor" "application_error_alert" { name = "[${var.env}] αʔόʔΤϥʔ͕ൃੜ͠·ͨ͠" type =
"error-tracking alert" tags = ["env:${var.env}", "managed_by:terraform"] priority = 2 on_missing_data = "resolve" include_tags = true group_retention_duration = "3d" monitor_thresholds { critical = 0 } query = <<-EOT error-tracking-logs( "(issue.age:<=300000 OR issue.regression.age:<=300000) env:${var.env}" ).index("*") .rollup("count") .by("issue.id") .last("5m") > 0 EOT message = templatefile( "${path.module}/messages/application_error_alert.pb.md", { notification_alert_channel = var.notification_alert_channel } ) } Terraform による管理 • protoc plugin で 生 成した Markdown を template fi le 関数で 読み込み設定する monitor.tf -
resource "datadog_monitor" "application_error_alert" { name = "[${var.env}] αʔόʔΤϥʔ͕ൃੜ͠·ͨ͠" type =
"error-tracking alert" tags = ["env:${var.env}", "managed_by:terraform"] priority = 2 on_missing_data = "resolve" include_tags = true group_retention_duration = "3d" monitor_thresholds { critical = 0 } query = <<-EOT error-tracking-logs( "(issue.age:<=300000 OR issue.regression.age:<=300000) env:${var.env}" ).index("*") .rollup("count") .by("issue.id") .last("5m") > 0 EOT message = templatefile( "${path.module}/messages/application_error_alert.pb.md", { notification_alert_channel = var.notification_alert_channel } ) } Terraform による管理 • protoc plugin で 生 成した Markdown を template fi le 関数で 読み込み設定する monitor.tf 複雑かつ 大 量の分岐だが 自 動 生 成してるため コスト0で実現可能 -
アラート • アラートの中にすでに Runbook の内容 が含まれている Runbook を探すという作業が必要ない • エラーに関する実装上の情報などだけで
はなくより豊富な情報をアラートで提供 非 実装者や 非 エンジニアでも温度感が分かる 対処すべき 行 動がすぐわかる アラートに対する認知者の増加 注 目 が集まることによる 見 逃し軽減 -
エラー検知で終わらせずに進捗を追う • アラートされたエラーに対して対処する必要がある場合それをしっかり チケット化して進捗を追っていくことが重要 • チケットとアラートが紐づいていないと進捗管理が困難 • そのエラーの現在のステータスがわからない どれだ…? すでに対応済み(反映待ち)
修正したが再発(デグレ) 誰かが修正している 誰も対応しておらず修正が必要 -
Error Tracking×Casa Management×Jira • Error Tracking の Issue から Case
Management を作成 事前に Jira と連携しておくと Case を作成すると 自 動でチケットが切られる 担当者やステータスも双 方 向で同期できる %BUBEPH$BTB.BOBHFNFOU -
Error Tracking×Casa Management×Jira • Error Tracking の Issue から Case
Management を作成 事前に Jira と連携しておくと Case を作成すると 自 動でチケットが切られる 担当者やステータスも双 方 向で同期できる %BUBEPH$BTB.BOBHFNFOU +JSB -
まとめ • Alert の適切な管理が重要 • Runbook を活 用 した Error
に対する認知負荷の軽減 • protoc plugin + Datadog + Terraform Reason Code と Runbook を 自 動 生 成で紐づけて管理コストを軽減 • タスク管理ツールと Error を紐付ける Error とタスクチケットを紐づけて対応の進捗までリンクしておく ステータスを確認するコスト軽減 情報の集約、連携でエラー取り逃がさず追い続ける