slack-goとZapierで障害対応初動を自動化した話

f:id:TatchNicolas:20220316183046p:plain

サーバサイド開発やインフラ周りをいじっているたっち(TatchNicolas)です。今回はJX通信社における障害対応フローの改善について書きます。

はじめに

TL;DR;

  • slack-goとZapierを組み合わせて、障害対応時の提携作業を自動化するツールを作った
  • 「自動化しよう」という意見がでやすい場自体を仕組みとして整備したことが改善のきっかけになった

今回の話の背景

少し前に、ビープラウドさんとのイベントにて、JX通信社NewsDigestチームのCI/CDおよび障害対応についてお話しさせていただきました。*1

そのなかで、「障害対応時に専用のSlackチャンネルを都度作成していること」「Notionテンプレを使って情報の整理をしていること」*2を紹介しました。イベント後も何か障害やヒヤリハットが起こると少しずつフローが改善されていき、またNewsDigest以外のプロダクトチームでも同様のフローが採用されたりと自然と社内に浸透していきました。

JX通信社のポストモーテムでは、「発生した障害に対する技術的な振り返り、再発防止」の他に「対応のマニュアル、対応中のメンバーの振る舞い」に対する振り返りをする項目を明示的に設けています。その結果、「この手順、自動化したいな」という声が挙がったことから、ZapierとGolangを使って障害対応の初動を自動化する仕組みを作りました

f:id:TatchNicolas:20220316175706p:plain:w400
ポストモーテムで自動化の案がでたときのメモ

何をつくったか

任意のチャンネルで @incident-bot 障害発生 <プロダクト略称> <障害のひとこと説明> のような形式でSlackに書き込むと、

  • 障害対応Slackチャンネル作成(#incident-yyyy-mm-dd-<プロダクト略称>-<障害のひとこと説明>)
  • 情報をまとめるNotionページの作成
  • 関係者への連絡(然るべき常設Slackチャンネルへ新規作成した障害対応slackチャンネルとNotionページを投下)

を自動で瞬時に行ってくれます。

f:id:TatchNicolas:20220315230506p:plain:w400 f:id:TatchNicolas:20220315230514p:plain:w600

こういった作業は障害発生時のような急いでいる時ほど速く確実に行いたいので、自動化にはもってこいですね。

どう作ったか

はじめは、以前社内勉強会*3でも取り上げた https://github.com/slack-go/slack を使って適当な場所へデプロイしてサクッと完成させようと思ったのですが、Notion APIを使ってみたところ執筆時点でページ単位のAPIキーの発行に対応しておらず、あまり気軽にキーを発行するわけにもいきませんでした。

そこで社内で相談したところ「Zapier越しになら記録もいい感じに残るし使ってOK」との助言をもらったので、「じゃあいっそのことZapierで完結させるか!チャチャっと終わらせたいし!」と作り始めました。

Zapierの困りごと

Zapierは、SlackもNotionもネイティブに対応しており、Slack連携でチャンネル作成やメッセージ送信、Notion連携でページの作成などの処理を簡単に作ることができます。なのでポチポチしていくだけで簡単に今回の用件を満たすものが作れそうだと思ったのですが、Slackチャンネル作成の機能が日本語に対応していなかったので、 冒頭の例のようなチャンネルを作ろうとすると #incident-yyyy-mm-dd-nd-_ のように日本語がアンダースコアで置き換えられてしまいました。

これにより困ることが2つあって、一つは急いでいるときにチャンネル名から何が起こっているのかを特定できないことです。障害対応中はアラートを流しているチャンネルや修正のためのCI/CDの状態を流しているチャンネルなど、いろいろなチャンネルを行き来します。なので日本語でチャンネルを検索できた方が便利ですし、チャンネルが作成されたことを通知された人も何が起こっているのかパッとみてイメージしやすいので、日本語チャンネル名対応は諦めたくありませんでした。

もう一つは、あまり考えたくないですが同じ日に同じプロダクトで障害が複数発生*4した場合、日本語部分がアンダースコアになってしまうとチャンネル名が被ってしまいます。するとチャンネル作成がエラーになってしまいますし、ランダムな接尾辞などを付与するのもなんだかイケてないので困りました。

そこで「チャンネルを作る」というアクションは今後も変わることが少ないと想定されるので、チャンネル作成の部分は当初の予定通りGolangで開発したbotに任せ、それ以外をZapierに分担させることにしました。

JXならではの工夫

JX通信社は、私が所属しているプロダクトであるニュースアプリのNewsDigestのほか、To BサービスのFASTALERT、KAIZODEがあり、それぞれが共通して使う社内基盤であるXWireというシステムも存在します。

また弊社の文化として、各プロダクトのチームは技術選定やインフラ管理などを自分たちの意思と責任で実践しており、たとえば「本番デプロイのためのAWSの権限をどう管理・取得するか」のような本当に会社全体で守るべきルール以外はかなり大きな裁量がプロダクト開発チームに与えられています

一方で、他プロダクトの良いと思った開発手法やツールなどは積極的にお互いに真似していく文化もあります。私はこれを個人的に「ゆるやかで自然発生的な標準化」と呼んでいます。

なので、「障害が発生したときの動きを自動化したい」といっても、プロダクトごとに以下の設定が異なりますし、今後も違いが出てくるかもしれません。

  • 障害対応時に作成するNotionページにどんな情報を含めるか、どんなTODOを含めるか*5
  • 障害対応Slackチャンネルに誰を招待するか
  • 障害の発生を誰に通知するか
  • その他、「追加で○○がしたい」etc...

そこで、プロダクトごとに異なる部分をZapierのPath*6を使って表現することにしました。

結果的に、ツールの細かな挙動もZapierの管理画面からポチポチと変更できるので、「障害対応チャンネルに招待する人を変えたい」「通知先を変えたい」などの変更も気軽にできるようになりました

まとめ

ノーコードでポチポチ気軽に変更できる部分と、コードを書いて作る部分を組み合わせて、「ゆるやかで自然発生的な標準化」の文化を活かしつつも、共通する部分を自動化して運用負荷を下げようと試みました。ノーコードのツールを使うのは初めてで、変更差分の管理やコメントを入れにくいなど慣れない部分もありましたが、Zapierが思ったよりも高機能で驚きました。

今後使われていく中で機能を落としたり追加したり改修が増えてくると、「やっぱり普通にbotに寄せよう」「いやZapier使い倒そう」など作り方自体を変えていくかもしれませんが、現時点では「制約のなかで欲しいものをチャチャっと作る」を実現するのにちょうどいい塩梅にできたかなと思います。幸い、今回の仕組みを作ったあとでこれが必要になるようなトラブルはまだ発生していないので、実際に使ってもらいながら改善していきたいと思います。

今回のツールは障害発生時に使われるものなので出番が少ないほど嬉しい性質のものではありますが、こういった改善のアイディアが出てくるのはポストモーテムで考える範囲を広げて「人の動き方をもっと良くするにはどうすればよいか」について議論することを明示的に組み込んだ一つの成果ではないかと思います。

障害対応フローについては他社さんでも色々な工夫をされていると思うので、「こういう事例しってるよ」「ウチではこんなことしてるよ」など知見がありましたら、ぜひ教えていただければ嬉しいです。

*1:https://speakerdeck.com/tatchnicolas/cdtozhang-hai-dui-ying

*2:詳しくは↑の註釈のURLから資料を見ていただきたいですが、アラートチャンネルでそのままコミュニケーションを始めるとアラートと人間の会話が混ざってしまいますし、Slackだけでは情報の整理という意味で不足を感じたのでSlack+Notionを障害対応時のツールとして両方使っています

*3:https://tech.jxpress.net/entry/slack-app-101

*4:対応フローを整備したときに指針として「false positiveには寛大になろう」と明文化して障害発生を宣言することのハードルを下げているため、実際は何もなくともチャンネル名が重複する可能性を考慮しました

*5:障害対応ページをまとめるページもプロダクトごとに分かれているため、挿入先データベースの指定も異なります。

*6:https://zapier.com/help/create/customize/add-branching-logic-to-zaps-with-paths