本指南說明如何使用 Zalando Postgres 運算子,將 Postgres 叢集部署至 Google Kubernetes Engine (GKE)。
PostgreSQL 是功能強大的開放原始碼物件關聯式資料庫系統,經過數十年的積極開發,在可靠性、功能強大和效能方面享有盛名。
本指南適用於平台管理員、雲端架構師和營運專員。這些人員有興趣在 GKE 上執行 PostgreSQL 做為資料庫應用程式,而不是使用 PostgreSQL 適用的 Cloud SQL。
目標
- 規劃及部署 Postgres 適用的 GKE 基礎架構
- 部署及設定 Zalando Postgres 運算子
- 使用運算子設定 Postgres,確保可用性、安全性、可觀測性和效能
優點
Zalando 提供以下優點:
- 以 Kubernetes 原生方式宣告式地管理及設定 PostgreSQL 叢集
- Patroni 提供的高可用性
- 支援使用 Cloud Storage 值區管理備份
- Postgres 叢集變更的滾動式更新,包括快速次要版本更新
- 宣告式 使用者 管理,可使用自訂資源產生及輪替密碼
- 支援 TLS、憑證輪替和連線集區
- 叢集複製和資料複製
部署架構
在本教學課程中,您將使用 Zalando Postgres 運算子,在 GKE 中部署及設定高可用性 Postgres 叢集。叢集有一個主備用資源,以及兩個由 Patroni 管理的待命 (唯讀) 備用資源。Patroni 是由 Zalando 維護的開放原始碼解決方案,可為 Postgres 提供高可用性和自動容錯移轉功能。如果主要備用資源發生故障,系統會自動將其中一個待命備用資源升級為主要備用資源。
您也會為 Postgres 部署高可用性區域 GKE 叢集,並在多個可用區中分散多個 Kubernetes 節點。這項設定有助於確保容錯能力、擴充性和地理位置備援。這項服務可進行輪流更新和維護,同時提供運作時間和可用性的服務水準協議。詳情請參閱區域叢集。
下圖顯示在 GKE 叢集的多個節點和區域中執行的 Postgres 叢集:
在圖表中,Postgres StatefulSet
部署在三個不同可用區的三個節點上。您可以透過在postgresql
自訂資源規格中設定必要的 Pod 相依性和反相依性規則,控管 GKE 在節點中的部署方式。如果一個區域失效,使用建議設定的 GKE 會在叢集中的其他可用節點上重新排定 Pod。如要保存資料,請使用 SSD 磁碟 (premium-rwo
StorageClass),這類磁碟建議用於高負載資料庫,因為延遲時間短且 IOPS 高。
費用
在本文件中,您會使用 Google Cloud的下列計費元件:
如要根據預測用量估算費用,請使用 Pricing Calculator。
完成本文所述工作後,您可以刪除已建立的資源,避免繼續計費。詳情請參閱清除所用資源一節。
事前準備
Cloud Shell 已預先安裝本教學課程所需的軟體,包括 kubectl
、gcloud CLI、Helm 和 Terraform。如果您未使用 Cloud Shell,則必須安裝 gcloud CLI。
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
Install the Google Cloud CLI.
-
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
Create or select a Google Cloud project.
-
Create a Google Cloud project:
gcloud projects create PROJECT_ID
Replace
PROJECT_ID
with a name for the Google Cloud project you are creating. -
Select the Google Cloud project that you created:
gcloud config set project PROJECT_ID
Replace
PROJECT_ID
with your Google Cloud project name.
-
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine, IAM, GKE, Backup for GKE APIs:
gcloud services enable compute.googleapis.com
iam.googleapis.com container.googleapis.com gkebackup.googleapis.com -
Install the Google Cloud CLI.
-
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
Create or select a Google Cloud project.
-
Create a Google Cloud project:
gcloud projects create PROJECT_ID
Replace
PROJECT_ID
with a name for the Google Cloud project you are creating. -
Select the Google Cloud project that you created:
gcloud config set project PROJECT_ID
Replace
PROJECT_ID
with your Google Cloud project name.
-
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine, IAM, GKE, Backup for GKE APIs:
gcloud services enable compute.googleapis.com
iam.googleapis.com container.googleapis.com gkebackup.googleapis.com -
Grant roles to your user account. Run the following command once for each of the following IAM roles:
roles/storage.objectViewer, roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin, roles/gkebackup.admin, roles/monitoring.viewer
gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
- Replace
PROJECT_ID
with your project ID. -
Replace
USER_IDENTIFIER
with the identifier for your user account. For example,user:myemail@example.com
. - Replace
ROLE
with each individual role.
- Replace
設定環境
如要設定環境,請按照下列步驟操作
設定環境變數:
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1
複製 GitHub 存放區:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
變更為工作目錄:
cd kubernetes-engine-samples/databases/postgres-zalando
建立叢集基礎架構
在本節中,您將執行 Terraform 指令碼,建立高可用性的私人地區 GKE 叢集。
您可以使用標準或 Autopilot叢集安裝運算子。
標準
下圖顯示部署在三個不同可用區的私有區域標準 GKE 叢集:
部署下列基礎架構:
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 節點的虛擬私有雲網路和私有子網路
- 透過 NAT 存取網際網路的路由器
us-central1
地區中的私人 GKE 叢集- 啟用自動調度資源的節點集區 (每個區域一到兩個節點,每個區域至少一個節點)
- 具備記錄與監控權限的
ServiceAccount
- 使用 Backup for GKE 進行災難復原
- 使用 Google Cloud Managed Service for Prometheus 監控叢集
輸出結果會與下列內容相似:
...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...
Autopilot
下圖顯示私人區域 Autopilot GKE 叢集:
部署基礎架構:
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 節點的虛擬私有雲網路和私有子網路
- 透過 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 --region ${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 副本:一個主要副本和兩個待機副本。
- 一個 CPU 要求和兩個 CPU 限制的 CPU 資源分配,以及 4 GB 記憶體要求和限制。
- 為每個工作負載設定容許條件、
nodeAffinities
和topologySpreadConstraints
,確保工作負載在 Kubernetes 節點之間適當分配,並利用各自的節點集區和不同可用區。
這項設定代表建立可供正式環境使用的 Postgres 叢集所需的基本設定。
下列資訊清單說明 Postgres 叢集:
這個資訊清單包含下列欄位:
spec.teamId
:您選擇的叢集物件前置字串spec.numberOfInstances
:叢集的執行個體總數spec.users
:具有權限的使用者清單spec.databases
:資料庫清單,格式為dbname: ownername
spec.postgresql
:postgres 參數spec.volume
:永久磁碟參數spec.tolerations
:容許條件 Pod 範本,可讓叢集 Pod 排定在pool-postgres
節點上spec.nodeAffinity
:nodeAffinity
Pod 範本,可告知 GKE 叢集 Pod 偏好排程至pool-postgres
節點。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 和記憶體要求與限制
- taint 和相依性,可將佈建的 Pod 副本分散到各個 GKE 節點。
- 資料庫
- 兩位具備資料庫擁有者權限的使用者
- 沒有權限的使用者
等待 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 StatefulSet,可控制三個 Postgres Pod 副本
PodDisruptionBudgets
,確保至少有一個可用的副本my-cluster
服務,僅以領導者副本為目標my-cluster-repl
服務,用於公開 Postgres 連接埠,以供連入連線和 Postgres 副本之間的複製作業使用my-cluster-config
無標題服務,用於取得正在執行的 Postgres Pod 副本清單- 密鑰,內含存取資料庫的使用者憑證,以及 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 密鑰中的密碼連線至資料庫。
執行用戶端 Pod,與 Postgres 叢集互動:
kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml
系統會從相關的 Secret 取得
myuser
和mydatabaseowner
使用者的憑證,並以環境變數的形式掛接至 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 shell:
exit
瞭解 Prometheus 如何收集 Postgres 叢集的指標
下圖顯示 Prometheus 指標的收集方式:
在圖表中,GKE 私人叢集包含:
- Postgres Pod,會收集路徑
/
和通訊埠9187
的指標 - 以 Prometheus 為基礎的收集器,可處理來自 Postgres Pod 的指標
- 將指標傳送至 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 Clusters Dashboard」(GKE 叢集資訊主頁) 頁面。
資訊主頁顯示的指標擷取率不是零。
前往 Google Cloud 控制台的「資訊主頁」頁面。
開啟 PostgreSQL Prometheus 總覽資訊主頁。資訊主頁會顯示擷取的資料列數。自動佈建資訊主頁可能需要幾分鐘的時間。
連線至用戶端 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
重新整理頁面。「資料列」和「區塊」圖表會更新,顯示實際的資料庫狀態。
退出 Pod shell:
exit
清除所用資源
刪除專案
Delete a Google Cloud project:
gcloud projects delete PROJECT_ID
刪除個別資源
設定環境變數。
export PROJECT_ID=${PROJECT_ID} export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1
執行
terraform destroy
指令:export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token) terraform -chdir=terraform/FOLDER destroy \ -var project_id=${PROJECT_ID} \ -var region=${REGION} \ -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
將
FOLDER
替換為gke-autopilot
或gke-standard
。系統顯示提示訊息時,請輸入
yes
。找出所有未連接的磁碟:
export disk_list=$(gcloud compute disks list --filter="-users:* AND labels.name=${KUBERNETES_CLUSTER_PREFIX}-cluster" --format "value[separator=|](name,zone)")
刪除磁碟:
for i in $disk_list; do disk_name=$(echo $i| cut -d'|' -f1) disk_zone=$(echo $i| cut -d'|' -f2|sed 's|.*/||') echo "Deleting $disk_name" gcloud compute disks delete $disk_name --zone $disk_zone --quiet done
刪除 GitHub 存放區:
rm -r ~/kubernetes-engine-samples/
後續步驟
- 探索 Google Cloud 的參考架構、圖表和最佳做法。 歡迎瀏覽我們的雲端架構中心。