使用 CloudNativePG 將 PostgreSQL 部署至 GKE

本指南說明如何使用 CloudNativePG 運算子,在 Google Kubernetes Engine (GKE) 上部署 PostgreSQL 叢集。

PostgreSQL 是開放原始碼的物件關聯式資料庫,經過數十年的積極開發,可確保用戶端效能穩定。這項服務提供多種功能,包括複製、時間點復原、安全性功能和擴充性。PostgreSQL 與主要作業系統相容,且完全符合 ACID (不可分割性、一致性、隔離性、耐用性) 標準。

本指南適用於有興趣在 GKE 上部署 Postgres 叢集的平台管理員、雲端架構師和營運專員。與使用 Cloud SQL 相比,在 GKE 中執行 Postgres 可為經驗豐富的資料庫管理員提供更多彈性和設定控制權。

優點

CloudNativePG 是由 EDB 根據 Apache 2 授權開發的開放原始碼運算子。為 PostgreSQL 部署作業帶來下列功能:

  • 以 Kubernetes 原生的宣告式方式管理及設定 PostgreSQL 叢集
  • 使用磁碟區快照Cloud Storage 管理備份
  • 傳輸中加密 TLS 連線、使用自有憑證授權單位,以及與 Certificate Manager 整合,自動核發及輪替 TLS 憑證
  • PostgreSQL 次要版本更新
  • 使用 Kubernetes API 伺服器維護 PostgreSQL 叢集狀態和容錯移轉,以提供高可用性,不需額外工具
  • 透過以 SQL 編寫的使用者定義指標,內建 Prometheus 匯出工具設定

設定環境

如要設定環境,請按照下列步驟操作:

  1. 設定環境變數:

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=postgres
    export REGION=us-central1
    

    PROJECT_ID 替換為您的 Google Cloud 專案 ID

  2. 複製 GitHub 存放區:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. 變更為工作目錄:

    cd kubernetes-engine-samples/databases/postgresql-cloudnativepg
    

建立叢集基礎架構

在本節中,您將執行 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 叢集
  • 啟用自動調度的節點集區 (每個可用區一到兩個節點,每個可用區至少一個節點)

輸出結果會與下列內容相似:

...
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 --location ${REGION}

部署 CloudNativePG 運算子

使用 Helm 資訊套件將 CloudNativePG 部署至 Kubernetes 叢集:

  1. 新增 CloudNativePG 運算子 Helm 資訊套件存放區:

    helm repo add cnpg https://cloudnative-pg.github.io/charts
    
  2. 使用 Helm 指令列工具部署 CloudNativePG 運算子:

    helm upgrade --install cnpg \
        --namespace cnpg-system \
        --create-namespace \
        cnpg/cloudnative-pg
    

    輸出結果會與下列內容相似:

    Release "cnpg" does not exist. Installing it now.
    NAME: cnpg
    LAST DEPLOYED: Fri Oct 13 13:52:36 2023
    NAMESPACE: cnpg-system
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    ...
    

部署 Postgres

下列資訊清單說明 CloudNativePG 運算子的自訂資源所定義的 PostgreSQL 叢集:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: gke-pg-cluster
spec:
  description: "Standard GKE PostgreSQL cluster"
  imageName: ghcr.io/cloudnative-pg/postgresql:16.2
  enableSuperuserAccess: true
  instances: 3
  startDelay: 300
  primaryUpdateStrategy: unsupervised
  postgresql:
    pg_hba:
      - host all all 10.48.0.0/20 md5
  bootstrap:
    initdb:
      database: app
  storage:
    storageClass: premium-rwo
    size: 2Gi
  resources:
    requests:
      memory: "1Gi"
      cpu: "1000m"
    limits:
      memory: "1Gi"
      cpu: "1000m"
  affinity:
    enablePodAntiAffinity: true
    tolerations:
    - key: cnpg.io/cluster
      effect: NoSchedule
      value: gke-pg-cluster
      operator: Equal
    additionalPodAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app.component
              operator: In
              values:
              - "pg-cluster"
          topologyKey: topology.kubernetes.io/zone
  monitoring:
    enablePodMonitor: true

這個資訊清單包含下列欄位:

  • spec.instances:叢集 Pod 數量
  • spec.primaryUpdateStrategy:滾動式更新策略:
    • Unsupervised:在副本節點更新後,自動更新主要叢集節點
    • Supervised:主要叢集節點必須手動切換
  • spec.postgresqlpostgres.conf 檔案參數覆寫,例如 pg-hba 規則、LDAP,以及同步複本必須符合的需求。
  • spec.storage:儲存空間相關設定,例如儲存空間類別、磁碟區大小和預先寫入記錄設定。
  • spec.bootstrap:叢集中建立的初始資料庫參數、使用者憑證和資料庫還原選項
  • spec.resources:叢集 Pod 的要求和限制
  • spec.affinity:叢集工作負載的相依性和反相依性規則

建立基本 Postgres 叢集

  1. 建立命名空間:

    kubectl create ns pg-ns
    
  2. 使用自訂資源建立 PostgreSQL 叢集:

    kubectl apply -n pg-ns -f manifests/01-basic-cluster/postgreSQL_cluster.yaml
    

    這個指令可能需要幾分鐘才能完成。

  3. 檢查叢集的狀態:

    kubectl get cluster -n pg-ns --watch
    

    請等待輸出內容顯示 Cluster in healthy state 狀態,再繼續下一個步驟。

    NAME             AGE     INSTANCES   READY   STATUS                     PRIMARY
    gke-pg-cluster   2m53s   3           3       Cluster in healthy state   gke-pg-cluster-1
    

檢查資源

確認 GKE 已為叢集建立資源:

kubectl get cluster,pod,svc,pvc,pdb,secret,cm -n pg-ns

輸出結果會與下列內容相似:

NAME                                        AGE   INSTANCES   READY   STATUS                     PRIMARY
cluster.postgresql.cnpg.io/gke-pg-cluster   32m   3           3       Cluster in healthy state   gke-pg-cluster-1

NAME                   READY   STATUS    RESTARTS   AGE
pod/gke-pg-cluster-1   1/1     Running   0          31m
pod/gke-pg-cluster-2   1/1     Running   0          30m
pod/gke-pg-cluster-3   1/1     Running   0          29m

NAME                        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
service/gke-pg-cluster-r    ClusterIP   10.52.11.24   <none>        5432/TCP   32m
service/gke-pg-cluster-ro   ClusterIP   10.52.9.233   <none>        5432/TCP   32m
service/gke-pg-cluster-rw   ClusterIP   10.52.1.135   <none>        5432/TCP   32m

NAME                                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/gke-pg-cluster-1   Bound    pvc-bbdd1cdd-bdd9-4e7c-8f8c-1a14a87e5329   2Gi        RWO            standard       32m
persistentvolumeclaim/gke-pg-cluster-2   Bound    pvc-e7a8b4df-6a3e-43ce-beb0-b54ec1d24011   2Gi        RWO            standard       31m
persistentvolumeclaim/gke-pg-cluster-3   Bound    pvc-dac7f931-6ac5-425f-ac61-0cfc55aae72f   2Gi        RWO            standard       30m

NAME                                                MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
poddisruptionbudget.policy/gke-pg-cluster           1               N/A               1                     32m
poddisruptionbudget.policy/gke-pg-cluster-primary   1               N/A               0                     32m

NAME                                TYPE                       DATA   AGE
secret/gke-pg-cluster-app           kubernetes.io/basic-auth   3      32m
secret/gke-pg-cluster-ca            Opaque                     2      32m
secret/gke-pg-cluster-replication   kubernetes.io/tls          2      32m
secret/gke-pg-cluster-server        kubernetes.io/tls          2      32m
secret/gke-pg-cluster-superuser     kubernetes.io/basic-auth   3      32m

NAME                                DATA   AGE
configmap/cnpg-default-monitoring   1      32m
configmap/kube-root-ca.crt          1      135m

運算子會建立下列資源:

  • 代表 PostgreSQL 叢集的叢集自訂資源,由運算子控管
  • 具有對應永久磁碟區的 PersistentVolumeClaim 資源
  • 密鑰,內含存取資料庫和 Postgres 節點間複寫作業的使用者憑證。
  • 三個資料庫端點服務:<name>-rw<name>-ro<name>-r,可連線至叢集。詳情請參閱 PostgreSQL 架構

向 Postgres 進行驗證

您可以連線至 PostgreSQL 資料庫,並透過運算子建立的不同服務端點檢查存取權。為此,您會使用額外的 Pod,其中包含 PostgreSQL 用戶端和已同步處理的應用程式使用者憑證,並以環境變數的形式掛接。

  1. 執行用戶端 Pod,與 Postgres 叢集互動:

    kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml
    
  2. pg-client Pod 上執行 exec 指令,並登入 gke-pg-cluster-rw 服務:

    kubectl wait --for=condition=Ready -n pg-ns pod/pg-client --timeout=300s
    kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
    
  3. 使用 gke-pg-cluster-rw 服務登入資料庫,建立具有讀寫權限的連線:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app
    

    終端機開頭會顯示資料庫名稱:

    app=>
    
  4. 建立資料表:

    CREATE TABLE travel_agency_clients (
    client VARCHAR ( 50 ) UNIQUE NOT NULL,
    address VARCHAR ( 50 ) UNIQUE NOT NULL,
    phone VARCHAR ( 50 ) UNIQUE NOT NULL);
    
  5. 將資料插入資料表:

    INSERT INTO travel_agency_clients(client, address, phone)
    VALUES ('Tom', 'Warsaw', '+55555')
    RETURNING *;
    
  6. 查看您建立的資料:

    SELECT * FROM travel_agency_clients ;
    

    輸出結果會與下列內容相似:

    client | address |  phone
    --------+---------+---------
    Tom    | Warsaw  | +55555
    (1 row)
    
  7. 登出目前的資料庫工作階段:

    exit
    
  8. 使用 gke-pg-cluster-ro 服務登入資料庫,確認唯讀存取權。這項服務允許查詢資料,但會限制任何寫入作業:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app
    
  9. 嘗試插入新資料:

    INSERT INTO travel_agency_clients(client, address, phone)
    VALUES ('John', 'Paris', '+55555')
    RETURNING *;
    

    輸出結果會與下列內容相似:

    ERROR:  cannot execute INSERT in a read-only transaction
    
  10. 嘗試讀取資料:

    SELECT * FROM travel_agency_clients ;
    

    輸出結果會與下列內容相似:

    client | address |  phone
    --------+---------+---------
    Tom    | Warsaw  | +55555
    (1 row)
    
  11. 登出目前的資料庫工作階段:

    exit
    
  12. 退出 Pod shell:

    exit
    

瞭解 Prometheus 如何收集 Postgres 叢集的指標

下圖顯示 Prometheus 指標的收集方式:

在圖表中,GKE 私人叢集包含:

  • Postgres Pod,會收集路徑 / 和通訊埠 9187 的指標
  • 以 Prometheus 為基礎的收集器,可處理來自 Postgres Pod 的指標
  • 將指標傳送至 Cloud Monitoring 的 PodMonitoring 資源

如要啟用從 Pod 收集指標的功能,請按照下列步驟操作:

  1. 建立 PodMonitoring 資源:

    kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
    
  2. 前往 Google Cloud 控制台的「指標探索器」頁面:

    前往 Metrics Explorer

    資訊主頁顯示的指標擷取率不是零。

  3. 在「選取指標」中,輸入「Prometheus Target」

  4. 在「使用中的指標類別」專區中,選取「Cnpg」

建立指標資訊主頁

如要以圖表呈現匯出的指標,請建立指標資訊主頁。

  1. 部署資訊主頁:

    gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
    
  2. 前往 Google Cloud 控制台的「資訊主頁」頁面。

    前往資訊主頁

  3. 選取「PostgresQL Prometheus Overview」(PostgresQL Prometheus 總覽) 資訊主頁。

    如要查看資訊主頁監控函式的方式,您可以重複使用「資料庫驗證」部分中的動作,並對資料庫套用讀取和寫入要求,然後在資訊主頁中查看收集到的指標視覺化資料。

  4. 連線至用戶端 Pod:

    kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
    
  5. 插入隨機資料:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);INSERT INTO test (randomdata) VALUES (generate_series(1, 1000));"
    
  6. 重新整理資訊主頁。圖表會更新為實際指標。

  7. 退出 Pod shell:

    exit