你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
在本文中,你将在 AKS 上部署高度可用的 PostgreSQL 数据库。
- 如果仍需为此部署创建所需的基础结构,请按照创建基础结构中的步骤在 AKS 上部署高度可用的 PostgreSQL 数据库 进行设置,然后返回到本文。
Important
AKS 文档和示例中都提到了开源软件。 AKS 服务级别协议、有限保修和 Azure 支持不涵盖你部署的软件。 将开源技术与 AKS 一起使用时,请查阅相应社区和项目维护者提供的支持选项来制定计划。
Microsoft 将负责生成我们在 AKS 上部署的开源包。 该责任包括对生成、扫描、签名、验证和修补过程拥有完整的所有权,以及对容器映像中的二进制文件的控制。 如需了解详细信息,请参阅 AKS 漏洞管理和 AKS 支持范围。
为启动应用用户创建机密
- 使用
kubectl create secret命令为启动应用用户生成一个机密,通过交互式登录来验证 PostgreSQL 部署。
Important
Microsoft 建议使用最安全的可用身份验证流。 此过程中所述的身份验证流要求在应用程序中高度信任,并具有在其他流中不存在的风险。 请仅在无法使用其他更安全的流(例如托管标识)时才使用此流。
PG_DATABASE_APPUSER_SECRET=$(echo -n | openssl rand -base64 16)
kubectl create secret generic db-user-pass \
--from-literal=username=app \
--from-literal=password="${PG_DATABASE_APPUSER_SECRET}" \
--namespace $PG_NAMESPACE \
--context $AKS_PRIMARY_CLUSTER_NAME
使用
kubectl get命令验证是否已成功创建机密。kubectl get secret db-user-pass --namespace $PG_NAMESPACE --context $AKS_PRIMARY_CLUSTER_NAME
设置用于 PostgreSQL 群集的环境变量
部署 ConfigMap 以使用以下
kubectl apply命令配置 CNPG 操作器。 这些值取代了不再需要的旧版ENABLE_AZURE_PVC_UPDATES开关,有助于错开升级并加快副本重新连接。 将此配置滚动到生产环境之前,请验证你依赖的任何现有DRAIN_TAINTS设置是否与 Azure 环境保持兼容。cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME -n $PG_NAMESPACE -f - apiVersion: v1 kind: ConfigMap metadata: name: cnpg-controller-manager-config data: CLUSTERS_ROLLOUT_DELAY: '120' STANDBY_TCP_USER_TIMEOUT: '10' EOF
安装 Prometheus PodMonitor
Prometheus 使用 CNPG GitHub 示例存储库中存储的记录规则来擦除 CNPG。 由于操作员管理的 PodMonitor 已弃用,因此请自行创建和管理 PodMonitor 资源,以便你可以将其定制到监视堆栈。
使用
helm repo add命令添加 Prometheus 社区 Helm 存储库。helm repo add prometheus-community \ https://prometheus-community.github.io/helm-charts升级 Prometheus 社区 Helm 存储库,并使用带有
helm upgrade标志的--install命令在主群集上安装它。helm upgrade --install \ --namespace $PG_NAMESPACE \ -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/docs/src/samples/monitoring/kube-stack-config.yaml \ prometheus-community \ prometheus-community/kube-prometheus-stack \ --kube-context=$AKS_PRIMARY_CLUSTER_NAME为群集创建 PodMonitor。 CNPG 团队正在弃用运营商托管的 PodMonitor,因此现在需要由你直接进行管理:
cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -f - apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: $PG_PRIMARY_CLUSTER_NAME namespace: ${PG_NAMESPACE} labels: cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME} spec: selector: matchLabels: cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME} podMetricsEndpoints: - port: metrics EOF
创建联合凭据
在本部分,你将创建 PostgreSQL 备份的联合标识凭据,以允许 CNPG 使用 AKS 工作负载标识向存储帐户目标进行身份验证来进行备份。 CNPG 操作器会创建一个与 CNPG 群集部署清单中所用群集同名的 Kubernetes 服务帐户。
使用
az aks show命令获取群集 OIDC 颁发者 URL。export AKS_PRIMARY_CLUSTER_OIDC_ISSUER="$(az aks show \ --name $AKS_PRIMARY_CLUSTER_NAME \ --resource-group $RESOURCE_GROUP_NAME \ --query "oidcIssuerProfile.issuerUrl" \ --output tsv)"使用
az identity federated-credential create命令创建联合标识凭据。az identity federated-credential create \ --name $AKS_PRIMARY_CLUSTER_FED_CREDENTIAL_NAME \ --identity-name $AKS_UAMI_CLUSTER_IDENTITY_NAME \ --resource-group $RESOURCE_GROUP_NAME \ --issuer "${AKS_PRIMARY_CLUSTER_OIDC_ISSUER}" \ --subject system:serviceaccount:"${PG_NAMESPACE}":"${PG_PRIMARY_CLUSTER_NAME}" \ --audience api://AzureADTokenExchange
部署高度可用的 PostgreSQL 群集
在本部分,你将使用 CNPG 群集自定义资源定义 (CRD) 部署高度可用的 PostgreSQL 群集。
群集 CRD 参数
下表概述了在群集 CRD 的 YAML 部署清单中设置的关键属性:
| Property | Definition |
|---|---|
imageName |
指向 CloudNativePG 操作数容器映像。 按照本指南中所示,与核心备份集成一起使用 ghcr.io/cloudnative-pg/postgresql:18-system-trixie,或者在采用 Barman Cloud 插件时切换到 18-standard-trixie。 |
inheritedMetadata |
特定于 CNPG 运算符。 CNPG 运算符将元数据应用于与群集相关的每个对象。 |
annotations |
包含公开群集终结点时所需的 DNS 标签,并为基于仲裁的故障转移启用 alpha.cnpg.io/failoverQuorum。 |
labels: azure.workload.identity/use: "true" |
指示 AKS 应将工作负载标识依赖项注入托管 PostgreSQL 群集实例的 Pod。 |
topologySpreadConstraints |
需要不同的区域和具有 "workload=postgres" 标签的不同节点。 |
resources |
配置服务质量 (QoS) 类别为 Guaranteed。 在生产环境中,这些值是最大限度使用基础节点 VM 的关键,根据所使用的 Azure VM SKU 而有所不同。 |
probes |
替换旧 startDelay 配置。 流媒体启动和就绪探测有助于确保副本在对外提供流量服务之前正常运行。 |
smartShutdownTimeout |
允许长时间运行的事务在更新期间正常完成,而不是采用强制停止延迟。 |
bootstrap |
特定于 CNPG 运算符。 使用空的应用数据库进行初始化。 |
storage |
定义数据库的 PersistentVolume 设置。 使用 Azure 托管磁盘时,简化的语法会将数据和 WAL 保留在相同的 64 GiB 卷上,从而在托管磁盘上提供更好的吞吐量层。 如果需要单独的 WAL 卷,请进行调整。 |
postgresql.synchronous |
minSyncReplicas
/
maxSyncReplicas已被较新的架构替换,并允许您指定同步复制行为。 |
postgresql.parameters |
特定于 CNPG 运算符。 映射 postgresql.conf、pg_hba.conf 和 pg_ident.conf 的设置。 该示例重点展示了适用于 AKS 工作负载标识方案的可观测性和 WAL 保留默认设置,但这些设置应根据具体工作负载进行调整。 |
serviceAccountTemplate |
包含生成服务帐户所需的模板,并将 AKS 联合标识凭据映射到 UAMI,从而能够从托管 PostgreSQL 实例的 Pod 进行 AKS 工作负载标识身份验证来访问外部 Azure 资源。 |
barmanObjectStore |
特定于 CNPG 运算符。 使用 AKS 工作负载标识配置 barman-cloud 工具套件,以便向 Azure Blob 存储对象存储进行身份验证。 |
若要进一步隔离 PostgreSQL 工作负荷,可以将污点(例如 node-role.kubernetes.io/postgres=:NoSchedule)添加到数据平面节点,并将示例 nodeSelector/tolerations 替换为 CloudNativePG 建议的值。 如果采用此方法,请相应地标记节点,并确认 AKS 自动缩放程序策略与拓扑保持一致。
PostgreSQL 性能参数
PostgreSQL 性能在很大程度上取决于群集的基础资源和工作负荷。 下表提供了标准 D4s v3 节点上运行的三节点群集(16-GiB 内存)的基线指导。 将这些值视为起点,并在了解工作负荷配置文件后对其进行调整:
| Property | 建议的值 | Definition |
|---|---|---|
wal_compression |
lz4 | 使用指定方法压缩 WAL 文件中的整页写入 |
max_wal_size |
6 GB | 设置触发检查点的 WAL 大小 |
checkpoint_timeout |
15 分钟 | 在自动 WAL 检查点之间设置最长时间 |
checkpoint_completion_target |
0.9 | 在检查点窗口期间平衡检查点工作负载 |
checkpoint_flush_after |
2 MB | 在将以前执行的写入刷新到磁盘之前所要达到的页数 |
wal_writer_flush_after |
2 MB | WAL 写入器写出的 WAL 数量,达到该数量将触发刷新 |
min_wal_size |
2 GB | 设置要将 WAL 收缩到的最小大小 |
max_slot_wal_keep_size |
10 GB | WAL 剩余用于服务复制槽的上限 |
shared_buffers |
4 GB | 设置服务器使用的共享内存缓冲区数(本示例中节点内存的 25%) |
effective_cache_size |
12 GB | 设置规划器关于数据缓存总大小的假设 |
work_mem |
1/256 的节点内存 | 设置要用于查询工作区的最大内存 |
maintenance_work_mem |
6.25% 的节点内存 | 设置用于维护操作的最大内存 |
autovacuum_vacuum_cost_limit |
2400 | autovacuum 在短暂睡眠之前可用的清空成本量 |
random_page_cost |
1.1 | 设置规划器对不按顺序提取磁盘页的成本估计值 |
effective_io_concurrency |
64 | 设置磁盘子系统能够有效处理的同时请求数 |
maintenance_io_concurrency |
64 | 用于维护工作的“effective_io_concurrency”变体 |
部署 PostgreSQL
使用
kubectl apply命令通过群集 CRD 部署 PostgreSQL 群集。cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME -n $PG_NAMESPACE -v 9 -f - apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: $PG_PRIMARY_CLUSTER_NAME annotations: alpha.cnpg.io/failoverQuorum: "true" spec: imageName: ghcr.io/cloudnative-pg/postgresql:18-system-trixie inheritedMetadata: annotations: service.beta.kubernetes.io/azure-dns-label-name: $AKS_PRIMARY_CLUSTER_PG_DNSPREFIX labels: azure.workload.identity/use: "true" instances: 3 smartShutdownTimeout: 30 probes: startup: type: streaming maximumLag: 32Mi periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 120 readiness: type: streaming maximumLag: 0 periodSeconds: 10 failureThreshold: 6 topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: cnpg.io/cluster: $PG_PRIMARY_CLUSTER_NAME affinity: nodeSelector: workload: postgres resources: requests: memory: '8Gi' cpu: 2 limits: memory: '8Gi' cpu: 2 bootstrap: initdb: database: appdb owner: app secret: name: db-user-pass dataChecksums: true storage: storageClass: $POSTGRES_STORAGE_CLASS size: 64Gi postgresql: synchronous: method: any number: 1 parameters: wal_compression: lz4 max_wal_size: 6GB max_slot_wal_keep_size: 10GB checkpoint_timeout: 15min checkpoint_completion_target: '0.9' checkpoint_flush_after: 2MB wal_writer_flush_after: 2MB min_wal_size: 2GB shared_buffers: 4GB effective_cache_size: 12GB work_mem: 62MB maintenance_work_mem: 1GB autovacuum_vacuum_cost_limit: "2400" random_page_cost: "1.1" effective_io_concurrency: "64" maintenance_io_concurrency: "64" log_checkpoints: 'on' log_lock_waits: 'on' log_min_duration_statement: '1000' log_statement: 'ddl' log_temp_files: '1024' log_autovacuum_min_duration: '1s' pg_stat_statements.max: '10000' pg_stat_statements.track: 'all' hot_standby_feedback: 'on' pg_hba: - host all all all scram-sha-256 serviceAccountTemplate: metadata: annotations: azure.workload.identity/client-id: "$AKS_UAMI_WORKLOAD_CLIENTID" labels: azure.workload.identity/use: "true" backup: barmanObjectStore: destinationPath: "https://${PG_PRIMARY_STORAGE_ACCOUNT_NAME}.blob.core.windows.net/backups" azureCredentials: inheritFromAzureAD: true retentionPolicy: '7d' EOF
注释
示例清单使用 ghcr.io/cloudnative-pg/postgresql:18-system-trixie 映像,因为它适用于稍后显示的核心 Barman Cloud 集成。 准备好切换到 Barman Cloud 插件时,在重新部署群集之前,请更新spec.imageNameghcr.io/cloudnative-pg/postgresql:18-standard-trixie并遵循插件配置指南。
Important
该示例 pg_hba 条目允许非 TLS 访问。 如果保留此配置,请记录团队的安全影响,并尽可能首选加密连接。
使用
kubectl get命令验证是否已成功创建主要 PostgreSQL 群集。 CNPG 群集 CRD 指定了三个实例,可以在启动并加入每个实例进行复制后查看正在运行的 Pod 来验证。 请耐心等待,因为所有三个实例需要一些时间才能联机并加入群集。kubectl get pods --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -l cnpg.io/cluster=$PG_PRIMARY_CLUSTER_NAME示例输出
NAME READY STATUS RESTARTS AGE pg-primary-cnpg-r8c7unrw-1 1/1 Running 0 4m25s pg-primary-cnpg-r8c7unrw-2 1/1 Running 0 3m33s pg-primary-cnpg-r8c7unrw-3 1/1 Running 0 2m49s
Important
如将本地 NVMe 与 Azure 容器存储一起使用,并且 Pod 停滞在初始化状态并出现多重附加错误,则 pod 可能仍会在丢失的节点上搜索卷。 Pod 开始运行后,会进入 CrashLoopBackOff 状态,因为 CNPG 在新的节点上创建了没有数据的新副本,并且无法找到 pgdata 目录。 若要解决此问题,请销毁受影响的实例并启动一个新实例。 运行下面的命令:
kubectl cnpg destroy [cnpg-cluster-name] [instance-number]
验证 Prometheus PodMonitor 是否正在运行
手动创建的 PodMonitor 将 kube-prometheus-stack 抓取配置与之前部署的 CNPG pod 关联起来。
使用 kubectl get 命令验证 PodMonitor 是否正在运行。
kubectl --namespace $PG_NAMESPACE \
--context $AKS_PRIMARY_CLUSTER_NAME \
get podmonitors.monitoring.coreos.com \
$PG_PRIMARY_CLUSTER_NAME \
--output yaml
示例输出
kind: PodMonitor
metadata:
labels:
cnpg.io/cluster: pg-primary-cnpg-r8c7unrw
name: pg-primary-cnpg-r8c7unrw
namespace: cnpg-database
spec:
podMetricsEndpoints:
- port: metrics
selector:
matchLabels:
cnpg.io/cluster: pg-primary-cnpg-r8c7unrw
如果使用 Azure Monitor for Managed Prometheus,则需要使用自定义组名称添加另一个 Pod 监视器。 托管 Prometheus 不会从 Prometheus 社区获取自定义资源定义 (CRD)。 除了组名外,CRD 是相同的。 这种设计使得托管 Prometheus 的 pod 监视器可以与使用社区 CRD 的 pod 监视器一起运行。 如果不使用托管 Prometheus,可以跳过本部分。 创建新的 Pod 监视器:
cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -f -
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: cnpg-cluster-metrics-managed-prometheus
namespace: ${PG_NAMESPACE}
labels:
azure.workload.identity/use: "true"
cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
spec:
selector:
matchLabels:
azure.workload.identity/use: "true"
cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
podMetricsEndpoints:
- port: metrics
EOF
验证是否已创建 Pod 监视器(请注意组名的差异)。
kubectl --namespace $PG_NAMESPACE \
--context $AKS_PRIMARY_CLUSTER_NAME \
get podmonitors.azmonitoring.coreos.com \
-l cnpg.io/cluster=$PG_PRIMARY_CLUSTER_NAME \
-o yaml
选项 A - Azure Monitor 工作区
部署 Postgres 群集和 Pod 监视器后,可以在 Azure Monitor 工作区中使用 Azure 门户查看指标。
选项 B - 托管 Grafana
或者,在部署 Postgres 群集和 Pod 监视器后,可以在部署脚本创建的托管 Grafana 实例上创建指标仪表板,以可视化导出到 Azure Monitor 工作区的指标。 您可以通过 Azure 门户访问托管的 Grafana。 导航到部署脚本创建的托管 Grafana 实例,然后选择“终结点”链接,如下所示:
选择“终结点”链接将打开一个新的浏览器窗口,你可以在托管 Grafana 实例上创建仪表板。 按照说明配置 Azure Monitor 数据源,然后就可添加可视化效果,创建 Postgres 群集指标仪表板。 设置数据源连接后,从主菜单中选择“数据源”选项。 您应该会看到如下所示的一组用于数据源连接的数据源选项:
在“托管 Prometheus”选项上,选择该选项以生成仪表板来打开仪表板编辑器。 编辑器窗口打开后,选择“添加可视化效果”选项,然后选择“托管 Prometheus”选项以浏览 Postgres 群集中的指标。 选择要可视化的指标后,选择“运行查询”按钮以提取可视化效果的数据,如下所示:
选择“保存”图标,将面板添加到仪表板。 可以通过在仪表板编辑器中选择“添加”按钮来添加其他面板,并重复此过程以可视化其他指标。 添加指标可视化效果后,应会显示如下所示的内容:
选择“保存”图标以保存仪表板。
后续步骤
Contributors
Microsoft 会维护本文。 本系列文章为以下参与者的原创作品:
- Ken Kilty | 主要 TPM
- Russell de Pina | 主要 TPM
- Adrian Joian | 高级客户工程师
- Jenny Hayes | 高级内容开发人员
- Carol Smith | 高级内容开发人员
- Erin Schaffer | 内容开发人员 2
- Adam Sharif | 客户工程师 2
确认书
本文档是与 CloudNativePG 操作员的维护者 EnterpriseDB 联合开发的。 我们感谢 加布里埃勒·巴托林尼 审查本文档的早期草稿并提供技术改进。