このガイドでは、Google Distributed Cloud(GDC)エアギャップ環境の 3 つのゾーンに高可用性 PostgreSQL スタックをデプロイするための包括的なチュートリアルを提供します。必要なソフトウェア アーティファクトを準備し、ターゲット VM をブートストラップして、Autobase を使用してプロビジョニング プロセス全体を自動化する方法について説明します。このガイドでは、PostgreSQL のライフサイクルをオーケストレートし、自動フェイルオーバーを処理するプライマリ管理レイヤとして Patroni を使用します。
アーキテクチャ
このアーキテクチャは、3 つのアベイラビリティ ゾーンに分散された 3 つの VM 環境で構成されています。

すべての VM は同一であり、同じ場所に配置されたサービスのスタックを実行します。
- PostgreSQL 17: コア リレーショナル データベース エンジン。
- Patroni: 高可用性マネージャー。PostgreSQL プロセスのライフサイクルを処理し、自動フェイルオーバーを実行します。ポート
8008(エンドポイント/primary)で HTTPS REST API を公開します。この API は、ロードバランサが現在のリーダーを識別するために使用されます。 - etcd: 分散構成ストア(DCS)。リーダー選出のコンセンサス レイヤを提供し、Patroni の構成を保存します。
- PgBouncer: PostgreSQL の前に配置され、接続オーバーヘッドを安定させる接続プーラー。ポート
6432でアプリケーション トラフィックの推奨エントリ ポイントを提供します。
このスタックには、GDC エアギャップ グローバル L4 ロードバランサも含まれています。これは、安定した仮想 IP(VIP)を提供するプラットフォーム マネージド サービスです。アプリケーションは、ポート 6432 の安定した VIP に接続します。ロードバランサは、この VIP を現在のリーダー VM の PgBouncer にルーティングします。PgBouncer は、リクエストをローカルの PostgreSQL インスタンスにプロキシします。トラフィック フローを管理するため、ロードバランサはヘルスチェックとして Patroni HTTPS エンドポイントを継続的にポーリングします。
リーダー VM のヘルスチェックは HTTP 200 OK を返して、VM がトラフィックの準備ができていることを示します。一方、レプリカ VM のヘルスチェックは HTTP 503 Service Unavailable を返して、ロードバランサにバイパスするように指示します。リーダーに障害が発生すると、新しいリーダーが選出され、その Patroni インスタンスが HTTP 200 OK を返すようになります。これにより、ロードバランサはトラフィックを新しい VM の PgBouncer ポートに自動的にリダイレクトします。
高可用性を確保し、データ損失を防ぐため、スタックはクォーラムのコンセプトに依存しています。3 つの VM を使用する場合、システムは、リーダーを選出して運用を継続するために、少なくとも 2 つのメンバーが正常で通信中である必要があります。etcd と Patroni によって管理されるこの多数決ベースのコンセンサスにより、スタックは単一の VM またはゾーンの完全な障害を自動的に許容できます。
パフォーマンスに関する注意事項
デプロイを計画する際は、パフォーマンスと信頼性を最適化するために、次の具体的な要素を考慮してください。
- ハードウェアのサイズ設定: 要件はワークロードによって異なりますが、各 VM の開始点として次の標準プロファイルを使用します。
- 開発 / 概念実証: 2 vCPU、8 GB RAM(安定した運用のための最小要件)。
- 小規模な本番環境: 4 vCPU、16 GB RAM。適度な同時実行性を備えた内部ツールに適しています。
- 標準的な本番環境: 8 vCPU、32 GB RAM。ミッション クリティカルなアプリケーションに推奨されるベースライン。
- 高スループット: 16 個以上の vCPU、64 GB 以上の RAM。メモリ(PostgreSQL 共有バッファ)に広範なデータ キャッシュを必要とするワークロード。
- ストレージのパフォーマンス: 高性能なストレージが不可欠です。etcd の安定性を確保するために、SSD ディスクを使用することを強くおすすめします。etcd はディスク書き込みレイテンシに非常に敏感です。公式の etcd ハードウェア ガイドラインでは、p99 ディスク WAL fdatasync レイテンシを 10 ミリ秒未満にすることを推奨しています。
- ネットワーク レイテンシ: VM 間のレイテンシは、レプリケーションのパフォーマンスに直接影響します。
- etcd クォーラム: 選出のタイムアウトとクラスタの不安定さを防ぐため、平均ラウンドトリップ時間(RTT)は 50 ミリ秒未満(理想的には 10 ミリ秒未満)にする必要があります。
- 同期レプリケーション: 構成されている場合、すべての書き込みトランザクションはレプリカの確認応答を待機する必要があります。GDC エアギャップのゾーン間レイテンシは通常 1 ミリ秒未満です。これは、書き込みオーバーヘッドを最小限(通常 10 ~ 30%)に抑えるのに最適です。
- PgBouncer の役割: PostgreSQL は接続ごとに新しい OS プロセスを作成します。これにより、約 10 MB の RAM が消費され、CPU コンテキスト切り替えのコストが発生します。PgBouncer は、永続接続のプールを維持することでこのオーバーヘッドを削減し、データベースが大幅に少ないバックエンド プロセスで数千のアプリケーション接続を処理できるようにします。
- サイドカー コンポーネント: Patroni と etcd は軽量ですが、一貫した CPU の可用性が必要です。高負荷のシナリオでは、ハイパーバイザ レベルで VM がオーバーサブスクライブされていないことを確認し、ハートビートとリーダーのメンテナンスに必要な CPU サイクルが「盗まれる」ことがないようにします。
- カーネルのチューニング: Autobase の自動化により、sysctl パラメータ(
vm.swappiness、net.core.somaxconnなど)の構成や透過的な巨大ページの無効化(THP)など、PostgreSQL に有益な最適化が自動的に適用されます。これらの変更により、メモリ管理のオーバーヘッドが削減され、トラフィックの多いデータベース インスタンスのネットワーク スループットが向上します。
始める前に
デプロイを開始する前に、環境が次の要件を満たしていることを確認する必要があります。
VM の要件を確認する
このチュートリアルでは、GDC エアギャップ プロジェクトに 3 つの VM を作成する必要があります。VM に関して、次の点と要件を考慮する必要があります。
- ゾーンの分散: このデプロイをゾーン障害に対して真に復元力のあるものにするには、VM を 3 つの異なるアベイラビリティ ゾーンに分散する必要があります。ただし、VM が 2 つのゾーンまたは 1 つのゾーンに配置されている場合でも、デプロイは同じままです。最も重要なのは、すべての VM が内部 IP アドレスを使用してネットワーク経由で相互に通信できることです。
- オペレーティング システム: このチュートリアルでは、Ubuntu 22.04 イメージを使用していることを前提としています。別のディストリビューションを使用している場合、このガイドの以降の手順は異なる場合があります。
- リソース: このチュートリアルでは、VM ごとに少なくとも 2 つの CPU と 8 GB のメモリをプロビジョニングする必要があります。本番環境では、特定のワークロードに適したリソースをプロビジョニングする必要があります(パフォーマンスに関する考慮事項をご覧ください)。
- ネットワーク IP: 各 VM の内部 IP アドレスと外部 IP アドレスの両方をメモしておきます。このガイドでは、外部ワークステーションからコマンドを実行するため、Ansible 制御に外部 IP を使用します。内部 IP は、サービス間の通信とバインディングに使用されます。ネットワーク内にブートストラッパー VM をプロビジョニングした場合は、内部 IP のみが必要になります。
- アクセス: Ansible の自動化では、パスワード プロンプトでブロックされることなく、管理タスク(パッケージのインストール、システム構成の変更)を実行する必要があるため、デプロイ ユーザーにはパスワードなしの sudo アクセス権が必要です。
- SSH: Ansible がターゲット VM に安全かつ非インタラクティブに接続できるように、キーベースの認証を有効にする必要があります。
ローカル ワークステーション ソフトウェアを準備する
デプロイを管理し、エアギャップ アーティファクトを準備するには、ローカル ワークステーションに一連の自動化ツールとコンテナ化ツールをインストールする必要があります。
- Ansible 2.17.0 以降: デプロイ プレイブックとロールを実行する自動化エンジン。
- Docker: ターゲット VM(Ubuntu 22.04)と同じ環境内で OS の依存関係を pull してパッケージ化するために使用されます。
- PostgreSQL クライアント(
psql): ローカル ワークステーションからテストクエリを実行し、データ レプリケーションを確認するために必要です。 Autobase リポジトリ:
- リポジトリのクローンを作成して、自動化のハンドブックとロールにアクセスします。 https://github.com/vitabaks/autobase
特定のリリースをチェックアウトします(このガイドではバージョン 2.5.2 を使用します)。
git checkout 2.5.2別のディストリビューションを使用している場合、このガイドの以降の手順は異なる場合があります。
このガイドのハンドブックを実行するには、ロールの接頭辞を解決できるように、ローカルの
autobaseソースコードを Ansible コレクションとしてインストールする必要があります。cd autobase/automation ansible-galaxy collection install . --force
いくつかの環境変数を作成する
このガイドでは、コマンドを簡素化するために次の環境変数を使用します。これらの変数には、プロジェクト ID、VM のアベイラビリティ ゾーン、ホスト名、ロードバランサがクラスタを識別するために使用するラベルなどの重要なパラメータが格納されます。現在のシェル セッションで、環境の実際の値に設定します(ゾーンはスペースで区切ります)。
VM には任意の名前を設定できますが、このガイドでは、クラスタノードの任意の名前として postgres-vm-1、postgres-vm-2、postgres-vm-3 を使用します。
export PROJECT_ID="your-project-id"
export ZONES="zone1 zone2 zone3"
export VM1_NAME="postgres-vm-1"
export VM2_NAME="postgres-vm-2"
export VM3_NAME="postgres-vm-3"
export VM_LABEL="app=my-postgres-cluster"
export CLUSTER_NAME="my-postgres-cluster"
Ansible を構成する
次のテンプレートを使用して、inventory.ini ファイルで VM 環境を定義します。
[master]
postgres-vm-1 ansible_host=XX.XX.XX.XX hostname=postgres-vm-1 bind_address=XX.XX.XX.XX
[replica]
postgres-vm-2 ansible_host=XX.XX.XX.XX hostname=postgres-vm-2 bind_address=XX.XX.XX.XX
postgres-vm-3 ansible_host=XX.XX.XX.XX hostname=postgres-vm-3 bind_address=XX.XX.XX.XX
[postgres_cluster:children]
master
replica
[etcd_cluster]
postgres-vm-1
postgres-vm-2
postgres-vm-3
[all:vars]
ansible_user=...
ansible_ssh_private_key_file=~/.ssh/...
postgresql_version=17
with_haproxy_load_balancing=false
patroni_superuser_password=...
etcd_package_repo="file:///tmp/packages/etcd-v3.5.25-linux-amd64.tar.gz"
installation_method="packages"
install_postgresql_repo=false
install_timescale_repo=false
install_citus_repo=false
apt_repository=[]
yum_repository=[]
install_system_packages=false
patroni_installation_method=deb
構成について:
[master]と[replica]: プライマリ データベース VM とセカンダリ データベース VM を定義します。VM1_NAME、VM2_NAME、VM3_NAMEの環境変数に設定された実際の VM 名を使用してください。[postgres_cluster:children]: マスターノードとレプリカノードの両方を集約するグループ。Ansible は 1 つのコマンドでデータベース クラスタ全体をターゲットにできます。[etcd_cluster]: etcd コンセンサス クラスタに参加するノードを定義します。これには、高可用性を確保するために 3 つのデータベース ノードがすべて含まれます。ansible_host:(各 VM の場合)Ansible がその VM に接続するために使用する VM の外部上り(内向き)IP。XX.XX.XX.XXは、実際の外部 IP に置き換えます。bind_address:(各 VM の場合)VM の内部 IP アドレス。XX.XX.XX.XXは、実際の内部 IP に置き換えます。ansible_user: Ansible が SSH を使用してターゲット VM に接続するために使用するリモート ユーザー。...は、実際のユーザー名に置き換えます。ansible_ssh_private_key_file: ターゲット VM への認証に使用される秘密 SSH 認証鍵のローカルパス。~/.ssh/...は実際のパスに置き換えます。patroni_superuser_password:postgresユーザーのパスワード。ここでは、安全性の高い強力なパスワードを使用してください。with_haproxy_load_balancing=false: プラットフォーム ネイティブの L4 ロードバランサを使用しているため、ローカル HAProxy を無効にします。etcd_package_repo: VM のブートストラップ ディレクトリ内の etcd バイナリのローカルパスを指します。installation_method="packages": ソースからコンパイルしたり、Python pip を使用したりするのではなく、OS パッケージを使用してコンポーネントをインストールするように自動化に指示します。install_..._repo=falseと_repository=[]: これらのオーバーライドにより、Ansible がインターネットにアクセスして外部リポジトリを追加したり、パッケージ リストを更新したりすることを防ぎます。install_system_packages=false: 初期化フェーズまたはブートストラップ フェーズですでにプロビジョニングしたパッケージを自動化でダウンロードしてインストールしようとしないようにします。patroni_installation_method=deb: インストールした.debパッケージを使用するようにロールに指示します。
VM を初期化する
データベース スタックには、ベースの Ubuntu イメージに含まれていない可能性のある複数の OS パッケージとライブラリが必要です。VM はインターネット アクセスできないエアギャップ環境にあるため、これらの依存関係を自身でダウンロードすることはできません。
この問題を解決する手順は次のとおりです。
ローカル ワークステーションで Docker コンテナを使用して、必要なファイルをすべてダウンロードします。次のコマンドは、
apt-rdependsを使用して、ターゲット アプリケーションに必要なすべての共有ライブラリと依存関係を再帰的に特定します。コンテナ内の公式 PostgreSQL リポジトリを構成してバージョン 17 のアーティファクトを取得し、依存関係リストを反復処理して個々の.debファイルをダウンロードします。その際、ターゲット VM でのバージョンの競合を回避するために、コアシステム ライブラリ(libc6やhostnameなど)を除外します。最後に、GitHub からスタンドアロンの etcd バイナリを直接取得します。まず、パッケージを格納するディレクトリを作成します。
mkdir -p ./packages次に、Docker コマンドを実行して、必要なすべてのパッケージと etcd バイナリをダウンロードします。
docker run --rm --platform linux/amd64 -v "$(pwd)/packages:/packages" \ ubuntu:22.04 bash -c " set -e apt-get update apt-get install -y ca-certificates curl gnupg apt-rdepends # Add PostgreSQL Repository curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \ gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg echo 'deb http://apt.postgresql.org/pub/repos/apt jammy-pgdg main' > \ /etc/apt/sources.list.d/pgdg.list apt-get update # Define Application Targets + Explicit dependencies needed for air-gap TARGETS='unzip tar pgbouncer patroni netdata postgresql-17 \ postgresql-client-17 postgresql-contrib-17 \ postgresql-server-dev-17 postgresql-17-dbgsym \ python3-psycopg2 python3-click python3-yaml python3-prettytable \ python3-urllib3 python3-tz python3-pip python3-setuptools \ python3-cryptography moreutils vim jq acl zstd libjq1 \ libpython3.10-stdlib libexpat1-dev zlib1g-dev libipc-run-perl \ libtime-duration-perl libjson-perl libpython3-dev \ libjs-sphinxdoc python3-wheel' # Resolve all recursive dependencies ALL_DEPS=\$(apt-cache depends --recurse --no-recommends --no-suggests \ --no-conflicts --no-breaks --no-replaces --no-enhances \$TARGETS | \ grep '^\w' | sort -u) cd /packages for pkg in \$ALL_DEPS; do if apt-cache show \"\$pkg\" > /dev/null 2>&1; then # Filter system core to avoid VM conflicts/breaks # We exclude core OS libraries (libc, systemd, etc.) because these # often cause version conflicts if the VM's patch level differs # from the online container. FILTER='base-files|debianutils|coreutils|findutils|diffutils|sed' FILTER+='|grep|gzip|hostname|ncurses|perl-base|libc6|binutils' FILTER+='|linux-libc|libc-bin|libc-dev-bin|systemd|dpkg|init' if [[ ! \"\$pkg\" =~ \$FILTER ]]; then apt-get download \"\$pkg\" || echo \"Failed \$pkg\" fi fi done # Download etcd binary if [ ! -f etcd-v3.5.25-linux-amd64.tar.gz ]; then curl -L https://github.com/etcd-io/etcd/releases/download/v3.5.25/\ etcd-v3.5.25-linux-amd64.tar.gz -o etcd-v3.5.25-linux-amd64.tar.gz fi "Ansible を使用して、3 つのターゲット VM すべてにアーカイブを同時にアップロードします。
ansible all -i inventory.ini -m copy -a "src=packages.tar.gz dest=/tmp/" -bVM 上の既存のパッケージ データを消去し、新しい tar ファイルを抽出します。
ansible all -i inventory.ini -m shell -a "rm -rf /tmp/packages && \ mkdir -p /tmp/packages && tar -xzf /tmp/packages.tar.gz -C /tmp/packages" -bダウンロードしたすべての
.debパッケージの非インタラクティブ インストールを実行します。エアギャップ環境で特定の事前依存関係に関する問題を回避するには、--force-dependsフラグの後にapt-get install -fyを使用して、依存関係ツリーをローカルで解決します。ansible all -i inventory.ini -m shell -a "DEBIAN_FRONTEND=noninteractive \ NEEDRESTART_MODE=a dpkg -i --force-depends /tmp/packages/*.deb" -b ansible all -i inventory.ini -m shell -a "DEBIAN_FRONTEND=noninteractive \ NEEDRESTART_MODE=a apt-get install -fy" -b自動化の準備が整う前に、デフォルトの未構成の状態でサービスが開始されないように、すべてのサービスを直ちに停止します。
ansible all -i inventory.ini -m shell -a \ "systemctl stop patroni etcd pgbouncer postgresql || true" -b最後に、デフォルトの PostgreSQL クラスタと既存の etcd データを削除して、クリーンな初期化を可能にします。
ansible all -i inventory.ini -m shell -a \ "pg_dropcluster 17 main --stop || true" -b ansible all -i inventory.ini -m shell -a \ "rm -rf /var/lib/postgresql/17/main/* /var/lib/etcd/default.etcd/*" -b
データベース インフラストラクチャをプロビジョニングする
VM がブートストラップされ、インベントリが構成されたので、Ansible で Autobase 自動化ハンドブックを使用して、高可用性 PostgreSQL スタックをデプロイできます。
まず、事前チェックを実行して、環境の準備が整っていることを確認します。
ansible-playbook vitabaks.autobase.deploy_pgcluster -i inventory.ini \
--tags pre_checks
チェックに合格した場合は、完全なデプロイに進みます。
ansible-playbook vitabaks.autobase.deploy_pgcluster -i inventory.ini
想定される出力: ハンドブックは、すべてのターゲット VM が到達して更新されたことを示す「PLAY RECAP」で正常に完了します。
PLAY RECAP ********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=254 rescued=0 ignored=0
postgres-vm-1 : ok=160 changed=53 unreachable=0 failed=0 skipped=514 rescued=0 ignored=2
postgres-vm-2 : ok=116 changed=40 unreachable=0 failed=0 skipped=505 rescued=0 ignored=2
postgres-vm-3 : ok=116 changed=40 unreachable=0 failed=0 skipped=505 rescued=0 ignored=2
デプロイを確認する
デプロイが完了したら、いくつかのチェックを実行して、すべてのコンポーネントが正常に機能していることを確認する必要があります。
HA ステータスを確認する
高可用性マネージャーのステータスを確認して、各 VM に割り当てられているロールを確認します。
ansible master -i inventory.ini -m shell -a "patronictl list" -b
出力例:
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 1 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
ヘルスチェック エンドポイントを確認する
REST API を使用して、Patroni がリーダーとレプリカを正しく識別していることをテストします。リーダー VM のヘルスチェックは 200 OK を返し、レプリカ VM のヘルスチェックは 503 Service Unavailable を返す必要があります。
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM3_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
個々の VM の健全性を確認する
すべての PostgreSQL インスタンスの準備状況を確認します。
ansible postgres_cluster -i inventory.ini -m shell -a "pg_isready -p 5432" -b
出力例:
postgres-vm-1 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
postgres-vm-2 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
postgres-vm-3 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
etcd の健全性を確認する
localhost をエンドポイントとして使用して、すべての VM でコンセンサス レイヤの健全性を確認します。
ansible all -i inventory.ini -m shell -a "ETCDCTL_API=3 etcdctl \
--endpoints=https://localhost:2379 \
--cacert=/etc/etcd/tls/ca.crt \
--cert=/etc/etcd/tls/server.crt \
--key=/etc/etcd/tls/server.key \
endpoint health" -b
出力例:
postgres-vm-1 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 28.78311ms
postgres-vm-2 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 33.081265ms
postgres-vm-3 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 24.414291ms
グローバル ロードバランサを構成する
データベース スタックに安定した仮想 IP(VIP)を提供するには、gdcloud CLI を使用してプラットフォーム ネイティブのグローバル L4 ロードバランサを構成します。
前提条件:
- プロジェクトに
load-balancer-adminロールがあることを確認します。 ロードバランサがサービスを提供するインスタンスを正しくターゲットに設定できるように、VM にラベルを適用します(
kubeconfigパラメータ値を、各ゾーンに対応する Management APIkubeconfigファイルに置き換えます)。kubectl --kubeconfig=ZONE_A_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM1_NAME} \ ${VM_LABEL} kubectl --kubeconfig=ZONE_B_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM2_NAME} \ ${VM_LABEL} kubectl --kubeconfig=ZONE_C_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM3_NAME} \ ${VM_LABEL}
- プロジェクトに
ロード バランシングのアクセスレベルを定義します。プロジェクトのネットワーク外から接続する必要がある場合は
EXTERNALを設定し、VPC 内からのみアクセスする必要がある場合はINTERNALを設定します。このチュートリアルでは、外部設定を使用します。export LB_SCHEME=EXTERNALヘルスチェックを作成します。ロードバランサは、Patroni の REST API を使用してリーダーを識別します。
gdcloud compute health-checks create https ${CLUSTER_NAME}-hc \ --project=${PROJECT_ID} \ --port=8008 \ --request-path="/primary" \ --check-interval=10 \ --timeout=5 \ --healthy-threshold=2 \ --unhealthy-threshold=3 \ --globalVM が配置されているゾーンごとに、個別のゾーン バックエンドを作成します。
for zone in $(echo $ZONES); do gdcloud compute backends create ${CLUSTER_NAME}-backend-${zone} \ --project=${PROJECT_ID} \ --zone=${zone} \ --labels="${VM_LABEL}" doneグローバル バックエンド サービスを作成します。
gdcloud compute backend-services create ${CLUSTER_NAME}-bes \ --project=${PROJECT_ID} \ --health-check="${CLUSTER_NAME}-hc" \ --globalゾーン バックエンドをグローバル サービスに追加します。
for zone in $(echo $ZONES); do gdcloud compute backend-services add-backend ${CLUSTER_NAME}-bes \ --project=${PROJECT_ID} \ --backend=${CLUSTER_NAME}-backend-${zone} \ --backend-zone=${zone} \ --global doneグローバル転送ルール(VIP)を作成します。このルールにより、ポート
6432でデータベースが公開されます。gdcloud compute forwarding-rules create ${CLUSTER_NAME}-fr \ --project=${PROJECT_ID} \ --load-balancing-scheme=${LB_SCHEME} \ --backend-service=${CLUSTER_NAME}-bes \ --ip-protocol-port="TCP:6432" \ --globalVIP アドレスを取得します。
LB_IP=$(gdcloud compute forwarding-rules describe ${CLUSTER_NAME}-fr \ --project=${PROJECT_ID} \ --load-balancing-scheme=${LB_SCHEME} \ --global \ --format=json \ | jq -r '.metadata.annotations["networking.gke.io/forwardingRuleCIDR"]' \ | cut -d '/' -f 1) echo "The load balancer IP is: ${LB_IP}"ProjectNetworkPolicy(PNP)を作成して、PgBouncer ポートへの上り(内向き)トラフィックを許可します(kubeconfigパラメータ値を、対応する環境のグローバル APIkubeconfigファイルに置き換えます)。kubectl --kubeconfig=GLOBAL_API_KUBECONFIG apply -f - <<EOF apiVersion: networking.global.gdc.goog/v1 kind: ProjectNetworkPolicy metadata: name: allow-pgbouncer namespace: ${PROJECT_ID} spec: ingress: - ports: - port: 6432 protocol: TCP policyType: Ingress subject: subjectType: UserWorkload EOF
データ レプリケーションを確認する
高可用性スタックが想定どおりに動作していることを確認するには、リーダーにサンプルデータを作成し、レプリカにそのデータが存在することを確認します。
サンプルデータを挿入する
inventory.ini でパスワードが指定されていない場合、自動化により、最初のデプロイ時に postgres ユーザーのランダムなパスワードが生成されます。任意の VM から取得できます。
export PG_PASSWORD=$(ansible master -i inventory.ini -m shell -a \
"grep -A10 'authentication:' /etc/patroni/patroni.yml | \
grep -A3 'superuser' | grep 'password:' | awk '{ print \$2 }'" -b | \
tail -n 1)
echo $PG_PASSWORD
PgBouncer ポート(6432)でロードバランサ VIP に接続し、サンプル テーブルを作成します。
PGPASSWORD="${PG_PASSWORD}" psql -h ${LB_IP} -p 6432 -U postgres -c "
CREATE TABLE employees (first_name TEXT, last_name TEXT);
INSERT INTO employees (first_name, last_name) VALUES ('John', 'Doe');
"
予想される出力:
INSERT 0 1
レプリケーションの状態を確認する
すべての VM で SELECT クエリを実行して、データがリーダーからすべてのレプリカに複製されていることを確認します。
ansible postgres_cluster -i inventory.ini -m shell -a "psql -U postgres -c \
'SELECT * FROM employees;'" -b
出力例:
postgres-vm-1 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
postgres-vm-2 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
postgres-vm-3 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
手動スイッチオーバーをテストする
手動スイッチオーバーを使用すると、リーダーロールを特定の候補 VM に正常に移動できます。これは通常、計画的なメンテナンス、ソフトウェアのアップグレード、またはゾーン間のリソース使用率のバランスを調整するために行われます。
現在のリーダーを特定する
VM の現在のロールとステータスを確認します。
ansible master -i inventory.ini -m shell -a "patronictl list" -b
出力例:
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 1 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
スイッチオーバーを実行する
現在のリーダーから別の VM への切り替えをトリガーします(この場合は、postgres-vm-1 から postgres-vm-2)。このコマンドは、--force を使用して手動確認プロンプトをスキップします。
ansible master -i inventory.ini -m shell -a "patronictl switchover \
--leader ${VM1_NAME} --candidate ${VM2_NAME} --force" -b
出力例:
Successfully switched over to "postgres-vm-2"
+ Cluster: postgres-cluster (7607933704953386478) -+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+---------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Replica | stopped | | unknown | | unknown | |
| postgres-vm-2 | 10.253.1.253 | Leader | running | 1 | | | | |
| postgres-vm-3 | 10.253.1.252 | Replica | running | 1 | 0/70000A0 | 0 | 0/70000A0 | 0 |
+---------------+--------------+---------+---------+----+-------------+-----+------------+-----+
ヘルスチェックのシフトを確認する
スイッチオーバー後、ヘルスチェックのステータスが新しいリーダーに移行したことを確認します。
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
古いリーダー(postgres-vm-1)は 503 を返し、新しいリーダー(postgres-vm-2)は 200 を返す必要があります。
自動フェイルオーバーをテストする
手動スイッチオーバーとは異なり、自動フェイルオーバーはリーダー VM が使用できなくなったときに発生します。このテストでは、Patroni が新しいリーダーを選出し、ロードバランサが手動操作なしでトラフィックをリダイレクトすることを確認します。postgres-vm-2 は、以前に実行された手動スイッチオーバー後の現在のリーダーであるとします。
現在のリーダーを特定する
VM の現在のロールとステータスを確認します。
ansible master -i inventory.ini -m shell -a "patronictl list" -b
出力例:
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Replica | streaming | 2 | 0/8000000 | 0 | 0/8000000 | 0 |
| postgres-vm-2 | 10.253.1.253 | Leader | running | 2 | | | | |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 2 | 0/8000000 | 0 | 0/8000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
VM 障害をシミュレートする
リーダー VM で patroni サービスを停止して、クラッシュまたはハード障害をシミュレートします。
ansible master -i inventory.ini -m shell -a "systemctl stop patroni" -b
新しいリーダー選出を観察する
10 ~ 20 秒待ってから、別の VM からステータスを確認して、新しいリーダーの昇格を確認します。
ansible replica -i inventory.ini -m shell -a "patronictl list" -b
出力例:
postgres-vm-3 | CHANGED | rc=0 >>
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 3 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | stopped | | unknown | | unknown | |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 3 | 0/90003F8 | 0 | 0/90003F8 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
他の VM(postgres-vm-1 または postgres-vm-3)のいずれかがリーダーになり、古いリーダー(postgres-vm-2)が停止としてマークされていることがわかります。
ヘルスチェックのシフトを確認する
ロードバランサのヘルスチェックで、新しく選出されたリーダーが正しく識別されることを確認します。
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
新しいリーダーは 200 OK を返すはずです。
障害が発生した VM を復元する
元の VM で patroni サービスを起動して、レプリカとしてスタックに再参加させ、欠落したデータをキャッチアップします。
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"systemctl start patroni" -b