对于习惯 SSH 登录虚拟机、编辑 postgresql.conf 和 pg_hba.conf 的 DBA 来说,迁移到 Kubernetes 后,最明显的变化不是 SQL,而是配置方式变了:Pod 可能随时重建,容器内手工修改的文件也不会成为可靠的事实来源。
CloudNativePG(CNPG)把 PostgreSQL 集群配置放进 Kubernetes 自定义资源(CRD)中。DBA 只需要声明目标状态,操作符负责生成配置、执行 reload,或在必要时安排受控的重启流程。这种“无 SSH”方式会改变日常操作习惯,但也带来了版本控制、审查、可重复部署和更清晰的恢复路径。
从编辑文件转向声明目标状态
传统虚拟机环境通常是命令式操作:
- SSH 到数据库服务器。
- 编辑磁盘上的配置文件。
- 执行
pg_ctl reload,或者重启 PostgreSQL。 - 依靠人工记录这次变更。
在 Kubernetes 中,配置应当成为集群资源的一部分。CNPG 的典型工作流是:
- 在
ClusterYAML 的spec.postgresql下声明参数。 - 通过 Git 审查变更。
- 使用
kubectl apply更新资源。 - 由 CNPG 判断哪些变化可以 reload,哪些变化需要重启。
这意味着容器文件系统不再是配置的权威来源。即使你临时进入 Pod 修改了文件,后续重建或同步也可能覆盖这次修改,而且这次变更不会自然地出现在 Git 历史中。
用 YAML 调整 PostgreSQL 参数
下面是一个可以改造的 CNPG 集群示例。它配置了三个实例、连接数、内存相关参数和基础日志设置:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: prod-postgres
spec:
instances: 3
postgresql:
parameters:
max_connections: "500"
shared_buffers: "4GB"
effective_cache_size: "12GB"
work_mem: "32MB"
maintenance_work_mem: "1GB"
logging_collector: "on"
log_min_messages: "warning"
storage:
size: 50Gi
保存为 cluster.yaml 后,可以这样提交:
kubectl apply -f cluster.yaml
kubectl get cluster prod-postgres
kubectl get pods -l cnpg.io/cluster=prod-postgres -o wide
CNPG 会根据资源中的声明生成 PostgreSQL 配置。参数的生效方式取决于 PostgreSQL 本身:能够动态修改的参数通常可以通过配置 reload 生效;需要重新启动实例的参数则需要更谨慎的处理。像 shared_buffers 这类参数通常不能仅靠 reload 生效,而 work_mem 等参数通常适合动态调整,但仍应结合 PostgreSQL 版本和实际参数属性验证。
对于包含多个实例的集群,重启流程由操作符协调。生产环境仍然需要检查 Pod 角色、同步状态、PDB、维护窗口和应用连接重试能力,不能把“自动滚动重启”理解成任何情况下都绝对无感。
可以通过 PostgreSQL 或 CNPG 的状态信息确认变更是否真正生效,而不是只检查 Kubernetes 对象是否更新:
kubectl cnpg status prod-postgres
kubectl exec -it prod-postgres-1 -- \
psql -U postgres -d postgres \
-c "SHOW shared_buffers; SHOW work_mem;"
上面的 Pod 名称只是示例,实际名称应以 kubectl get pods 的输出为准。
声明式管理 pg_hba.conf
客户端认证规则也不需要直接编辑容器中的 pg_hba.conf。可以将自定义规则写入 spec.postgresql.pg_hba:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: prod-postgres
spec:
instances: 3
postgresql:
pg_hba:
- host all all 127.0.0.1/32 scram-sha-256
- hostssl app_db app_user 10.244.0.0/16 scram-sha-256
- host all all 0.0.0.0/0 reject
规则的顺序非常重要,PostgreSQL 会使用匹配到的第一条规则。示例中的网段需要替换成真实的应用网络范围,认证方式也应优先使用符合当前环境的安全配置,例如 scram-sha-256。不要为了快速排障在生产环境广泛使用 trust,因为它可能绕过密码认证。
CNPG 还需要保留集群内部通信和复制所需的规则。实践中,应以当前 CNPG 版本生成的默认行为和文档约束为准,避免用过于宽泛的规则覆盖内部连接所需的访问控制。
提交规则后,可以观察集群事件和实例状态:
kubectl apply -f cluster.yaml
kubectl describe cluster prod-postgres
kubectl get events --sort-by=.lastTimestamp
修改认证规则前,建议至少保留一个经过验证的管理入口,并在非生产环境测试新规则。错误的 pg_hba.conf 规则可能让应用无法连接,甚至让管理员失去登录路径。
用户、数据库与 Secret 分开管理
数据库用户的密码不应直接写在 Cluster YAML 或 Git 仓库中。可以先创建 Kubernetes Secret,再让 CNPG 在初始化数据库时引用它:
kubectl create secret generic app-user-credentials \
--from-literal=username=app_user \
--from-literal=password='replace-with-a-strong-password'
对应的集群资源可以这样写:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: prod-postgres
spec:
instances: 3
bootstrap:
initdb:
database: app_db
owner: app_user
secret:
name: app-user-credentials
storage:
size: 50Gi
这个示例假设 Secret 与 Cluster 资源位于同一个 Kubernetes namespace,并且 Secret 包含 CNPG 需要的键。生产环境中,建议使用外部 Secret 管理系统、Sealed Secrets 或其他受控的密钥同步方案,而不是把真实密码直接放进 shell 历史记录。示例中的密码只是占位值,不能用于生产。
还要区分两类变更:bootstrap.initdb 主要用于初始化集群;对于已经运行的集群,新增用户、轮换密码和修改权限通常应通过受控 SQL migration、专门的 Job,或其他符合团队审计流程的机制完成,而不是期待修改 bootstrap 配置后自动重建现有数据库。
“无 SSH”带来的工程收益
把配置放入 YAML 后,数据库运维获得了几个传统手工操作难以稳定提供的能力:
- 变更可审查:
shared_buffers、认证网段和日志策略都可以通过 Pull Request 审核。 - 配置可复现:新环境可以使用同一套声明重建集群,减少“这台机器曾经手工改过什么”的依赖。
- 失败更容易暴露:YAML 结构、资源字段和操作符约束可以在 Kubernetes API 或部署流水线阶段被检查。
- 恢复路径更清晰:节点或 Pod 发生故障后,操作符可以依据资源声明重新调度实例;但这并不替代备份、归档、恢复演练和数据持久化设计。
- 减少漂移:不允许把容器内临时修改当作长期配置,能避免线上状态与仓库内容逐渐分叉。
这些收益并不意味着所有数据库操作都应该交给操作符。参数调优仍然需要容量模型、查询数据和压测结果;认证规则仍然需要网络边界和最小权限设计;重启流程仍然需要应用侧连接池和故障转移能力配合。
迁移时可以采用的检查清单
- 把现有
postgresql.conf中的业务相关参数整理为spec.postgresql.parameters。 - 将
pg_hba.conf规则按连接来源、数据库、用户和认证方式重新审查,而不是机械复制。 - 明确每个参数是 reload 生效还是需要重启,并为重启设置维护窗口。
- 使用 Secret 或外部密钥系统管理密码,避免明文进入 Git 和 shell 历史。
- 在测试集群验证 YAML、认证规则、复制状态和应用重连行为。
- 为配置资源建立 Git 审查、部署记录和回滚流程。
- 继续维护备份、PITR、监控和恢复演练,不能把自愈能力当成备份的替代品。
CloudNativePG 并没有削弱 DBA 对 PostgreSQL 的控制,而是把控制面从服务器上的文本文件移到了可审查的声明式资源。真正的转变是:数据库配置不再依赖某个人记得一条 SSH 命令,而成为团队可以理解、验证、发布和恢复的系统资产。