金曜の午後5時過ぎに本番環境を壊したことがある。
それも、「今日くらいは早く上げてしまおう」と思って実行した、軽い気持ちのデプロイで。あれから2年以上経った今でも、その日のSlackのタイムラインを鮮明に覚えている。なぜ書こうと思ったかというと、先月また別のチームで似たような話を聞いたからだ。金曜夕方のデプロイ障害は、どこでも一定の確率で起きる。
17時05分、本番が落ちた
当時のデプロイ手順は単純だった。ステージング確認 → PRマージ → GitHub Actionsのワークフロー起動。自動化は十分にできていると思っていた。
問題は、そのワークフローが本番のRDSエンドポイントと特定のプライベートサブネットに依存していて、直前のインフラ変更でサブネットのルートテーブルが書き換わっていたことだった。ステージングでは再現しない。本番だけで起きる類の問題だった。
17時05分にデプロイを実行して、17時07分にSlackのアラートチャンネルが騒ぎ始めた。
ERROR: Connection timeout to 10.0.3.14:5432
Request failed: internal server error
最初の30分で私がやったことは、次のようなものだった。
- ロールバックの実行(ワークフローのrerun-from-previous)
- ログの確認(CloudWatch Logsで直近30分)
- インフラチームへの連絡(Slackで該当チャンネルにメンション)
- 現状の整理(何が壊れているか、どこまで影響しているか)
ロールバックが完了したのが17時23分。18分間のダウンだった。
正直なところ、ロールバックを実行する判断は即座にできた。「調査より先に直す」という判断軸は、以前の経験から身についていたからだと思う。でも、その判断がなければもっと引き延びていた可能性がある。「原因が分からないのにロールバックしていいのか」と悩む人も多い。運用を考えると、「まず戻す」の共通認識がチームにあるかどうかは、初動の速さに直接影響する。
「誰がやらかしたのか」という空気
復旧後のSlackで、雰囲気が少し変わった。誰かが「そもそも金曜夕方にデプロイすること自体どうなの」と書いた。それ自体は正しい指摘だった。でもその流れで、「確認不足では」「ステージングの設定が違った」という話に進みかけた。
私はその場で、ひとつだけコメントした。
「今夜は今日起きたことを整理するだけにしましょう。来週、30分だけポストモーテムの時間をもらえますか」
これは意識的な判断だった。疲弊した状態で議論を続けると、どうしても「誰が」という方向に引っ張られる。そのまま決めた社内ルールは、往々にして形式的なものになる。当日夜の判断を「翌週に先送りする」コストは低い。一方で、誤った方向で合意してしまうコストは後から取り返しがつかない。
ポストモーテムを開いた
翌週の月曜日に、メンバー5人を集めて30分のポストモーテムを開いた。私が使ったのはシンプルな構成だった。
| 項目 | 内容 |
|---|---|
| タイムライン | デプロイ実行〜復旧までの時系列 |
| 根本原因 | インフラ変更とデプロイの依存関係が明示されていなかった |
| 貢献要因 | 金曜夕方に実行された(週末を挟む判断が遅れる) |
| 再発防止策(案) | 複数出してから優先度をつける |
最初に「今日は誰かを責めることはしない。仕組みの話だけをする」と宣言した。
根本原因を整理すると、問題は個人の判断ではなく「インフラ変更とアプリデプロイの依存関係がどこにも書かれていなかった」ことだった。ステージング環境と本番環境で設定が乖離していた事実も、このタイミングで初めて全員の認識になった。再発防止策は5案出てきた。その中から実装コストと効果を比較して、最初にやるものを決めた。
仕組みが変わるまで
ポストモーテムで決めたことは3つだった。
1. 金曜午後デプロイ禁止
金曜13時以降のプロダクションデプロイを禁止するチームルールを作った。機能リリースかホットフィックスかで例外を設けるかどうか議論したが、「例外をきっちり定義しないと形骸化する」という意見が勝ち、当面は一律禁止にした。
運用を考えると、ルールが複雑になるほど守られなくなる。シンプルな方が続く。インシデント対応コストを月次で集計すると、1件あたり平均2〜3時間の稼働が吹き飛んでいた。週1回でも防げれば、年間で数十時間は回収できる計算だった。
2. リリースチェックリストの整備
デプロイ前に確認する項目を8つに絞ったチェックリストを作った。インフラ変更と依存するデプロイの確認項目も含めた。GitHubのPRテンプレートにチェックボックスとして埋め込んだ。
## デプロイ前チェックリスト
- [ ] ステージング確認済み
- [ ] 直近1週間のインフラ変更と依存関係を確認
- [ ] ロールバック手順を把握している
- [ ] デプロイ時刻は金曜13時以前
ここは改善の余地がある。現時点では人間が毎回チェックするだけで、自動検証にはなっていない。インフラ変更とアプリデプロイの依存関係を自動検知する仕組みは、まだできていない。
3. 本番ロールバック訓練
四半期に1回、ロールバック手順を実際に実行する訓練を入れた。「ロールバックを実行できる状態」を全員が維持するための措置だった。
この3つが定着するまでに、だいたい2ヶ月かかった。金曜デプロイ禁止は最初の1ヶ月で3回破りかけた。「このリリースだけは」という案件が出るたびに、毎回議論になった。今思えば、「例外」の定義をもっと早く決めるべきだったかもしれない。結局、半年後に「P1インシデント対応は例外とする」というルールを加えた。
振り返って
あの金曜夕方のデプロイから変わったことは、ルールだけじゃない。
「インシデントが起きたとき、チームはどう反応するか」という共通認識が少し変わった気がする。復旧後の最初の反応が「誰が」ではなく「何が起きたか」に向かうようになった。ポストモーテムの場で責任追及が始まったことは、それ以降一度もない。
運用を考えると、技術的な仕組みよりもこういう文化の変化の方が、実は難しく価値があると思っている。チェックリストは古くなるし、ルールは形骸化する。でも「インシデントから学ぶ」という共通の構えは、少しずつ積み上がっていく。
今後は、チェックリストの自動化と、ステージング・本番の環境差を検知する仕組みの整備を進めていきたいと考えている。まだ道半ばなので、進捗はまた書きます。