CI/CDをデータベースとインフラに拡張する実践ロードマップ

アプリケーションのパイプラインは順調に動いています。コード変更はコミットから本番環境まで、自動テスト、ビルド、デプロイを経て流れていきます。チームは自信を持ってアップデートをプッシュできます。しかし、問題があります。データベーススキーマの変更は、誰かが本番環境で直接SQLスクリプトを実行することで行われ、インフラはクラウドコンソールにログインしてボタンをクリックすることで設定されています。

このギャップが摩擦を生みます。開発者がテーブルに新しいカラムを追加しても、マイグレーションスクリプトはDBAにメールで送られ、手動で実行されます。サーバーの設定変更が必要でも、誰かがSSHでログインしてファイルを編集しなければなりません。これらの手作業は、他の場所で構築してきた一貫性を壊します。リスクを持ち込み、監査証跡を欠き、ロールバックをほぼ不可能にします。

良いニュースは、同じパイプラインの原則がデータベースとインフラにも適用できることです。違いは詳細にあります。何をテストするか、リスクをどう管理するか、ロールバックをどう処理するかです。

データベースマイグレーションをパイプラインに組み込む

データベースの変更はアプリケーションコードとは異なります。なぜなら、それらはライブデータに対して動作するからです。アプリケーションコードのバグは修正が簡単なエラーを引き起こすかもしれません。悪いマイグレーションはデータを破損したり、永久に削除したりする可能性があります。この現実が、チームがデータベースデプロイの自動化に慎重になる理由ですが、代替手段である手動実行はさらに悪いです。

まず、すべてのスキーマ変更をコードとして扱うことから始めます。各マイグレーションはバージョン管理に保存されたスクリプトであり、アプリケーションと同じリポジトリか専用リポジトリに置きます。スクリプトには明確なバージョン、何を行うかの説明、対応するロールバックスクリプトが必要です。

例えば、カラムを追加するマイグレーションは次のようになります:

-- V002__add_status_column.sql
-- Forward migration: add a status column with a default value
ALTER TABLE users ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'active';
-- V002__add_status_column_rollback.sql
-- Rollback migration: remove the status column
ALTER TABLE users DROP COLUMN status;

次の図は、データベースとインフラのステージが既存のパイプラインにどのように組み込まれるかを示しています:

flowchart TD A[コードコミット] --> B[ビルド & 単体テスト] B --> C[アプリケーションをステージングにデプロイ] C --> D[データベースマイグレーションのドライラン] D --> E[インフラプロビジョニング] E --> F[結合テスト] F --> G{承認ゲート?} G -- Yes --> H[本番デプロイ] G -- No --> I[ロールバック] H --> J[データベースマイグレーション適用] J --> K[インフラ適用] K --> L[スモークテスト] L -- 成功 --> M[デプロイ完了] L -- 失敗 --> I I --> N[以前の状態に復元]

パイプラインはこれらのマイグレーションを開発、ステージング、本番の各環境で自動的に実行します。しかし、リスクが高いため、追加のゲートが必要です:

  • ステージングでのドライラン: 本番でマイグレーションを実行する前に、本番と同程度のデータ量でステージングで実行します。これにより、パフォーマンスの問題や予期しないロック動作を検出できます。
  • 互換性テスト: マイグレーションが既存データと互換性があるかを確認します。デフォルト値なしでNOT NULLカラムを追加するマイグレーションは、そのカラムにNULL値を持つ既存行があると失敗します。
  • 破壊的変更に対する承認ゲート: カラムの削除、データ型の変更、テーブルの削除には手動承認が必要です。これらの変更は元に戻すのが難しいか不可能です。

すべてのマイグレーションにはテスト済みのロールバックスクリプトが必要です。カラムの追加は通常、安全に元に戻せます。テーブルの削除はそうではありません。パイプラインは、マイグレーションが失敗した場合やチームが元に戻すことを決定した場合に、自動的にロールバックを実行できる必要があります。

Infrastructure as Code: クリックではなく宣言する

インフラには、サーバー、ネットワーク、ロードバランサー、データベースインスタンス、そしてアプリケーションの実行に必要なすべてのコンポーネントが含まれます。これらをクラウドコンソールから手動でプロビジョニングすると、いくつかの問題が発生します:

  • 環境間にずれが生じます。開発環境と本番環境で微妙に異なる設定になることがあります。
  • 変更の再現が困難です。サーバーがクラッシュした場合、まったく同じものを再作成できますか?
  • 監査証跡がありません。先週、誰がファイアウォールルールを変更しましたか?

解決策は、インフラをコードとして宣言することです。インフラがどうあるべきかを記述した設定ファイルを書き、パイプラインにその設定を適用させます。これがInfrastructure as Code(IaC)です。

Terraform、AWS CloudFormation、Pulumiなどのツールを使用すると、ファイル内でリソースを定義できます。これらのファイルはアプリケーションコードと同じパイプラインを通過します。リポジトリに入り、コードレビューを受け、開発環境でテストされ、ステージングと本番に適用されます。

インフラのテストはアプリケーションのテストとは異なります。アプリケーションテストはコードが正しく動作するかを確認します。インフラテストは設定が期待通りの環境を生成するかを確認します:

  • 必要なポートは開いていますか?
  • ファイアウォールは正しく設定されていますか?
  • OSのバージョンは正しいですか?
  • リソースサイズ(CPU、メモリ、ディスク)は指定通りですか?

さらに進んだチームは、隔離された環境でインフラをプロビジョニングし、テストを実行した後に破棄します。これにより、本番に変更を適用する前に高い確信を得られます。

インフラのリスクゲートもデータベースと同じパターンに従います。ディスクサイズを調整する変更は自動テストだけで十分かもしれません。ネットワークを再構成したり、データベースの種類を変更する変更は、手動承認とより徹底的な検証が必要です。

データベースとインフラのロールバック戦略

アプリケーションコードのロールバックは通常簡単です。以前のバージョンをデプロイするだけです。データベースマイグレーションやインフラ変更のロールバックには、より多くの計画が必要です。

データベースマイグレーションの場合、ロールバックスクリプトは前方マイグレーションと同時に作成する必要があります。パイプラインでロールバックをテストしてください。頭の中だけで考えないでください。一部のマイグレーションは追加的(カラムの追加)で、きれいにロールバックできます。その他は変革的(テーブルの分割)で、注意深いロールバックロジックが必要です。安全にロールバックできないマイグレーションがある場合、それはマイグレーションアプローチを再設計する必要があるというシグナルです。

インフラの場合、パイプラインは設定の以前の状態を保存する必要があります。ロールバックが必要な場合、パイプラインは以前の設定を適用します。これは宣言型IaCツールでうまく機能します。なぜなら、それらは現在の状態と望ましい状態の差分を自動的に処理するからです。

パイプライン拡張のための実践的チェックリスト

領域 追加すべきもの リスクゲート ロールバック
データベース バージョン管理下のマイグレーションスクリプト ステージングでのドライラン、破壊的変更には承認 マイグレーションごとにテスト済みロールバックスクリプト
インフラ IaC設定ファイル 自動検証、アーキテクチャ変更には承認 以前の設定を保存しデプロイ可能に

パターンは繰り返される

データベースとインフラをパイプラインに組み込んだら、同じパターンが他の領域にも適用できることに気づくでしょう。環境設定、フィーチャーフラグ、モバイルアプリのリリースなどです。詳細は変わります。何をテストするか、リスクをどう管理するか、どうロールバックするか。しかし、核となるアイデアは同じです。すべての変更は一貫性があり、テストされ、元に戻せる経路をたどります。

まずはパイプラインに1つのデータベースマイグレーションを追加することから始めてください。次に1つのインフラ変更です。最初のいくつかはプロセスを構築しているため遅く感じるでしょう。しかし、それぞれが次の変更をより速く、より安全にします。

目標は自動化そのものではありません。何かが壊れたとき、そしてそれは必ず起こりますが、何が変わったのか、どう修正するのか、どう再発を防ぐのかを正確に把握できるようにすることです。