运维操作手册

Alauda CloudNativePG 集群日常运维的实用参考。每个章节都是独立的——直接跳转到你需要的操作。

TIP

kubectl 命令中,应将 CNPG 集群写为 cluster.postgresql.cnpg.io — 在 ACP 集群上,裸 cluster 简称会解析为 Cluster API 的资源。下面的几个操作步骤使用了 cnpg kubectl plugin(kubectl cnpg ...);请从上游 CloudNativePG release artifacts 中安装它。

集群生命周期

创建集群

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata: { name: <name>, namespace: <ns> }
spec:
  instances: 3
  # Omit image fields to run the PostgreSQL version shipped with this
  # release. To select a major explicitly, set imageName to an operand
  # image from your platform registry, or create a ClusterImageCatalog
  # (not installed by default) and use imageCatalogRef — see
  # Configuration (Images section).
  storage:
    size: 5Gi
    # storageClass: <override>   # omit to use the default block SC
  bootstrap:
    initdb:
      database: app
      owner: app
      # postInitApplicationSQL:  # runs in the 'app' DB after init
      #   - "CREATE EXTENSION IF NOT EXISTS vector"

等待 phase: Cluster in healthy state。一个 3 实例集群通常会在两到五分钟内进入 healthy 状态(首次使用时的镜像拉取耗时占主导)。

扩缩实例

通过编辑 spec.instances 来增加或减少 Replica:

kubectl patch cluster.postgresql.cnpg.io <name> -n <ns> \
  --type=merge -p '{"spec":{"instances":4}}'

扩容会添加新的备用 Pod(一次一个);缩容会移除编号最高的 Replica。主节点不会因为缩容而被删除——如果要移除主节点的 Pod,请先执行 switchover。

Switchover(计划内,无数据丢失)

使用 cnpg kubectl plugin 提升指定的 Replica:

kubectl cnpg status <name> -n <ns>          # see current topology
kubectl cnpg promote <name> <name>-2 -n <ns>

当前主节点会完成正在进行的事务,目标 Replica 会完成提升,旧主节点随后作为备用节点重新加入。总写入中断时间通常为 5–15 秒。(spec.switchoverDelay 控制 operator 等待旧主节点正常关闭的时长。)

删除集群

kubectl delete cluster.postgresql.cnpg.io <name> -n <ns>
DANGER

删除 Cluster 会同时删除其 PVC,因此也会删除其数据。 实例 PVC 由 Cluster 拥有,并会随其一起被垃圾回收。在删除之前,请先执行最终备份(并验证备份有效!);如果你只想停止计算资源但保留卷,也可以改为让集群休眠(添加 cnpg.io/hibernation: "on" 注解)。

备份和恢复

配置备份存储

CNPG 使用 Barman Cloud plugin 进行兼容 S3 的备份。请参见 Quick Start: Step 3 了解创建流程——包括插件接入时触发的滚动重启(请等待 healthy 之后再执行首次备份)。

按需备份

apiVersion: postgresql.cnpg.io/v1
kind: Backup
metadata: { name: <name>-backup-20260610, namespace: <ns> }
spec:
  cluster: { name: <cluster-name> }
  method: plugin
  pluginConfiguration:
    name: barman-cloud.cloudnative-pg.io

查看进度:kubectl get backup -n <ns>phase 会从 running 变为 completed(或 failed)。小型集群通常在 10–60 秒内完成备份。

计划备份

apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata: { name: <name>-daily, namespace: <ns> }
spec:
  schedule: "0 0 3 * * *"   # 03:00 UTC daily — 6-field cron WITH seconds
  immediate: false
  suspend: false
  backupOwnerReference: self
  cluster: { name: <cluster-name> }
  method: plugin
  pluginConfiguration:
    name: barman-cloud.cloudnative-pg.io

如果要在创建时立即执行第一次备份,请设置 immediate: true。注意:将 immediate: true patch 到一个已存在的 ScheduledBackup 上不会追溯触发——它只在创建时生效。

从备份恢复

创建一个新的 Cluster,并将 bootstrap.recovery 指向源集群的 ObjectStore。使用 externalClusters 声明源集群:

apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata: { name: source-backup-readonly, namespace: <ns> }
spec:
  configuration:
    destinationPath: s3://<bucket>/<source-prefix>/   # SOURCE cluster's path
    endpointURL: http://<your-s3-endpoint>
    s3Credentials:
      accessKeyId:     { name: s3-creds, key: ACCESS_KEY_ID }
      secretAccessKey: { name: s3-creds, key: ACCESS_SECRET_KEY }
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata: { name: <new-name>, namespace: <ns> }
spec:
  instances: 1
  storage: { size: 5Gi }
  bootstrap:
    recovery:
      source: source-cluster   # alias name
      # recoveryTarget:        # optional, for PITR
      #   targetTime: "2026-05-12 14:00:00.000000+00:00"
  externalClusters:
  - name: source-cluster
    plugin:
      name: barman-cloud.cloudnative-pg.io
      parameters:
        barmanObjectName: source-backup-readonly
        serverName: <source-cluster-name>   # the name of the SOURCE Cluster

首先会执行完整恢复作业(在小型集群上大约需要 30–60 秒),然后新的主节点启动。PITR 要求恢复目标时间必须落在源集群的 WAL 归档范围内。

验证备份是否存在

mc alias set s3 http://<your-s3-endpoint> '<access>' '<secret>'
mc ls --recursive s3/<bucket>/<prefix>/base/
# Each base/<timestamp>/ directory is one full backup
mc ls --recursive s3/<bucket>/<prefix>/wals/ | tail -20
# WAL segments are continuously archived

故障切换场景

主 Pod 丢失时自动故障切换

如果主 Pod 被删除、被杀死,或者其所在节点发生故障,operator 会自动提升同步进度最靠前的备用节点。无需手动干预。

kubectl delete pod <cluster>-1 -n <ns>   # simulate
kubectl get cluster.postgresql.cnpg.io <cluster> -n <ns> -w
# Watch the PRIMARY column change

kubectl cnpg status <cluster> -n <ns> 会显示复制拓扑以及当前哪个 Pod 是主节点。

手动故障切换(替换异常主节点)

对于计划内替换,请使用上面的 switchover 操作步骤(kubectl cnpg promote)。避免直接对主节点使用 kubectl delete pod——switchover 更加干净。

灾难恢复(整个集群丢失)

按照 从备份恢复 操作步骤,将最近的备份恢复到一个新的 namespace 或新的集群名称中。

Drain 和节点维护

Drain 一个 worker 节点

CNPG 会按 Cluster 创建 PodDisruptionBudgets,因此 kubectl drain 的行为是安全的:

kubectl drain <node> --ignore-daemonsets --delete-emptydir-data

行为取决于被 drain 的节点上运行的是哪个 Pod:

场景预期行为
仅 ReplicaPDB 允许一个 Replica 发生中断;驱逐很快完成
Primaryoperator 会先执行 switchover;主节点 PDB 会阻止驱逐,直到新的主节点被提升
Primary 和一个 Replica 在同一节点上先执行 switchover,再驱逐 Replica;集群会短暂处于冗余降低状态

对于同步复制集群,请一次只 drain 一个节点,并等待 kubectl cnpg status 显示所有 Replica 重新开始 streaming 后,再 drain 下一个节点。

升级期间执行 cordon

在升级 worker 节点时,先执行 cordon,再执行 drain。operator 会自动将 Pod 重新调度到其他 worker 上。如果 Pod 无法重新调度(容量不足),请先添加节点,或在 drain 之前临时降低 spec.instances

Operator 和 PostgreSQL 升级

Operator(OLM bundle)升级

installPlanApproval: Automatic 时,OLM 会自动从 catalog 中获取新版本。CSV 会从旧版本切换到新版本,operator Pod 只会重启一次。在 operator 升级期间,PostgreSQL Pod 不会被重新创建——它们会保持原样继续运行。

如果你使用的是 installPlanApproval: Manual,InstallPlan 会一直停留在 phase: RequiresApproval,直到你对其进行 patch:

kubectl patch installplan <name> -n cnpg-system \
  --type=merge -p '{"spec":{"approved":true}}'

有关逐版本升级的具体说明,请参见 Upgrade

PostgreSQL 大版本升级(例如 17 → 18)

CNPG 支持声明式大版本升级:将 Cluster 指向下一个大版本的 operand image(spec.imageName,如果你在管理 catalog,则可以使用 spec.imageCatalogRef.major)。operator 会执行一次 离线 升级:实例先关闭,pg_upgrade 在专用 job 中运行,然后实例以新的大版本恢复运行(Replica 会基于升级后的主节点重新创建)。

在触发之前请先做备份,先验证扩展与新大版本的兼容性,并且要预期在 pg_upgrade job 运行期间会有写入中断(时长取决于数据规模)。

小版本 / 补丁版本升级

更新 PostgreSQL 小版本(例如 18.3 → 18.4)是一次滚动更新:Replica 会一次一个地在新镜像上重启,然后执行 switchover,最后旧主节点更新。典型的写入中断时间为 5–15 秒(即 switchover 期间)。

监控

每个实例都通过内置 exporter 在 9187 端口暴露指标;默认查询包(cnpg-system 中的 cnpg-default-monitoring ConfigMap)会在启动时由 operator 自动安装并接入——Cluster 侧无需任何配置。

在 ACP 上抓取指标时,你需要一个带有 prometheus: kube-prometheus 标签的 PodMonitor;在可视化方面,则需要导入两个 curated dashboard——这两项都在 Grafana dashboards 中提供了逐步说明。

日志访问

# Operator log
kubectl logs -n cnpg-system deploy/cnpg-controller-manager --tail=200

# Per-instance log (PostgreSQL + instance manager)
kubectl logs -n <ns> <cluster-name>-1 -c postgres --tail=200

日志采用 JSON 格式;可通过 jq 进行格式化以提高可读性。

故障排查矩阵

症状最可能原因解决方法
CSV 卡在 Installing 且提示 deployment not availableoperator Pod 启动失败在 operator Pod 上执行 kubectl logs --previous
kubectl wait/get cluster/<name> 在 Cluster 存在时返回 NotFound在 ACP 上,裸 cluster 会解析为 Cluster API 的资源使用 cluster.postgresql.cnpg.io/<name>
Cluster 卡在 Setting up primary 且出现 ImagePullBackOff该 Cluster 所在节点无法拉取 operand imagespec.imageName 设置为你平台镜像仓库中的 operand image
PVC 卡在 Pending没有默认 StorageClasskubectl get sc; 添加 spec.storage.storageClass
Backup 失败并提示 requested plugin is not available在插件接入的滚动发布完成之前就触发了备份等待 Cluster in healthy state,然后重新创建 Backup
Backup 失败并提示 no such hostCluster 节点无法访问 ObjectStore 的 endpointURL使用集群内部可访问的 endpoint
Backup 失败并提示 SignatureDoesNotMatchS3 access key / secret 配对错误验证 Secret 中的 key 与 ObjectStore 里的 accessKeyId.key / secretAccessKey.key 一致
恢复 job 报错:目标 not yet streamedPITR 目标时间超出了源集群的 WAL 归档范围使用 mc ls <bucket>/<source>/wals/ 确认时间戳覆盖了目标时间
Prometheus 中没有指标PodMonitor 缺失,或者缺少 prometheus: kube-prometheus 标签参见 Grafana dashboards
psql -U <app>Peer authentication failed通过 Unix socket 连接时使用了错误的 OS 用户通过 <cluster>-rw 服务使用 TCP,并使用 <cluster>-app Secret 中的密码

对于配置层面的问题,请参见 故障排查快速参考

问题反馈渠道

  • 产品问题(operator、镜像、备份 plugin):通过你的 Alauda 支持渠道反馈。
  • 文档问题:GitHub alauda/cnpg-docs

有关这些操作背后的更深层模型,请参考 架构