容器里跑 PostgreSQL 的 8 条纪律(每条都踩过)
容器化 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.html | shared_buffers 与每连接内存的关系、initdb 默认行为的相关说明 |
| Postgres 官方镜像文档(Docker Hub) | https://hub.docker.com/_/postgres | PGDATA 与数据目录位置、POSTGRES_HOST_AUTH_METHOD 等环境变量 |
核验说明
- 第 2 条的 panic 日志在第 01 篇的实验里复现过两次;第 4、5 条的报错与数字分别来自第 01、16 篇的实测;第 8 条来自第 12 篇的 PITR 演练。
- 未做:没有在 Kubernetes 上验证同一批纪律(PVC 的语义与 docker volume 不同);没有测
--memory与shared_buffers之外的参数(如work_mem峰值)在 OOM 中的权重。