KernelRanch
返回文章列表

容器里跑 PostgreSQL 的 8 条纪律(每条都踩过)

2026-11-10 #数据库

容器化 PostgreSQL 不难,难的是那些"跑起来没问题、出事才发现"的细节。下面 8 条全部来自这几天在本机和 VPS 上的实际故障。

1. 挂载点别猜,看镜像

postgres 官方镜像的数据目录是 /var/lib/postgresql/data,但 18 的镜像把 PGDATA 放到了 /var/lib/postgresql/18/docker,所以挂载点应该写 /var/lib/postgresql。挂错的表现是容器能起,数据却写在可写层里,docker rm 之后全没了。

2. 停容器用 stop,不要 rm -f

跑着写入的时候直接 docker rm -f,再起会得到:

PANIC:  could not locate a valid checkpoint record
FATAL:  the database system is starting up

这个故障我复现了两次。docker stop 会发 SIGTERM 让 postmaster 正常关闭;rm -f 是 SIGKILL,共享内存里的脏页来不及落盘。

3. --link 的数据目录不能跨挂载点

pg_upgrade --link 靠硬链接搬文件,硬链接不能跨文件系统。如果新旧库分别挂在两个 volume 上,--link 会失败,只能退回 --copy。要省时间就让两个目录在同一个挂载点下。

4. PG 18 的 initdb 默认开 checksums

PG 14 的库默认没有 checksums,PG 18 的 initdb 默认开启。用 pg_upgrade 升上去会直接拒绝:

old cluster does not use data checksums but the new one does
Failure, exiting

两条路:旧库先 pg_checksums --enable(308MB 实测 943ms),或者新库 initdb --no-data-checksums。

5. --memory 是硬上限,shared_buffers 要留余量

实测:512MB 容器 + shared_buffers=384MB + 100 个连接,33 条连接稳过,35 条起必 OOM。被内核杀掉的是 checkpointer 或 backend,postmaster 重建集群,恢复窗口约 2.7 秒。每连接私有内存约 3.2MB,反推公式大致是 shared_buffers ≤ (容器内存 − 22MB − 连接数 × 3.2MB) / 1.1。

6. 端口映射能免则免

宿主端口会被 Windows 保留段、动态端口段和"已被占用"三件事同时威胁。容器内 docker exec、容器间自定义网络,能绕开整类问题。

7. 时区与 locale 不是自动的

镜像默认 Etc/UTC、C.UTF-8。业务在 +08 时区时,要么建库时指定 --locale 和 TZ,要么全链路用 timestamptz 并在展示层转换。混用 timestamp 加本地时间,跨时区一定出错。

8. 备份与日志不要写在容器里

容器可写层会被 rm 带走。归档目录、pg_wal 之外的备份文件、日志,都挂出去。PITR 演练里我就因为归档目录放在容器可写层,恢复时找不到 WAL 段而失败。

小结

这 8 条的共同点是:它们都不会在 docker run 成功的那一刻暴露。挂载点、停止方式、checksums、内存上限,全都等到升级、恢复或压力上来才现形。

如果只记一条,记第 2 条:容器里的数据库要用 docker stop,不要图快用 rm -f。一条命令的差别,换来的是一次数据目录损坏。

数据来源与检索时间

检索时间 2026-11-10。故障日志与数字均来自本机实测。

来源URL对应数据
PostgreSQL 18 文档《pg_upgrade》https://www.postgresql.org/docs/18/pgupgrade.html--link 使用硬链接、不能跨文件系统;data checksums 不一致时拒绝升级
PostgreSQL 18 文档《19.4 Resource Consumption》https://www.postgresql.org/docs/18/runtime-config-resource.htmlshared_buffers 与每连接内存的关系、initdb 默认行为的相关说明
Postgres 官方镜像文档(Docker Hub)https://hub.docker.com/_/postgresPGDATA 与数据目录位置、POSTGRES_HOST_AUTH_METHOD 等环境变量

核验说明

  • 第 2 条的 panic 日志在第 01 篇的实验里复现过两次;第 4、5 条的报错与数字分别来自第 01、16 篇的实测;第 8 条来自第 12 篇的 PITR 演练。
  • 未做:没有在 Kubernetes 上验证同一批纪律(PVC 的语义与 docker volume 不同);没有测 --memory 与 shared_buffers 之外的参数(如 work_mem 峰值)在 OOM 中的权重。