本指南介绍了如何使用 CloudNativePG 操作器在 Google Kubernetes Engine (GKE) 上部署 PostgreSQL 集群。
PostgreSQL 是一种开源对象关系型数据库,经过了数十年的积极开发,可确保稳定的客户端性能。它提供一系列功能,包括复制、时间点恢复、安全功能和扩展性。PostgreSQL 与主要操作系统兼容,并完全符合 ACID(原子性、一致性、隔离性、耐用性)标准。
本指南适用于有意在 GKE 上部署 Postgres 集群的平台管理员、云架构师和运营专家。在 GKE 中运行 Postgres(而不是使用 Cloud SQL)可以为经验丰富的数据库管理员提供更多灵活性和配置控制。
优势
CloudNativePG 是由 EBD 根据 Apache 2 许可开发的开源操作器。它为 PostgreSQL 部署引入了以下功能:
- 用于管理和配置 PostgreSQL 集群的声明式 Kubernetes 原生方法
- 使用卷快照或 Cloud Storage 进行备份管理
- 在传输过程中加密的 TLS 连接,能够使用自己的证书授权机构以及与 Certificate Manager 的集成来自动颁发和轮替 TLS 证书
- 次要 PostgreSQL 版本的滚动更新
- 使用 Kubernetes API 服务器维护 PostgreSQL 集群状态和故障切换以实现高可用性,无需其他工具
- 通过以 SQL 编写的用户定义的指标实现内置 Prometheus 导出器配置
目标
- 为 Postgres 规划和部署 GKE 基础架构
- 使用 Helm 部署和配置 CloudNativePG Postgres 操作器
- 部署 PostgreSQL 集群
- 配置 PostgreSQL 身份验证和可观测性
部署架构
PostgreSQL 具有各种部署选项,从独立数据库服务器到复制的高可用性集群不等。本教程重点介绍如何将高可用性集群部署到 GKE。
在此部署中,PostgreSQL 集群工作负载分布在区域 GKE 集群中的多个可用区中,确保高可用性和冗余。如需了解详情,请参阅区域级集群。
下图显示了在 GKE 集群中的多个节点和可用区上运行的 Postgres 集群:
默认设置包括一个主 PostgreSQL 服务器和两个备份服务器,如果主服务器发生故障,备份服务器可以进行接管,从而确保持续的数据库可用性。
CloudNativePG 操作器资源使用 GKE 集群的单独命名空间以实现更好的资源隔离,并采用推荐的每个 PostgreSQL 集群一个数据库的微服务方法。数据库及其对应的用户(应用用户)是在表示集群的 Kubernetes 自定义资源中定义的。
在讨论数据库时,存储是关键组成部分。存储必须高效运行,确保连续可用性,并保证数据一致性。出于这些原因,我们建议使用基于 SSD 磁盘的
premium-rwo
存储类别。在为 PostgreSQL 集群设置 Pod 时,CloudNativePG 操作器会根据需要自动创建PersistentVolumeClaims
。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
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.
-
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, Resource Manager APIs:
gcloud services enable compute.googleapis.com
iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com - Install the Google Cloud CLI.
-
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, Resource Manager APIs:
gcloud services enable compute.googleapis.com
iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com -
Grant roles to your user account. Run the following command once for each of the following IAM roles:
roles/compute.securityAdmin, roles/compute.viewer, roles/container.clusterAdmin, roles/container.admin, roles/iam.serviceAccountAdmin, roles/iam.serviceAccountUser
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
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID。克隆 GitHub 代码库:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
切换到工作目录:
cd kubernetes-engine-samples/databases/postgresql-cloudnativepg
创建集群基础架构
在本部分中,您将运行 Terraform 脚本以创建高可用性专用区域级 GKE 集群。
您可以使用 Standard 或 Autopilot 集群安装操作器。
标准
下图显示了部署在三个不同可用区中的专用区域级 Standard 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 节点的 VPC 网络和专用子网
- 用于通过 NAT 访问互联网的路由器
- 专用 GKE 集群(在
us-central1
区域中) - 启用了自动扩缩的节点池(每个可用区一个到两个节点,每个可用区最少一个节点)
输出类似于以下内容:
...
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 节点的 VPC 网络和专用子网
- 用于通过 NAT 访问互联网的路由器
- 专用 GKE 集群(在
us-central1
区域中) - 具有日志记录和监控权限的
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}
部署 CloudNativePG 运算符
使用 Helm 图表将 CloudNativePG 部署到 Kubernetes 集群:
添加 CloudNativePG 运算符 Helm 图表代码库:
helm repo add cnpg https://cloudnative-pg.github.io/charts
使用 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 集群:
此清单包含以下字段:
spec.instances
:集群 Pod 的数量spec.primaryUpdateStrategy
:滚动更新策略:Unsupervised
:在副本节点之后自主更新主集群节点Supervised
:主集群节点需要手动切换
spec.postgresql
:postgres.conf
文件参数替换值,例如 pg-hba 规则、LDAP 以及要满足的同步副本要求。spec.storage
:与存储相关的设置,例如存储类别、卷大小和预写式日志设置。spec.bootstrap
:在集群中创建的初始数据库的参数、用户凭据和数据库恢复选项spec.resources
:集群 Pod 的请求和限制spec.affinity
:集群工作负载的亲和性和反亲和性规则
创建基本 Postgres 集群
创建命名空间:
kubectl create ns pg-ns
使用自定义资源创建 PostgreSQL 集群:
kubectl apply -n pg-ns -f manifests/01-basic-cluster/postgreSQL_cluster.yaml
此命令可能需要几分钟才能完成。
检查集群状态:
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 资源
- 包含用户凭据的 Secret,用于访问数据库以及在 Postgres 节点之间进行复制。
- 三个数据库端点服务:
<name>-rw
、<name>-ro
和<name>-r
,用于连接到集群。如需了解详情,请参阅 PostgreSQL 架构。
向 Postgres 进行身份验证
您可以连接到 PostgreSQL 数据库,并通过运算符创建的不同服务端点检查访问权限。为此,请使用一个额外 Pod,其中包含一个 PostgreSQL 客户端并以环境变量的形式装载了同步应用用户凭据。
运行客户端 Pod 以与您的 Postgres 集群进行交互:
kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml
在
pg-client
Pod 上运行exec
命令并登录gke-pg-cluster-rw
Service:kubectl wait --for=condition=Ready -n pg-ns pod/pg-client --timeout=300s kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
使用
gke-pg-cluster-rw
Service 登录数据库以建立具有读写权限的连接:psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app
终端以您的数据库名称开头:
app=>
创建表:
CREATE TABLE travel_agency_clients ( client VARCHAR ( 50 ) UNIQUE NOT NULL, address VARCHAR ( 50 ) UNIQUE NOT NULL, phone VARCHAR ( 50 ) UNIQUE NOT NULL);
将数据插入到表中:
INSERT INTO travel_agency_clients(client, address, phone) VALUES ('Tom', 'Warsaw', '+55555') RETURNING *;
查看您创建的数据:
SELECT * FROM travel_agency_clients ;
输出类似于以下内容:
client | address | phone --------+---------+--------- Tom | Warsaw | +55555 (1 row)
退出当前数据库会话:
exit
使用
gke-pg-cluster-ro
Service 登录数据库以验证只读权限。此 Service 允许查询数据,但限制任何写入操作:psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app
尝试插入新数据:
INSERT INTO travel_agency_clients(client, address, phone) VALUES ('John', 'Paris', '+55555') RETURNING *;
输出类似于以下内容:
ERROR: cannot execute INSERT in a read-only transaction
尝试读取数据:
SELECT * FROM travel_agency_clients ;
输出类似于以下内容:
client | address | phone --------+---------+--------- Tom | Warsaw | +55555 (1 row)
退出当前数据库会话:
exit
退出 Pod shell:
exit
了解 Prometheus 如何收集 Postgres 集群的指标
下图展示了 Prometheus 指标收集的工作原理:
在该图中,GKE 专用集群包含:
- Postgres Pod,用于通过路径
/
和端口9187
收集指标 - 基于 Prometheus 的收集器,用于处理 Postgres Pod 中的指标
- 将指标发送到 Cloud Monitoring 的
PodMonitoring
资源
如需启用从 Pod 收集指标的功能,请执行以下步骤:
创建
PodMonitoring
资源:kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
在 Google Cloud 控制台中,转到 Metrics Explorer 页面:
信息中心显示非零指标提取率。
在选择一个指标中,输入 Prometheus Target(Prometheus 目标)。
在活跃指标类别部分中,选择 Cnpg。
创建指标信息中心
如需直观呈现导出的指标,请创建指标信息中心。
部署信息中心:
gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
在 Google Cloud 控制台中,转到信息中心页面。
选择 PostgresQL Prometheus Overview(PostgresQL Prometheus 概览)信息中心。
如需查看信息中心如何监控函数,您可以重复使用数据库身份验证部分中的操作,对数据库应用读取和写入请求,然后在信息中心内查看收集的指标可视化效果。
连接到客户端 Pod:
kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
插入随机数据:
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));"
刷新信息中心。图表将使用已实现的指标进行更新。
退出 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
后续步骤
- 探索有关 Google Cloud 的参考架构、图表和最佳做法。查看我们的 Cloud 架构中心。