配布資料の目次 › 構築年表
配布資料 34構築年表 第5章 — 運用成熟期の自動化
全事実は題材プロジェクトの git 履歴(origin/master)・イシュートラッカー・memory の実照会(2026-07-18)に基づく。
運用の自動化は、一括で設計されたものではありません。
「事故 → 検知器 → 自己修復 → 機械的ガード」の順に、事故のたびに一段ずつ積み上がりました。
デプロイフローという一つの仕組みだけでも4世代の進化があって、各世代の境目には必ず具体的な事故があります。 この章はその積み上がり方の記録です。
1. デプロイフローの4世代と、世代交代を起こした事故
| 世代 | 期間 | 方式 | 世代交代の契機 |
|---|---|---|---|
| G1 | 〜3月末 | 手動 SSH 操作 | — |
| G2 | 3/30〜 | スクリプト化 + 完了マーカー | staging 実機構築 |
| G3 | 4/29〜 | 非同期起動 + watchdog + 状態ポーリング | 「無限待機・非完了」事故 |
| G4 | 7/1〜 | CI ビルド先行 + ローカル一括ラッパー | 本番デプロイ20分事故(来ない CI イメージを8分待ち→サーバ上ビルド11分) |
G3 の事故分析が面白いです。
原因は4つ複合していました。 通知 curl にタイムアウトが無く無限ハングしました。prune にもタイムアウトが無いままでした。リモート実行ツールの60秒制限を、デプロイ時間(10〜25分)が超過しました。そして「処理中」と「ハング」を区別する完了マーカーが存在しませんでした。
対策も4点セットになります。全 curl にタイムアウト、PID 付き開始マーカー、exit code 付き完了マーカー、非同期ランチャーと状態判定スクリプトです。
watchdog は導入直後に誤発火しました。 正常ビルドの無音区間で kill してしまい、閾値を実測ベースで 300→900秒に是正し、heartbeat を追加しました。
監視の側にも事故があります。 長時間 SSH トンネル監視が idle 切断で2回連続沈黙しました。ここから「短時間 SSH(1〜2秒)の反復ポーリングで完了マーカーを見る」型が確立し、後に G4 のラッパー自体に組み込まれました。
見落とされがちな教訓を一つ。 staging デプロイスクリプトの git log を見ると、誕生から2日間でヘルスチェック方式を4回作り直しています。
運用スクリプトも一つのプロダクトであって、イテレーションで磨くものです。
2. CI の死と再誕
- 3/10。 初代デプロイ CI 誕生(staging/production ワークフロー)
- 4/2。 わずか3週間で完全停止。
workflows-disabled/へ隔離しました。削除ではなく遺構として保存しています。SSH スクリプトデプロイが正になりました - 4月〜。 デプロイ以外の検査 CI が先に復活しました(利用者向け文言の禁止語スキャン等)
- 6/27。 デプロイ CI 再誕。CI でビルドしてイメージを VPS へ直送する build-ship 方式・push 自動です
- 7/14。 push 自動トリガー撤去。デプロイを伴わないマージでも毎回フルビルドが走り、2週間で約80回、無料枠の主消費源になっていました
- 7/15。 それでも実デプロイが高頻度(前日10回)で、無料枠2,000分を使い切り CI 全停止
「push したら自動ビルド」は、一見すると正しい CI の教科書です。
ところがAI 駆動でマージ頻度が人間の数倍になると、無駄の源になります。
ビルドはデプロイ意図と結合した手動 dispatch のみとして、節約は content-hash タグとキャッシュで担保します。
3. アラートは事故のたびに1つずつ増えた
Prometheus + Grafana は staging 構築と同じ週(3/30)に compose 同居で導入しました。 コンテナの外に置くと内部メトリクスが取れない、という設計判断によります。
以後のアラートはすべて事故駆動で追加されています。
- デプロイ完了通知メール(4月)→ 通知経路の SendGrid 統一。本番に Slack webhook が無く「失敗してもログのみ」だったギャップの解消です
- ログ集約(Loki・6月)。デプロイでコンテナが入れ替わってもログが残る構造へ
- レプリケーション監視・スタンバイ監視(6/30・DR 構築と同日)
- CPU steal アラート(7/12)が型の完成形になりました。本番バッチ停止の原因がホスト側ノイジーネイバーの CPU steal と判明し、同日中に Grafana アラートを file provisioning(コード)で実装 → staging で導通実証 → ベンダ申告用の証跡収集まで1セットです2146
「アラートを設定した」と「アラートが鳴る」は別物です。 だから導通実証まで含めて1セットにしています。
4. 自己修復・無人化の4装置
① seed 自己修復。 本番の法定表示(特商法)が消失する重大事故が起きました。 原因は「法定表示の投入が開発データブロック内にあり、本番 seed では毎回スキップされる=一度消えると二度と戻らない」という構造欠陥でした。
対策は冪等な create-if-not-exists を毎デプロイ実行する自己修復化、検知(health チェック)、バックアップの3層です。1467
副作用の教訓も書いておきます。 後日、本番 DB を直接 UPDATE した改善が、seed 自己修復に巻き戻された疑いがあります。 「seed が正本」の設計は、DB 直接編集と衝突します。
② バックアップの5層。 サイレント失敗が2回起きました。
1回目(5/3・実行権限漏れで全期間失敗)は即日修正し、鮮度監視スクリプトを同日新設しました。 2回目(5/21 発覚・19日間サイレント失敗)は、原因が cron の env 未伝播と、鮮度監視スクリプト自体が本番未配備だったことです。検知する仕組みは用意してあったのに、適切なタイミングで実行されるようには配備されていない期間がありました。
一般化するとこうなります。 「書けた」では無人化になりません。実行権限・env 伝播・配備同期・鮮度監視・通知到達の5層が揃って初めて無人になります。939/1204/1206
③ イシュートラッカーの先回りアーカイブ。 無料枠250件の上限に対し、「超えてエラーが出てから対処する」実装はエラー時には hook が発火できず機能しませんでした。 保存の直前に件数を数えて先回りアーカイブする方式に変えました。1213
④ メンテナンスモード。 自動解除と手動解除を1週間で往復した末、「解除は人間の判断。ただしバイパス Cookie で検証は可能」に着地しました。
自動化しない判断も設計です。
5. 「複製が健全」と「DR が機能する」は別物だった
災害復旧(大阪スタンバイ + WireGuard)の構築と本番フェイルオーバーリハーサルは、ほぼ1日で完結しました。 そのわりに、密度がいちばん高い1日です。〜1916
- AI は着手時に「着手=即実行ではありません。本番 DB の切替を伴うため人間の承認が必要です」と宣言し、案A(本番フルリハ)と案B(専用ドリル環境・月額コスト付き)を提示してきました
- 案A(本番フルリハ)を選びました。 不可逆点(promote 直前)に go/no-go ゲートを設計します
- read-only プリフライトが本物の欠陥を発見しました。 レプリケーション自体は RPO=0 で健全なのに、アプリサーバから昇格後のスタンバイへ全ポート到達不可でした。つまり「今 DB が全損してもアプリが新 Primary に繋がらない」。現状の DR は機能しない状態だったことになります。前提是正イシューを起票し、同日中に接続経路を実装して疎通を実証しました
- 本番リハを実施しました。メンテON → fence → 昇格 → アプリ再ポイント → 稼働実証 → スタンバイ再投入 → switchback で元トポロジ完全復元(レプリケーション位置の完全一致まで確認)
- リハーサルで runbook のバグを2件、実機で発見して是正しました
未テストの手順書は、本番で必ずバグが出ます。
6. バッチデプロイ三部作は運用成熟の縮図
2週間で完結した三部作は、「文書ルール → 事故 → hook 化 → 抜け穴 → 再明文化」という運用成熟の縮図になっています。
| # | 日付 | 言った言葉(実記録) | 変わったこと |
|---|---|---|---|
| ① | 7/2 | 「複数イシューをまとめてバッチデプロイしてブラウザテストするように効率化して」 | バッチが任意からデフォルト運用へ。「In Review = デプロイ待ちキュー」意味論の導入。起票から3分で Done の doc-only 運用変更 |
| ② | 7/15 | 「デプロイ頻度が高すぎるので頻度を下げる計画を立てて」(前日10回デプロイ→無料枠枯渇の翌日) | セッション原則1回・月15回目安の明文化 + 4時間ガード hook で機械的にブロック。特筆すべきは「指示が逐次形でも、例外非該当ならキュー化を先に提案する」——指示への盲従より運用原則を優先させる規定 |
| ③ | 7/16 | (検証の後回しという抜け穴への指摘) | dev テストのバッチ化を公式化しつつ境界を固定しました。per-PR 最低ゲートは必須、staging 前に dev 一括必須、「バッチだから後で」を検証省略の言い訳にしない |
7. AI 自身の利用料も運用対象になる
AI 課金(メール解析 LLM)が右肩上がりになったときの対処も、インフラコストと同じ統治で行いました。
①版が変わったときだけ再処理する(無駄な再課金の停止) ②生成呼び出しの計量、失敗バックオフ、日次バジェット上限(環境変数で統治) ③LLM の前に決定論的なプレフィルタを置く
staging での実証で、LLM 使用が 84→3件(-96%)になりました。〜2051
AI の API 費用も「監視・上限・バックオフ」の対象になります。 CI 無料枠とまったく同じ構造の問題です。
まとめ: 無人化チェックリスト
自動化・無人化を1つ作るたびに、この5層を確認します。 バックアップで2回学んだ教訓を一般化したものです。
- 実行できるか(権限・依存ツール・env の伝播)
- 配備されているか(リポジトリにあるもの ≠ サーバにあるもの。配備の同期も自動化する)
- 動いていることを検知できるか(鮮度監視。「動いているはず」は必ず腐る)
- 失敗が人間に届くか(通知経路の実到達テストまで)
- 直せるか(自己修復 or runbook。runbook は本番リハで実証済みか)
手を動かすなら
- デプロイフロー4世代の各境目の事故を事例カードとこの章から特定して、「自分のプロジェクトは今どの世代か」を診断してみてください
- 無人化チェックリスト5層で、自分のプロジェクトの既存の自動化(CI・バックアップ等)を監査してみてください。たいてい3層目から先が無いはずです
- Keihi でバッチデプロイ運用を再現してみてください。複数イシューを In Review に貯めて、一括反映・一括検証する流れを通します
- No.6AI活用の3段階と、多くの組織が止まる場所
- No.7数年後に変わることと、変わらないこと
- No.112人が見ていない時間に、何をどこまで任せられるか
- No.115デプロイフローの4世代と、世代交代を起こした事故
- No.117CIを一度殺して、必要な分だけ再誕させた
- No.118文書 → 事故 → 機械化 → 抜け穴 → 再明文化
- No.120アラートは本当に鳴るのか、わざと壊して確かめる
- No.121気づくより、壊れても勝手に直っている方が強い
- No.122バックアップが19日間サイレント失敗していた
- No.123無人化を支える5層の点検
- No.124「複製が健全」と「復旧できる」は別物だった
- No.126バッチデプロイを起動して、見張らずに完了を確認する
ほか1回