用声明式滚动更新管理 Kubernetes 上的 PostgreSQL:扩容、扩副本与升级

2026-08-25 21 预计阅读时间: 1 分钟
来源: postgr.es AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

在 Kubernetes 上部署 PostgreSQL 只是起点。真正考验运维体系的,是运行数周或数月后出现的日常变更:实例内存不足、读流量需要更多副本、镜像需要更新。CYBERTEC PG Operator(CPO)将这些操作收敛为 PostgreSQL 自定义资源的期望状态修改,再由 Operator 配合 Patroni 执行有序切换,而不是由人工逐个重启 Pod。

关键不在于“改一行 YAML”,而在于理解滚动过程和边界:副本先更新、再切换主库、旧主库最后以副本身份回归。只要集群本身健康,这能避免整个数据库集群同时不可用。

资源调整不是同时重启

当 PostgreSQL 需要更多 CPU 或内存时,可以修改 spec.resources。CPO 不会同时销毁主从节点,而是先处理副本节点;副本带着新资源规格恢复后,Patroni 执行 switchover,让已更新的节点成为主库;最后再更新原主库。

下面的命令将请求资源调整为 500m CPU1Gi 内存,并设置 1 CPU1Gi 的上限。执行前,将 cpopg-cluster 替换为实际命名空间与集群名:

kubectl -n cpo patch pg pg-cluster --type=merge -p '{
  "spec": {
    "resources": {
      "requests": {
        "cpu": "500m",
        "memory": "1Gi"
      },
      "limits": {
        "cpu": "1",
        "memory": "1Gi"
      }
    }
  }
}'

kubectl -n cpo get pod -w

观察 Pod 时,典型顺序是副本先终止并重建,随后主从角色切换,原主库再以副本身份加入。不要只看到 Pod 重建就判定故障;更可靠的判断是持续检查集群角色、就绪状态和复制状态。

资源变更还需要考虑 Kubernetes 调度约束。requests 提高后,节点必须有足够的可调度容量;limits 设得过低则可能触发 CPU 限流或内存 OOM。对于生产库,建议先确认节点余量、PodDisruptionBudget、存储性能和应用连接池配置。

PostgreSQL 参数也应进入期望状态

容器资源是 Kubernetes 层的配置,max_connections 这类参数属于 PostgreSQL 层。CPO 可以将参数写入集群声明,由 Patroni 在整个集群内协调生效。

kubectl -n cpo patch pg pg-cluster --type=merge -p '{
  "spec": {
    "postgresql": {
      "parameters": {
        "max_connections": "200"
      }
    }
  }
}'

kubectl -n cpo exec pg-cluster-0 -- \
  psql -U postgres -tAc 'show max_connections;'

并非所有 PostgreSQL 参数都能在线重载。有些参数要求重启,另一些还会明显扩大内存消耗。例如 max_connections 提升后,每个连接的工作内存、后端进程和应用连接池都要重新评估。实践中,优先采用连接池控制并发,而不是仅仅把连接数上限调大。

通过副本数承接读扩展

读请求增长时,修改 numberOfInstances 即可让 Operator 创建新副本。新节点会从领导者克隆并进入流复制;它赶上 WAL 后,才能作为稳定的只读目标。

kubectl -n cpo patch pg pg-cluster --type=merge -p '{
  "spec": {
    "numberOfInstances": 3
  }
}'

kubectl -n cpo get pod
kubectl -n cpo exec pg-cluster-2 -- \
  psql -U postgres -tAc 'select now(), pg_is_in_recovery();'

若输出中的 pg_is_in_recoveryt,该实例是副本。是否能真正分担读流量,还取决于应用如何发现和路由只读实例:服务名、代理层、连接池或应用侧读写分离策略都必须同步配置。

缩容同样是声明式操作。例如将实例数改回 2

kubectl -n cpo patch pg pg-cluster --type=merge -p '{
  "spec": {
    "numberOfInstances": 2
  }
}'

Operator 会有序移除最高编号节点。若恰好涉及领导者,Patroni 会先将主库角色切换给保留下来的节点。缩容前仍应检查复制延迟、备份状态和业务连接情况,避免在副本落后或流量高峰时进行操作。

镜像更新与大版本升级要分开看

更新 PostgreSQL 容器镜像同样是修改声明。下面示例展示镜像字段的变更方式;镜像名称和版本必须与已安装的 Operator 及存储、扩展兼容。

kubectl -n cpo exec pg-cluster-0 -- psql -U postgres -c "
  create table if not exists before_update(note text);
  insert into before_update values ('verified before image update');
"

kubectl -n cpo patch pg pg-cluster --type=merge -p '{
  "spec": {
    "dockerImage": "docker.io/cybertecpostgresql/cybertec-pg-container:rocky9-18.4-1"
  }
}'

kubectl -n cpo get pod -w
kubectl -n cpo exec pg-cluster-0 -- psql -U postgres -tAc 'select version();'
kubectl -n cpo exec pg-cluster-0 -- \
  psql -U postgres -tAc 'select note from before_update order by ctid desc limit 1;'

镜像滚动更新不等于所有升级都同样简单。小版本更新通常风险较低;跨 PostgreSQL 主版本则涉及数据目录格式、扩展兼容性、回退路径和 pg_upgrade。即使 Operator 能编排升级流程,也应将其视为独立变更:先在接近生产的数据与流量条件下演练,再核对备份恢复、扩展、驱动、监控和回滚预案。

把日常变更变成可审查的配置

这些操作的共同模式是:修改期望状态,由 Operator 持续协调实际状态。命令行 patch 适合验证和应急,但生产环境更适合把 PostgreSQL 自定义资源放进 Git,以 Pull Request 记录资源、参数、副本数和镜像变更。

上线前可以用下面这份清单约束风险:

  • 确认所有副本健康、复制延迟可接受,并且至少存在一个可接管的副本。
  • 检查 Kubernetes 节点容量、存储余量以及 Pod 调度策略。
  • 将应用连接池、只读路由和数据库参数作为同一项变更评审。
  • 镜像或主版本升级前完成备份恢复演练,并验证扩展兼容性。
  • 变更期间持续观察 Pod 就绪状态、Patroni 角色和业务错误率。

声明式模型不能消除容量规划和升级风险,但它将高风险的手工编排替换为可重复、可观察、可审查的滚动过程。这正是 Kubernetes 上 PostgreSQL 日常运维应当追求的边界:人为定义目标,控制器负责有序抵达目标。


相关推荐