深夜2時のマイグレーション・パニックに終止符を:SchemaHeroによる宣言的データベース・スキーマ管理

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

午前2時14分、PagerDutyの呼び出し音

午前2時14分、スマートフォンの呼び出し音が鳴り響きます。最新のAPIデプロイメントがクラッシュループに陥り、PagerDutyのアラートが眠りを妨げました。ログを確認すると、おなじみの悪夢のようなエラーが表示されています:ERROR: column "last_login_at" of relation "users" does not exist(エラー:「users」リレーションに「last_login_at」カラムが存在しません)。

誰かがマイグレーション・スクリプトの実行を忘れたのかもしれません。あるいはもっと悪いことに、スクリプトの全10ステップのうち4番目で失敗し、本番データベースが中途半端に壊れた状態になっている可能性もあります。FlywayやLiquibaseのような従来のツールは強力ですが、命令型のモデルで動作します。これらは、バージョン管理されたスクリプト(001, 002, 003…)の厳格な順序に依存しています。もし1つのステップが失敗したり、誰かが本番環境で手動変更を加えたりすれば、パイプライン全体が停止してしまいます。

現代のKubernetes環境では、デプロイメントからネットワーク・ポリシーに至るまで、ほぼすべてを「宣言的」に管理しています。データベース・スキーマも例外であってはなりません。SchemaHeroはこのパラダイムを転換します。ALTER TABLEスクリプトを書く代わりに、YAMLファイルでテーブルの「あるべき状態」を定義します。SchemaHeroが差分の抽出と実行を処理します。このモデルに移行して以来、マイグレーション関連のデプロイ失敗を80%以上削減しつつ、GitOpsワークフローをクリーンに保っているチームをいくつも見てきました。

インストール:Operatorのデプロイ

SchemaHeroは、Kubernetes OperatorとCLIプラグインの組み合わせで動作します。Operatorはクラスター内の変更を監視し、CLIは既存のデータベースからスキーマを生成するのを手助けします。

まず、Krew経由でkubectlプラグインをインストールします。このツールは、マイグレーションの検査や、現在の環境からのYAML定義の生成に不可欠です:

kubectl krew install schemahero

次に、クラスターでOperatorを実行する必要があります。CLIから直接インストールすることもできますが、本番環境ではHelmを使用することを強くお勧めします。これにより、インストール自体がバージョン管理され、再現性が確保されます:

helm repo add schemahero https://charts.schemahero.io
helm install schemahero schemahero/schemahero \
  --namespace schemahero-system \
  --create-namespace

一度 schemahero-system 内のPodが正常に起動すれば、クラスターの準備は完了です。Operatorは、DatabaseTableという2つの主要なカスタムリソース定義(CRD)を監視するようになります。

設定:SQLをコードとして扱う

SchemaHeroは「過程」ではなく「目的地」を重視します。最終的な状態を定義すれば、Operatorがそこに到達するための経路を計算します。

1. インスタンスへの接続

まず、Databaseオブジェクトを定義します。これはSchemaHeroに対し、データベースの場所と認証方法を伝えます。PostgreSQL、MySQL、CockroachDBをサポートしています。以下はPostgreSQLインスタンスの標準的な設定です:

apiVersion: databases.schemahero.io/v1alpha4
kind: Database
metadata:
  name: app-db
  namespace: storage
spec:
  connection:
    postgres:
      uri:
        valueFrom:
          secretKeyRef:
            name: db-credentials
            key: uri

接続文字列は安全に管理してください。db-credentialsシークレットには、postgres://user:password@postgres-svc:5432/appdbのようなURIを含める必要があります。SchemaHeroはこの接続を使用して「ドリフト検出(drift detection)」を行い、YAMLと実際のデータベースの状態を比較します。

2. テーブル構造の定義

.sqlファイルのことは忘れてください。これからはテーブルをTableオブジェクトとして定義します。last_login_atカラムを追加する必要がある場合、ALTER文を書くのではなく、YAMLスペックにカラムを追加するだけです。

apiVersion: schemas.schemahero.io/v1alpha4
kind: Table
metadata:
  name: users
  namespace: storage
spec:
  database: app-db
  name: users
  schema:
    postgres:
      primaryKey: [id]
      columns:
        - name: id
          type: integer
          constraints:
            notNull: true
        - name: username
          type: varchar(255)
          constraints:
            notNull: true
        - name: last_login_at
          type: timestamp with time zone
          constraints:
            nullable: true

このYAMLを適用すると、SchemaHeroは単にコードを闇雲に実行するのではなく、プラン(実行計画)を生成します。カラムがすでに存在すれば何もしません。型が異なれば、変換を計画します。

安全第一:検証と承認

データベース変更の自動化は、幼児にチェーンソーを渡すような不安を感じさせるかもしれません。事故を防ぐために、SchemaHeroは変更ごとにMigrationオブジェクトを作成します。これは、生成されたSQLがデータに適用される前に内容をレビューできるステージング領域として機能します。

保留中の変更ステータスは、プラグインで確認できます:

kubectl schemahero get migrations -n storage

SchemaHeroが実行しようとしているSQLを正確に確認するには、マイグレーションの詳細を表示します:

kubectl schemahero describe migration <migration-name> -n storage

ArgoCDを使用した厳格なGitOps構成では、本番環境のマイグレーションに手動承認を必要とするようSchemaHeroを設定できます。開発環境やステージング環境では、immediateDeploy: trueに設定してパイプラインを高速に回すことができます。もしマイグレーションが失敗した場合(例えば、すでに50万行のNULLデータがあるテーブルにNOT NULL制約を追加しようとした場合など)、OperatorはMigrationオブジェクトのステータスにエラーを報告します。その際、YAMLを更新してデフォルト値を含めるように修正し、再度プッシュすればよいのです。

構成ドリフトの終焉

SchemaHeroは標準的なKubernetes의パターンに従っているため、これらの変更の監視は簡単です。OperatorのログをLokiに転送したり、失敗したMigrationオブジェクトに対してPrometheusアラートを設定したりできます。Operatorのヘルスチェックを行うには、次のコマンドを実行します:

kubectl logs -n schemahero-system -l app.kubernetes.io/name=schemahero

ここでの本当の強みは「一貫性」です。もしジュニアDBAが本番環境で手動でカラムを削除したとしても、SchemaHeroの次のリコンシリエーション・ループ(状態回復ループ)がそのドリフトを検知します。実際の状態がGitリポジトリと一致していないことを認識し、欠落したカラムを自動的に再作成します。データベースを単なるKubernetesリソースの1つとして扱うことで、ストレスの多いマイグレーションを単なる「日常的な出来事」に変えることができます。これにより、インフラの回復力が高まり、そして何より、夜ぐっすり眠れるようになるのです。

Share: