仕組みから学ぶ Web
応用読了目安 14#CI#CD#デプロイ#自動化

CI/CD — 壊れていることに、人間より先に気づく

自動化そのものが目的ではない。「壊れた変更が本番に届かない」ことと「いつでも戻せる」ことを仕組みで保証する。

この記事の進み方

What — パイプラインの各段階

Figureコードが本番に届くまで
  1. 1① 静的解析型チェック・Lint・フォーマット軽い
  2. 2② 単体テスト外部に依存しない部分の検証軽い
  3. 3③ 結合テストDB や外部との連携を含む検証
  4. 4④ ビルド成果物を1つ作る
  5. 5⑤ 検証環境へデプロイ本番に近い環境で動作確認重い
  6. 6⑥ 本番へデプロイ段階的に切り替える重い

どの段階も「通らなければ先へ進めない」ことが重要。1つでも「失敗しても進める」段階があると、そこは実質的に存在しないのと同じになる。

1/6
① 静的解析数秒〜数十秒。実行せずに分かる問題を潰す。最も速いので最初に置く。フォーマットの差分は自動修正して、レビューの議論から除く。

上流ほど速く、下流ほど本番に近い。速いものを先に置くことで、壊れた変更を早く弾ける。

デプロイ戦略

Compare本番への反映の仕方

1台ずつ順番に入れ替える。追加リソースが少なくて済む。

[旧][旧][旧][旧]
[新][旧][旧][旧]   ← 1台ずつ
[新][新][旧][旧]
[新][新][新][新]

切り戻し: 逆順に入れ替える(時間がかかる)
必要なリソース
+1台分
切り戻しの速さ
遅い(再デプロイ)
新旧の混在
する
実装の容易さ
簡単
影響範囲
  • 移行中は新旧が同時に動くため、DB スキーマの互換性が必要。
  • Kubernetes の既定の挙動でもあり、最も手軽。

どれを選ぶかは、切り戻しの速さと、必要なリソース量のトレードオフ。

確認 — ここまで読めたか

落ちたままのテストを1件放置すると、なぜ全体が壊れるのですか?

まず選ぶ(解答例は a〜d の記号で説明します)

Why — CI/CD が本当に買っているもの

自動化は手段です。目的は2つあります。

目的1:壊れた変更が本番に届かないこと

人間のレビューだけでは、すべての破壊を検出できません。型の不整合、テストの失敗、依存関係の壊れ。これらは機械のほうが確実に見つけます。

目的2:いつでも戻せること

どれだけ検証しても、本番でしか起きない問題があります。そのとき重要なのは「問題を起こさないこと」ではなく、**「起きたときに素早く戻せること」**です。

戻すのに30分かかるなら、障害は30分続きます。3秒で戻せるなら3秒です。この差が、リリースの心理的な重さを決めます。

同じ成果物を使い回す

環境ごとにビルドすると、「検証では動いたのに本番で動かない」が起きます。

❌ 環境ごとにビルド
  検証用にビルド → 依存ライブラリのマイナーバージョンが 1.2.3
  本番用にビルド → その間に 1.2.4 が出ていて、そちらが入る

✅ 一度だけビルドして使い回す
  ビルド → artifact:sha-a3f9c2
  検証環境にデプロイ → artifact:sha-a3f9c2
  本番環境にデプロイ → artifact:sha-a3f9c2  (同じもの)

検証したものと、本番に出すものが同一であることが保証されます。 環境ごとの差分は、成果物の中ではなく環境変数で表現します。

DB マイグレーションが一番の難所

コードは戻せますが、実行済みのマイグレーションは簡単には戻せません

❌ 危険な手順
  1. カラムを削除するマイグレーションを実行
  2. 新コードをデプロイ
  → 問題が起きて旧コードに戻したいが、カラムが無いので動かない
✅ 安全な手順(拡張 → 移行 → 縮小)
  1. 新しいカラムを追加する(旧コードは無視するので影響なし)
  2. 新旧どちらでも動くコードをデプロイ
  3. データを移行する
  4. 旧カラムを使わないコードをデプロイ
  5. 落ち着いてから旧カラムを削除する

各段階で、前後のバージョンが同時に動いても壊れないようにします。ローリングデプロイでは新旧が必ず混在するため、これは必須の考え方です。

確認 — ここまで読めたか

ステージングと本番で、それぞれビルドし直すのは何が問題ですか?

まず選ぶ(解答例は a〜d の記号で説明します)

演習 — まず自分で判断する

解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。

演習 — 設計判断を問う

このリリースを、安全に進める手順に分けてください

与えられた条件
  • users テーブルの user_name カラムを、first_name と last_name に分割する
  • アプリは Kubernetes 上で 12 台のポッドが動いている(ローリングデプロイ)
  • ユーザー数は 500 万人。マイグレーションのデータ移行には約 40 分かかる
  • user_name を参照しているコードは、アプリ内に 30 箇所ある
  • 外部の分析基盤が、users テーブルを日次でコピーしている
  • サービスは 24 時間稼働で、メンテナンス停止は避けたい
この軸で考える
  • · ローリングデプロイ中、新旧のコードが同時に動くことをどう扱うか
  • · 40分のデータ移行中、書き込みが発生することをどう扱うか
  • · 切り戻しが必要になったとき、どの時点まで戻れるか
まず選ぶ(解答例は a〜d の記号で説明します)

演習 — 説明できるか

「CI は時間がかかるだけ」と言う同僚に、何を買っているのかを説明してください

与えられた条件
  • 相手は手元でテストを流している
  • チームの CI は現在3件落ちたまま
  • まず何から手を付けるかまで示したい

読み終わりましたか?

読了にすると、これを前提とする記事がロードマップで開放されます。

この知識を使う実践ケース

この記事を前提にしている記事