このガイドでは、Zalando Postgres オペレーターを使用して Postgres クラスタを Google Kubernetes Engine(GKE)にデプロイする方法について説明します。
PostgreSQL は、オープンソースの優れたオブジェクト リレーショナル データベース システムであり、数十年にわたって積極的に開発され、信頼性、機能の堅牢性、パフォーマンスで高い評価を得ています。
このガイドは、Cloud SQL for PostgreSQL の代わりに、GKE でデータベース アプリケーションとして PostgreSQL を実行することに関心があるプラットフォーム管理者、クラウド アーキテクト、運用担当者を対象としています。
環境の設定
環境の設定手順は次のとおりです。
環境変数を設定します。
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1
PROJECT_ID
は、実際の Google Cloudプロジェクト ID に置き換えます。GitHub リポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
作業ディレクトリを変更します。
cd kubernetes-engine-samples/databases/postgres-zalando
クラスタ インフラストラクチャを作成する
このセクションでは、Terraform スクリプトを実行して、限定公開の高可用性リージョン GKE クラスタを作成します。
オペレーターは、Standard または Autopilot クラスタを使用してインストールできます。
Standard
次の図は、3 つの異なるゾーンにデプロイされた限定公開のリージョン GKE Standard クラスタを示しています。
このインフラストラクチャをデプロイします。
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
プロンプトが表示されたら、「yes
」と入力します。このコマンドが完了し、クラスタが準備完了ステータスになるまでに数分かかることがあります。
Terraform が次のリソースを作成します。
- Kubernetes ノード用の VPC ネットワークとプライベート サブネット
- NAT 経由でインターネットにアクセスするためのルーター
us-central1
リージョンの限定公開 GKE クラスタ- 自動スケーリングが有効になっているノードプール(ゾーンあたり 1~2 ノード、最小ゾーンあたり 1 ノード)
- ロギングとモニタリングの権限を持つ
ServiceAccount
- Backup for GKE(障害復旧用)
- Google Cloud Managed Service for Prometheus(クラスタ モニタリング用)
出力は次のようになります。
...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...
Autopilot
次の図は、限定公開のリージョン GKE Autopilot クラスタを示しています。
インフラストラクチャをデプロイします。
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
プロンプトが表示されたら、「yes
」と入力します。このコマンドが完了し、クラスタが準備完了ステータスになるまでに数分かかることがあります。
Terraform が次のリソースを作成します。
- Kubernetes ノード用の VPC ネットワークとプライベート サブネット
- NAT 経由でインターネットにアクセスするためのルーター
us-central1
リージョンの限定公開 GKE クラスタ- ロギングとモニタリングの権限を持つ
ServiceAccount
- Google Cloud Managed Service for Prometheus(クラスタ モニタリング用)
出力は次のようになります。
...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...
クラスタに接続する
クラスタと通信を行うように kubectl
を構成します。
gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}
Zalando オペレーターをクラスタにデプロイする
Helm チャートを使用して、Zalando オペレーターを Kubernetes クラスタにデプロイします。
Zalando オペレーターの Helm チャート リポジトリを追加します。
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
Zalando オペレーターと Postgres クラスタの名前空間を作成します。
kubectl create ns postgres kubectl create ns zalando
Helm コマンドライン ツールを使用して Zalando オペレーターをデプロイします。
helm install postgres-operator postgres-operator-charts/postgres-operator -n zalando \ --set configKubernetes.enable_pod_antiaffinity=true \ --set configKubernetes.pod_antiaffinity_preferred_during_scheduling=true \ --set configKubernetes.pod_antiaffinity_topology_key="topology.kubernetes.io/zone" \ --set configKubernetes.spilo_fsgroup="103"
Postgres クラスタを表すカスタム リソースで
podAntiAffinity
設定を直接構成することはできません。代わりに、オペレーターの設定ですべての Postgres クラスタのpodAntiAffinity
設定をグローバルに設定します。Helm を使用して Zalando オペレーターのデプロイ ステータスを確認します。
helm ls -n zalando
出力は次のようになります。
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION postgres-operator zalando 1 2023-10-13 16:04:13.945614 +0200 CEST deployed postgres-operator-1.10.1 1.10.1
Postgres をデプロイする
Postgres クラスタ インスタンスの基本構成には、次のコンポーネントが含まれています。
- Postgres の 3 つのレプリカ: 1 つのリーダー レプリカと 2 つのスタンバイ レプリカ。
- 1 つの CPU リクエストと 2 つの CPU 上限に対する CPU リソースの割り当て(4 GB のメモリ リクエストと上限)。
- toleration、
nodeAffinities
、topologySpreadConstraints
は各ワークロードに構成され、それぞれのノードプールと異なるアベイラビリティ ゾーンを利用して Kubernetes ノード間で適切に分散されます。
この構成は、本番環境に対応した Postgres クラスタの作成に必要な最小限の設定を表しています。
次のマニフェストは、Postgres クラスタを記述しています。
このマニフェストには次のフィールドがあります。
spec.teamId
: 選択したクラスタ オブジェクトの接頭辞spec.numberOfInstances
: クラスタの合計インスタンス数spec.users
: 権限を持つユーザーリストspec.databases
:dbname: ownername
形式のデータベース リストspec.postgresql
: postgres パラメータspec.volume
: Persistent Disk のパラメータspec.tolerations
: クラスタ Pod をpool-postgres
ノードにスケジュールできるようにする toleration Pod テンプレートspec.nodeAffinity
: クラスタ Pod がpool-postgres
ノードでスケジューリングされるよう GKE に指示するnodeAffinity
Pod テンプレート。spec.resources
: クラスタ Pod のリクエストと上限spec.sidecars
:postgres-exporter
を含むサイドカー コンテナのリスト
詳細については、Postgres ドキュメントのクラスタ マニフェスト リファレンスをご覧ください。
基本的な Postgres クラスタを作成する
基本構成を使用して新しい Postgres クラスタを作成します。
kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml
このコマンドは、次の設定内容で Zalando オペレーターの PostgreSQL カスタム リソースを作成します。
- CPU とメモリのリクエストと上限
- プロビジョニングされた Pod レプリカを GKE ノードに分散するための taint とアフィニティ。
- データベース
- データベース所有者権限を持つ 2 人のユーザー
- 権限のないユーザー
GKE が必要なワークロードを開始するまで待ちます。
kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgres
このコマンドが完了するまで数分かかる場合があります。
GKE によって Postgres ワークロードが作成されたことを確認します。
kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgres
出力は次のようになります。
NAME READY STATUS RESTARTS AGE pod/my-cluster-0 1/1 Running 0 6m41s pod/my-cluster-1 1/1 Running 0 5m56s pod/my-cluster-2 1/1 Running 0 5m16s pod/postgres-operator-db9667d4d-rgcs8 1/1 Running 0 12m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-cluster ClusterIP 10.52.12.109 <none> 5432/TCP 6m43s service/my-cluster-config ClusterIP None <none> <none> 5m55s service/my-cluster-repl ClusterIP 10.52.6.152 <none> 5432/TCP 6m43s service/postgres-operator ClusterIP 10.52.8.176 <none> 8080/TCP 12m NAME READY AGE statefulset.apps/my-cluster 3/3 6m43s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/postgres-operator 1/1 1 1 12m NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE poddisruptionbudget.policy/postgres-my-cluster-pdb 1 N/A 0 6m44s NAME TYPE DATA AGE secret/my-user.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m45s secret/postgres.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/sh.helm.release.v1.postgres-operator.v1 helm.sh/release.v1 1 12m secret/standby.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/zalando.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s
オペレーターが次のリソースを作成します。
- Postgres の 3 つの Pod レプリカを制御する Postgres StatefulSet
- 少なくとも 1 つのレプリカを使用できる状態にする
PodDisruptionBudgets
- リーダー レプリカのみをターゲットとする
my-cluster
Service - 受信接続と Postgres レプリカ間のレプリケーション用に Postgres ポートを公開する
my-cluster-repl
Service - 実行中の Postgres Pod レプリカのリストを取得するための
my-cluster-config
ヘッドレス Service - データベースへのアクセスと Postgres ノード間のレプリケーションのためのユーザー認証情報を含むシークレット
Postgres に対する認証を行う
Postgres ユーザーを作成し、データベース権限を割り当てることができます。たとえば、次のマニフェストは、ユーザーとロールを割り当てるカスタム リソースを記述しています。
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
users:
mydatabaseowner:
- superuser
- createdb
myuser: []
databases:
mydatabase: mydatabaseowner
このマニフェストの内容:
mydatabaseowner
ユーザーには、SUPERUSER
とCREATEDB
のロールが付与されており、完全な管理者権限(Postgres 構成の管理、新しいデータベース、テーブル、ユーザーの作成)が含まれます。このユーザーをクライアントと共有しないでください。たとえば、Cloud SQL では、お客様にSUPERUSER
ロールを持つユーザーへのアクセス権を付与することは許可されません。myuser
ユーザーにはロールが割り当てられていません。これは、SUPERUSER
を使用して最小権限を付与されたユーザーを作成するベスト プラクティスに従っています。mydatabaseowner
からmyuser
に詳細な権限が付与されます。セキュリティを維持するため、myuser
認証情報はクライアント アプリケーションとのみ共有する必要があります。
パスワードを保存する
scram-sha-256
のパスワードを保存するためのおすすめの方法を使用してください。たとえば、次のマニフェストは、postgresql.parameters.password_encryption
フィールドを使用して scram-sha-256
暗号化を指定するカスタム リソースを記述しています。
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
postgresql:
parameters:
password_encryption: scram-sha-256
ユーザー認証情報をローテーションする
Zalando を使用して、Kubernetes Secret に保存されているユーザー認証情報をローテーションできます。たとえば、次のマニフェストは、usersWithSecretRotation
フィールドを使用してユーザー認証情報のローテーションを定義するカスタム リソースを記述しています。
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
usersWithSecretRotation:
- myuser
- myanotheruser
- ...
認証の例: Postgres に接続する
このセクションでは、サンプルの Postgres クライアントをデプロイし、Kubernetes Secret のパスワードを使用してデータベースに接続する方法について説明します。
クライアント Pod を実行して Postgres クラスタとやり取りします。
kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml
myuser
ユーザーとmydatabaseowner
ユーザーの認証情報が関連する Secret から取得され、環境変数として Pod にマウントされます。準備ができたら、Pod に接続します。
kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres kubectl exec -it postgres-client -n postgres -- /bin/bash
Postgres に接続し、
myuser
認証情報を使用して新しいテーブルを作成してみます。PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"
コマンドは、次のようなエラーにより失敗します。
ERROR: permission denied for schema public LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...
デフォルトで権限が割り当てられていないユーザーが行うことができるのは、Postgres へのログインとデータベースの一覧取得のみであるため、このコマンドは失敗します。
mydatabaseowner
認証情報を使用してテーブルを作成し、テーブルに対するすべての権限をmyuser
に付与します。PGPASSWORD=$OWNERPASSWORD psql \ -h my-cluster \ -U $OWNERUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);GRANT ALL ON test TO myuser;GRANT ALL ON SEQUENCE test_id_seq TO myuser;"
出力は次のようになります。
CREATE TABLE GRANT GRANT
myuser
認証情報を使用してランダムなデータをテーブルに挿入します。for i in {1..10}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" done
出力は次のようになります。
INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1
挿入した値を取得します。
PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "SELECT * FROM test;"
出力は次のようになります。
id | randomdata ----+--------------- 1 | jup9HYsAjwtW4 2 | 9rLAyBlcpLgNT 3 | wcXSqxb5Yz75g 4 | KoDRSrx3muD6T 5 | b9atC7RPai7En 6 | 20d7kC8E6Vt1V 7 | GmgNxaWbkevGq 8 | BkTwFWH6hWC7r 9 | nkLXHclkaqkqy 10 | HEebZ9Lp71Nm3 (10 rows)
Pod のシェルを終了します。
exit
Prometheus が Postgres クラスタの指標を収集する仕組みを理解する
次の図は、Prometheus 指標の収集の仕組みを示しています。
この図では、GKE のプライベート クラスタに次のものが存在します。
- パス
/
とポート9187
の指標を収集する Postgres Pod - Postgres Pod の指標を処理する Prometheus ベースのコレクタ
- Cloud Monitoring に指標を送信する
PodMonitoring
リソース
Google Cloud Managed Service for Prometheus は、Prometheus 形式での指標の収集をサポートしています。Cloud Monitoring は、Postgres 指標に対して統合ダッシュボードを使用します。
Zalando は、postgres_exporter コンポーネントをサイドカー コンテナとして使用し、Prometheus 形式でクラスタ指標を公開します。
labelSelector
で指標を収集するPodMonitoring
リソースを作成します。kubectl apply -n postgres -f manifests/03-prometheus-metrics/pod-monitoring.yaml
Google Cloud コンソールで、GKE クラスタのダッシュボード ページに移動します。
ダッシュボードにゼロ以外の指標の取り込み率が表示されます。
Google Cloud コンソールで [ダッシュボード] ページに移動します。
PostgreSQL Prometheus Overview ダッシュボードを開きます。ダッシュボードには取得された行数が表示されます。ダッシュボードの自動プロビジョニングには数分かかる場合があります。
クライアント Pod に接続します。
kubectl exec -it postgres-client -n postgres -- /bin/bash
ランダムなデータを挿入します。
for i in {1..100}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" done
ページを更新すると、[Rows] グラフと [Blocks] グラフが更新され、実際のデータベースの状態が表示されます。
Pod のシェルを終了します。
exit