不能只用Deployment部署生产级PostgreSQL,因其无法保障有状态服务所需的稳定网络标识、有序启停、独占存储及故障自愈能力;必须用StatefulSet或Operator。

直接用 Deployment + PersistentVolumeClaim 部署单实例 PostgreSQL 是可行的,但生产环境不推荐——它没有故障自动恢复、主从切换或备份策略,一旦 Pod 重启或节点宕机,数据库就不可用。
为什么不能只写一个 Deployment YAML?
PostgreSQL 是有状态服务,Kubernetes 原生的 Deployment 会无差别重建 Pod,导致:
- 数据目录被清空(如果没正确挂载
PV) - 多个副本同时启动,互相争抢数据目录,触发
postmaster.pid冲突,Pod 卡在CrashLoopBackOff - 无法保证启动顺序:比如初始化脚本依赖外部存储卷就绪,但
Deployment不提供 init 容器与主容器的强依赖控制
官方镜像的 docker-entrypoint.sh 虽然支持 POSTGRES_DB 自动建库,但它只在数据目录为空时执行——而 Kubernetes 中若 PVC 已存在且非空,该脚本直接跳过,不会校验一致性。
必须用 StatefulSet 吗?
是的。除非你用 Operator(如 Crunchy、KubeBlocks 或 Stolon),否则 StatefulSet 是唯一安全的选择,因为:
- 每个 Pod 有稳定、唯一的网络标识(
postgres-0.postgres-headless),便于主从发现 - 启停顺序严格:
postgres-0必须先就绪,postgres-1才启动;缩容时也逆序终止 - 每个 Pod 绑定独立的
PVC(通过volumeClaimTemplates),避免多实例写同一目录
别试图用 Deployment + hostPath 模拟——hostPath 无法跨节点迁移,节点故障即丢数据,且不满足 ReadWriteOnce 在多副本下的隔离要求。
环境变量和 ConfigMap 别混用
POSTGRES_PASSWORD、POSTGRES_USER 这类敏感字段必须用 Secret,不是 ConfigMap。常见错误:
- 把密码明文写进
ConfigMapYAML,Git 提交后泄露 - 在
envFrom中同时引用ConfigMap和Secret,但键名冲突(例如都定义了POSTGRES_DB),后者被覆盖却不报错 - 忘记给
Secret设置type: Opaque,导致挂载失败但日志只显示failed to sync pod,无具体原因
正确做法:kubectl create secret generic postgres-secret --from-literal=POSTGRES_PASSWORD=xxx,然后在容器中用 env 显式引用,不要依赖 envFrom 批量注入。
PV/PVC 的访问模式必须匹配实际需求
PostgreSQL 单实例只能用 ReadWriteOnce(RWO)。如果你看到别人用了 ReadWriteMany(RWX),那是错的——PostgreSQL 进程不允许多个实例并发写同一数据目录。
- 本地开发(k3s/minikube):用
hostPath+ RWO,但需确保路径在目标节点上已存在且权限为700、属主为999(PostgreSQL 官方镜像默认用户 ID) - 云环境(AWS/GCP/Azure):优先选云盘类 PV(
gp3、pd-standard),它们原生支持 RWO,无需额外配置 - 绝对避开 NFS 类 RWX 存储:即使挂载成功,initdb 可能因文件锁机制失败,日志里只报
could not write lock file
一个容易被忽略的点:PVC 的 storageClassName 必须和集群中实际存在的 StorageClass 名字完全一致(区分大小写),否则 PVC 会卡在 Pending 状态,且 kubectl describe pvc 的 Events 里只显示 No volume plugin matched,不提示具体缺哪个插件。











