在 Kubernetes 上部署 PostgreSQL 只是起点。真正考验运维体系的,是运行数周或数月后出现的日常变更:实例内存不足、读流量需要更多副本、镜像需要更新。CYBERTEC PG Operator(CPO)将这些操作收敛为 PostgreSQL 自定义资源的期望状态修改,再由 Operator 配合 Patroni 执行有序切换,而不是由人工逐个重启 Pod。
关键不在于“改一行 YAML”,而在于理解滚动过程和边界:副本先更新、再切换主库、旧主库最后以副本身份回归。只要集群本身健康,这能避免整个数据库集群同时不可用。
资源调整不是同时重启
当 PostgreSQL 需要更多 CPU 或内存时,可以修改 spec.resources。CPO 不会同时销毁主从节点,而是先处理副本节点;副本带着新资源规格恢复后,Patroni 执行 switchover,让已更新的节点成为主库;最后再更新原主库。
下面的命令将请求资源调整为 500m CPU 和 1Gi 内存,并设置 1 CPU、1Gi 的上限。执行前,将 cpo 和 pg-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_recovery 为 t,该实例是副本。是否能真正分担读流量,还取决于应用如何发现和路由只读实例:服务名、代理层、连接池或应用侧读写分离策略都必须同步配置。
缩容同样是声明式操作。例如将实例数改回 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 日常运维应当追求的边界:人为定义目标,控制器负责有序抵达目标。