Kubernetes上でのPostgreSQL高可用性:CloudNativePGの実践ガイド

Database tutorial - IT technology blog
Database tutorial - IT technology blog

クイックスタート:5分以内で構築する最初の高可用性クラスター

Kubernetes上で本番環境グレード of PostgreSQLクラスターを管理することは、かつては綱渡りのような作業でした。レプリケーションの遅延のバランスを調整し、恐ろしいフェイルオーバーに対処し、基本的なStatefulSetと格闘しなければなりませんでした。CloudNativePG (CNPG) は「オペレーター」パターンを使用することで、この状況を一変します。Postgresを単なるコンテナとしてではなく、自身の内部状態を理解する第一級市民(ファーストクラス・シチズン)として扱います。

まずはCloudNativePGオペレーターをインストールすることから始めましょう。これは、24時間365日休まずにデータベースを管理してくれる「デジタルDBA」だと考えてください。

kubectl apply -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/releases/cnpg-1.24.0.yaml

オペレーターが起動したら、シンプルなYAMLファイルを使用して3ノードの高可用性クラスターをデプロイできます。私は通常、次のような cluster.yaml を使用します。

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: production-db
spec:
  instances: 3
  storage:
    size: 20Gi
  # 安全性のためにPodを異なる物理ノードに分散させます
  affinity:
    enablePodAntiAffinity: true
    topologyKey: "kubernetes.io/hostname"

kubectl apply -f cluster.yaml を実行します。約3分以内に3つのPodが表示されます。1つがプライマリ(読み書き可能)として機能し、他の2つがレプリカとして機能します。プライマリノードが消失した場合、オペレーターはハートビートの失敗を検出し、数秒以内にレプリカを昇格させます。午前3時に手動で対応する必要はありません。

オペレーターが複雑な詳細をどのように処理するか

なぜ標準のStatefulSetを使わないのでしょうか? 従来のK8sコントローラーは、ステートフルなデータベースを扱うにはあまりにも「単純」すぎます。データベースがトランザクションの途中なのか、あるいはレプリケーションが同期されていないのかを判断できません。しかし、CNPGは調整ループ(reconciliation loop)の中で動作します。

インテリジェントな調整ループ

オペレーターは数秒ごとにクラスターを監視します。プライマリの健全性、レプリカの遅延、ノードの安定性を追跡します。ノードが失敗した場合、オペレーターは回復を待つだけではありません。すぐに健全なノード上に新しいPodをプロビジョニングし、プライマリからデータをクローンしてクラスターに同期し直します。私のテストでは、この自己修復プロセスは通常、監視アラートが鳴る前に完了します。

「スプリットブレイン」の悪夢を回避するフェイルオーバー

障害は避けられませんが、データ汚損は避けなければなりません。CNPGは厳格なフェンシング(fencing)プロトコルを使用して、新しいプライマリを昇格させる前に古いプライマリが完全に隔離されていることを保証します。これにより、2つのノードが同時に同じデータに書き込もうとする「スプリットブレイン」シナリオを防ぎます。手動設定がこの問題で破綻するのを何度も見てきましたが、CNPGなら問題になりません。

バックアップとポイントインタイムリカバリ(PITR)

データベースの価値は、最後に成功したリストアによって決まります。CNPGはBarman(Backup and Recovery Manager)と統合されており、AWS S3やMinIOなどのオブジェクトストレージにデータを直接ストリーミングします。これは単なる夜間のダンプではなく、継続的なWAL(Write-Ahead Log)アーカイブです。

以下は、実戦でテスト済みのS3バックアップ設定です。

spec:
  backup:
    barmanObjectStore:
      destinationPath: s3://my-backups-bucket/pg-data
      s3Credentials:
        accessKeyId:
          name: s3-creds
          key: ACCESS_KEY_ID
        secretAccessKey:
          name: s3-creds
          key: SECRET_ACCESS_KEY
      wal:
        compression: gzip
    retentionPolicy: "30d"

この設定は命綱となります。開発者が誤って午後2時15分に重要な本番テーブルを削除してしまったとしても、データベース全体を午後2時14分55秒の状態に戻すことができます。1秒単位で復元できる機能は、あらゆるチームにとって強力なセーフティネットとなります。

データインポートの効率化

レガシーデータを最新のK8sクラスターに移行する場合、フォーマットの調整が面倒なことがよくあります。生のデータを素早く変換する必要があるときは、toolcraft.app/ja/tools/data/csv-to-json を使用しています。ブラウザ上で完全に動作するため、機密データがマシンから外部に出ることはありません。SQLインポートスクリプトを実行する前のメタデータ準備に安全な選択肢です。

本番環境で得られた貴重な教訓

本番環境で複数のCNPGクラスターを管理してきた経験から、安定した環境を構築するためのいくつかの重要なルールを絞り込みました。

1. リソースの固定

Postgresはメモリ(RAM)を好みます。厳密な制限を設定しないと、トラフィックの急増時にKubernetesのOOM (Out Of Memory) Killerがデータベースを停止させてしまいます。私は常に requestslimits を全く同じ値に設定しています。中規模のワークロードの場合、まずは4GiのRAMと2つのCPUから開始し、pg_stat_statements のデータに基づいてスケールさせてください。

2. ストレージのレイテンシを優先する

ネットワークストレージは便利ですが低速です。高トランザクションのデータベースでは、AWSの io2 やGCPの premium-rwo のようなハイパフォーマンスティアを使用してください。NVMeドライブを備えたLocal Persistent Volumes (LPV) を使用できれば、パフォーマンスは標準的なクラウドディスクよりも3倍から5倍高速になることがよくあります。

3. CNPG CLIプラグインの活用

データベースの健全性を確認するために kubectl get pods だけに頼ってはいけません。CNPGプラグインをインストールして、レプリケーションの状態を詳細に確認してください。

kubectl cnpg status production-db

このコマンドにより、どのノードがプライマリか、正確なレプリケーションの遅延(バイト単位)、および継続的なバックアップが実際に正常であるかどうかを正確に把握できます。

4. 「退屈な」アップグレード

Postgresのバージョンアップは、かつては週末を費やすようなプロジェクトでした。CNPGを使えば、それは何でもない「非イベント」になります。YAML内のイメージバージョンを更新すると、オペレーターがローリングアップデートを実行します。まずレプリカにパッチを適用し、制御されたスイッチオーバーを実行してから、古いプライマリにパッチを適用します。ダウンタイムは通常5秒未満です。

運用の雑務をCloudNativePGオペレーターに任せることで、「データベースの用務員」を卒業し、コードに集中できるようになります. AWS RDSのようなマネージドサービスのパワーを享受しつつ、独自のKubernetesノードによる完全な制御と低コストを実現できます。

Share: