GitOps と blue-green / 無停止デプロイ
症状
目標: スキーマとアプリケーションの変更をダウンタイムなしでデプロイする。expand-contract マイグレーション、blue-green 環境、フィーチャーフラグ、自動ロールバックで無停止に近づける。
1. GitOps: Git を唯一の信頼できる情報源にする
インフラ、スキーママイグレーション、アプリケーションのバージョンを Git で定義する。デプロイはリポジトリへのマージによってトリガーされる (GitOps)。リコンサイラー (Argo CD/Flux または CI/CD) が望ましい状態を実環境に適用する。これによりすべての変更が監査可能かつ再現可能になり、必要に応じて以前のコミットに戻せる。
PostgreSQL
# repo/
# migrations/ (Vxxx__*.sql)
# k8s/ (Deployment, Service)
# flags/ (feature flag config)2. スキーマを後方互換に変更する (expand-contract)
無停止のためには、スキーマを破壊的な 1 ステップで変更せず、2 つのフェーズに分ける。EXPAND: 旧コードと新コードが同時に動作できるよう新しい構造 (新しい列/テーブル) を追加する (NULL 許容列、デフォルト付き、二重書き込み)。アプリケーションが新しい構造に移行した後に CONTRACT: 使われなくなった古い列/テーブルを別のマイグレーションで削除する。これによりデプロイ中も旧バージョンと新バージョンのアプリケーションが問題なく並行稼働する。
PostgreSQL
-- EXPAND (V5): backward-compatible addition
ALTER TABLE customer ADD COLUMN email text;
-- for a while the code writes/reads both columns
-- CONTRACT (V9): drop the old column
ALTER TABLE customer DROP COLUMN mail_old;3. リスクのある動作をフィーチャーフラグの背後に置く
新しいコードパス (新しい列の読み取りなど) をフィーチャーフラグの背後で条件付きで実行する。スキーマの準備ができたらフラグをオンにし、問題があればデプロイに触れずにオフにする。フラグはコードのデプロイ (deploy) と機能の有効化 (release) を分離する。expand フェーズは出荷されるが、動作の変更は制御された形で有効化され、迅速に元に戻せる。
PostgreSQL
-- application layer (pseudocode)
-- if flag('new_email_field'):
-- SELECT email FROM customer ...
-- else:
-- SELECT mail_old FROM customer ...4. blue-green 環境を構築する
2 つの同一の環境を保持する: 'blue' (本番稼働中) と 'green' (新バージョン)。新しいアプリケーションバージョンを green にデプロイし、実トラフィックを受ける前に検証する。準備ができたらルーター/トラフィックを green に切り替える。重要な点: データベースは通常共有されているため、スキーマは両方のバージョンと互換でなければならない (expand-contract がこれを保証する)。切り替え時に接続先が変わっても、スキーマの互換性によりダウンタイムは発生しない。
PostgreSQL
# traffic is switched to green (new version)
# shared DB: schema must be compatible with both blue and green5. 監視でデプロイを検証する (カナリア/観察)
すべてのトラフィックを切り替える前に、エラー率、レイテンシ、データベースのエラー/ロック数、レプリケーションラグなどのメトリクスを監視する。必要に応じてトラフィックのごく一部 (カナリア) を green に送って観察する。ヘルス指標が良好ならトラフィックを段階的に増やし、悪ければ先に進まない。監視は自動ロールバックの判断材料となる。
PostgreSQL
-- live health queries
SELECT count(*) FROM pg_stat_activity WHERE wait_event_type='Lock';
SELECT * FROM pg_stat_replication;6. 自動ロールバックを準備する
メトリクスがしきい値を超えたら、デプロイは自動的にロールバックされなければならない: blue-green では、トラフィックを素早く blue (旧バージョン) に戻す。blue はまだ稼働しているため、アプリケーションのロールバックは即時である。スキーマ側のロールバックは通常不要である: expand-contract により新しいスキーマは旧コードとも互換であるため、アプリケーションをロールバックすれば十分である。そのため、スキーマの変更はアプリケーションのデプロイから独立させ、常に後方互換に保つべきである。
PostgreSQL
# traffic instantly returns to blue (application rollback)
# schema is not rolled back: expand-contract is compatible with old code
# if truly needed: write a new corrective migration