Skip to content

PG18:云原生与部署 ​

把 PostgreSQL 跑在容器、Kubernetes 或云托管服务上,在今天已经不是「可选项」而是「默认选项」。云原生环境改变了数据库与底层资源的关系:存储变成网络盘、实例随时可能被调度迁移、配置通过环境变量注入、备份靠快照与对象存储。PG18 的多个新特性恰好落在这个交点上——异步 I/O 子系统直面「网络存储延迟高、并发读多」的现实,initdb 默认开启校验和重塑了镜像初始化的默认安全基线,pg_upgrade 保留统计则直接压缩了容器化集群的大版本升级窗口。

本页聚焦「怎么把 PG18 部署好」:官方 Docker 镜像的细节(尤其是 PGDATA 路径在 18 上的重要变化)、Kubernetes 上的三种主流形态、云托管服务的选型考量,以及配置管理、备份与可观测性在云上的正确姿势。所有 PostgreSQL 侧的参数与行为均以官方 release notes 与文档为准;所有镜像侧的细节(环境变量、路径)均来自 Docker 官方镜像文档。

前置知识

建议先阅读:PG18:核心新特性总览

基础概念 ​

核心术语 ​

概念英文 / 记法说明
镜像image包含 PostgreSQL 二进制与 entrypoint 的容器镜像,官方镜像名为 postgres
数据卷volume / persistent storage容器外持久化数据目录的机制,PG 的 PGDATA 必须落在其上
环境变量注入env vars容器初始化参数的标准传递方式,如 POSTGRES_PASSWORD
Operatorkubernetes operator用 CRD + 控制循环把「运维知识」编码进 K8s 的组件
有状态负载StatefulSetK8s 中为数据库类工作负载提供稳定标识与有序部署的控制器
托管服务managed service云厂商运维控制面、用户只管数据与连接的形态
存算分离storage-compute separation计算节点与存储层解耦的云架构,典型如共享存储或页服务

什么才算「云原生地用 PostgreSQL」 ​

跑在容器里只是起点。云原生的完整要求是:数据可持久(数据卷的生命周期独立于容器)、实例可替换(任何节点都能被杀掉重建,由副本与备份兜底)、配置可声明(所有参数进版本管理,而非 SSH 上去改文件)、故障可自愈(failover 由 Operator 或控制面自动完成)、成本可伸缩(存储与算力独立扩缩)。这五条里,PG 本体只负责第一层的「数据正确性」,其余由镜像、Operator、云平台共同补齐。

PG18 里与部署直接相关的变化 ​

变化对部署的影响
异步 I/O 子系统(io_method 等)容器/云盘场景可以显式配置 I/O 执行方式;effective_io_concurrency 默认 16 且不再依赖 fadvise()
initdb 默认启用数据校验和新初始化的集群默认带 checksums;pg_upgrade 要求新旧集群设置一致
pg_upgrade 保留优化器统计、新增 --swap大版本升级窗口显著缩短
idle_replication_slot_timeout云上失联副本/订阅的槽有了自动失效的保险丝
监控视图增强(pg_stat_io 字节计数、每后端 I/O/WAL)云上可观测性直接受益

语法与用法 ​

官方镜像最小用法(来自 Docker 官方文档):POSTGRES_PASSWORD 是唯一必填变量:

bash
docker run --name pg18 \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -d postgres:18

带持久化与初始化的完整用法:

bash
docker run --name pg18 \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -e POSTGRES_USER=app \
  -e POSTGRES_DB=appdb \
  -e PGDATA=/var/lib/postgresql/18/docker \
  -v pg18-data:/var/lib/postgresql \
  -p 5432:5432 \
  -d postgres:18

PG18 镜像的数据路径变了

官方镜像文档明确:PG18 起 PGDATA 默认值改为版本化路径 /var/lib/postgresql/18/docker,镜像声明的 VOLUME 改为 /var/lib/postgresql。PG17 及以前的习惯做法是把卷挂在 /var/lib/postgresql/data——这个路径在 PG18 镜像上不再是数据目录。挂载与迁移务必对准新路径,详见下文「官方 Docker 镜像」一节。

docker-compose 写法:

yaml
services:
  pg18:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?required}
      POSTGRES_USER: app
      POSTGRES_DB: appdb
      PGDATA: /var/lib/postgresql/18/docker
    volumes:
      - pg18-data:/var/lib/postgresql
    ports:
      - "5432:5432"

volumes:
  pg18-data: {}

容器内调整 PG18 的 I/O 与复制参数:

conf
# postgresql.conf(或通过 ALTER SYSTEM / 启动参数覆盖)
io_method = worker
io_workers = 3

# 逻辑复制/物理复制场景的槽保险丝(新增于 PG18)
idle_replication_slot_timeout = 2h
sql
-- 运行时查看与修改(io_method 只能启动时设置,其余多数可热改)
SHOW io_method;
ALTER SYSTEM SET idle_replication_slot_timeout = '1h';
SELECT pg_reload_conf();

详细说明 ​

官方 Docker 镜像:标签、环境变量与 PGDATA 变化 ​

官方镜像由 PostgreSQL Docker 社区(docker-library/postgres)维护,标签形如 postgres:18(另有 postgres:18-alpine 等变体)。初始化由 entrypoint 脚本完成:首次启动(数据目录为空)时执行 initdb,再按顺序执行 /docker-entrypoint-initdb.d/ 下的 .sql、.sql.gz、.sh 初始化脚本。

镜像文档定义的环境变量(与部署最相关的部分):

变量必填说明
POSTGRES_PASSWORD是超级用户密码;不允许为空。除非显式把 POSTGRES_HOST_AUTH_METHOD 设为 trust(不建议),否则必须提供
POSTGRES_USER否初始超级用户名,默认 postgres;指定时会同时创建同名数据库
POSTGRES_DB否初始数据库名,默认取 POSTGRES_USER 的值
PGDATA否数据目录路径。PG18 镜像默认值变为 /var/lib/postgresql/18/docker
POSTGRES_HOST_AUTH_METHOD否控制 pg_hba.conf 中 host 连接的认证方法,14+ 默认 scram-sha-256
POSTGRES_INITDB_ARGS否透传给 initdb 的参数(如 --data-checksums 等)
POSTGRES_INITDB_WALDIR否把事务日志放到数据目录之外的位置

PGDATA 的版本化是 PG18 镜像最重要的变更。 官方文档原文明确:PG18 及以上,PGDATA 默认为 /var/lib/postgresql/18/docker(后续大版本会把 18 换成对应主版本号),镜像声明的 VOLUME 相应改为 /var/lib/postgresql。这带来两个直接后果:

  1. 旧挂载习惯必须改。PG17 及以前要把卷挂到 /var/lib/postgresql/data(挂到 /var/lib/postgresql 不会持久化数据);PG18 起则应该把卷挂到 /var/lib/postgresql,让镜像去管理版本化子目录。
  2. 大版本升级更顺滑。版本化子目录让「同一卷上并存 18 与 19 两个数据目录」成为自然形态,官方文档指出这正是为了在挂载 /var/lib/postgresql 的前提下配合 pg_upgrade --link 实现快速升级。

从 PG17 及以前镜像迁移到 PG18 镜像时,官方给出的路径是:显式设置 PGDATA,并先把既有数据挪进 PG_MAJOR/docker 子目录,再调整卷结构。

异步 I/O 在云盘与 NVMe 上的意义 ​

云环境的存储普遍是网络盘(EBS、云盘、持久卷),单次 I/O 延迟比本地 NVMe 高且波动大,而 PG 的顺序扫描、位图堆扫描、VACUUM 这类操作恰恰要发起大量独立的页读请求。PG18 的异步 I/O 让后端把这些请求排队并发提交,而不是一个一个同步等——release notes 明确列出受益场景为顺序扫描、位图堆扫描、VACUUM 等。存储越慢、并发读越密集,收益越明显;本地 NVMe 上收益相对小但通常仍为正。

三种 io_method 在云原生语境下的取舍:

取值依赖适用备注
worker(默认)无绝大多数容器与云环境常驻 io_workers(默认 3)个 I/O 进程,跨平台稳妥
io_uring构建期启用 liburing;Linux 内核支持 io_uring(该接口自内核 5.1 引入)高吞吐 NVMe 场景需确认镜像构建与运行时(seccomp 等)都放行 io_uring
sync无对照基线、排障即 PG17 及以前的同步行为

选型的定性顺序是「先默认、再对照、后切换」:保持 worker 跑基准 → 用 sync 重跑同负载建立基线 → 确认差距值得追且依赖满足时再评估 io_uring。多数场景走到第二步就会发现,瓶颈往往不在 I/O 执行方式上。

另一个对容器友好的变化:effective_io_concurrency 与 maintenance_io_concurrency 的默认值提升到 16,并且在没有 fadvise() 支持的系统上也可以设置大于 0——部分精简容器镜像与某些存储栈恰好缺这个系统调用,过去只能被锁死在 0。

Kubernetes 部署概览 ​

在 K8s 上跑 PostgreSQL,主流形态有三类,共同点是:不手写 StatefulSet 的全部细节,而是把拓扑、failover、备份策略声明出来。三者均围绕「期望状态 + 控制循环」运转,差异在于控制循环里沉淀的运维知识范围与治理归属。

CloudNativePG(CNPG):PG 生态里目前最活跃的 K8s Operator 之一,声明式管理集簇(primary + replicas)、内置备份到对象存储、支持滚动的大版本升级与受控的 pg_upgrade 流程。清单层面,用户声明的是一个 Cluster 资源(实例数、存储、备份目标),Operator 负责把期望状态变成现实。对 PG18 的支持情况以 CNPG 官方发布说明为准——Operator 对新大版本的支持通常在内核发布后数周内跟进。

Zalando Postgres Operator:老牌 Operator,同样以 CRD 声明集簇,围绕 Patroni 构建高可用,强调 Spilo 镜像(集成了 Patroni 与常用扩展的「胖镜像」)。

Patroni(自行编排):Patroni 本身不是 Operator,而是用 DCS(如 etcd)做共识的 HA 组件;可以在 K8s 里配合 StatefulSet 自行搭建,也可以在虚拟机环境使用。它的原理、DCS 配置与托管方式在本教程高可用阶段已有专页:

延伸阅读

Patroni 的架构与配置细节请见 Patroni 高可用。

三者的选择逻辑可以概括为一句话:要声明式、开箱即用选 Operator(CNPG 或 Zalando);要最大控制权或已在用 Patroni,就 Patroni + 自建编排。无论哪条路,下面这些运维知识都是通用的:PGDATA 要落在 PersistentVolume 上、大版本升级要演练 pg_upgrade 或逻辑复制方案、备份要真正做恢复演练。

云托管服务选型考量 ​

如果自运维不是核心竞争力,托管服务(DBaaS)通常是起步阶段的正确答案。市面上常见的几类:

服务形态备注
AWS RDS for PostgreSQL / Aurora PostgreSQL全托管大版本上线节奏、参数白名单由厂商控制
阿里云 RDS PostgreSQL全托管国内访问合规与生态集成友好
Google Cloud SQL for PostgreSQL全托管与 GCP 数据栈集成方便
Supabase / Neon面向应用开发者的 Postgres 平台分别以「应用平台套件」「存算分离/分支」为特色

选型时真正需要对比的是运营细节而不是功能清单:

  • 大版本可用性:PG18 能不能选、什么时候可选,完全由厂商决定;参数白名单同样如此——io_method、idle_replication_slot_timeout 这类 PG18 新参数在托管环境未必开放设置。
  • 扩展可用性:PostGIS、TimescaleDB、pg_stat_statements、pgvector 等是否预装、版本多新(见本系列第三页)。
  • 备份与 PITR 能力:保留窗口、能否恢复到独立实例、跨区域复制。
  • 连接与网络模型:直连还是走代理、连接数上限、VPC/私网打通方式。
  • 监控导出:能否把指标接到你自己的 Prometheus(见下文可观测性)。

具体性能指标与价格本页不做断言——这类数字随规格、区域、时间变化太快,任何「抄来的结论」都会误导选型,请以各厂商官方文档与自己的压测为准。还有一条容易被忽略的约束:托管服务把「参数调优的自由」连同「调优的责任」一起收走了——你无法 SSH 进去改 postgresql.conf,PG18 新参数是否开放、何时开放,全在厂商的参数白名单里。如果你的工作负载高度依赖底层调优(大内存排序、并行维护作业、AIO 配置),自建或发行版形态反而更合适;反之,多数中小规模应用在托管服务上能拿到更好的总体拥有成本。

12-factor 与配置管理 ​

12-factor 应用的第三条是「配置存储在环境里」。数据库侧的对应实践分两层:

连接与应用配置进环境。 连接串、凭据通过环境变量或 Secret 注入,不落镜像、不进代码仓库。官方镜像的 POSTGRES_* 变量就是这套约定在数据库初始化上的体现。

数据库参数分层管理。 PG 的参数有四个来源层级(优先级从高到低):会话级 SET → 角色级/库级 ALTER ROLE / ALTER DATABASE → postgresql.auto.conf(ALTER SYSTEM 写入)→ postgresql.conf。云原生的正确姿势是:把「需要持久的基础参数」写进配置文件或启动参数(随镜像/清单进版本管理),把「运维期的热调整」用 ALTER SYSTEM:

sql
-- 热调整示例:写进 postgresql.auto.conf 并 reload,重启后依然生效
ALTER SYSTEM SET idle_replication_slot_timeout = '1h';
SELECT pg_reload_conf();

-- 查看参数的当前值与来源
SELECT name, setting, source FROM pg_settings WHERE name = 'io_workers';

参数管理的方法论与更多示例见 ALTER SYSTEM 与参数管理。

Secret 管理。 POSTGRES_PASSWORD 这类值应来自 K8s Secret / 密钥管理服务,而不是写死在 compose 文件或 CI 变量里;镜像文档也提醒:POSTGRES_HOST_AUTH_METHOD=trust 可以绕过密码要求,但等于对同网段开放免密连接,生产禁止。

initdb 校验和默认值带来的部署影响 ​

PG18 的 initdb 默认启用数据校验和(可用 --no-data-checksums 关闭)。对部署流程的影响有三处:

  1. 新建集群的默认安全基线提高了。官方镜像初始化出的 PG18 数据目录默认带 checksums,页面损坏能在读取时被发现。
  2. pg_upgrade 要求新旧集群 checksum 设置一致。把「老的无 checksum 集群」升级到 PG18 时,要么新集群显式 --no-data-checksums 保持一致,要么借机开启 checksums(推荐,但必须演练)。
  3. ** checksums 有 CPU 开销**,但通常远小于其带来的数据完整性收益;有疑虑就在压测环境对比。

云上备份与快照 ​

云环境给了你两种备份手段,必须分清它们不是一回事:

  • 存储快照(volume snapshot):秒级、便宜、适合「快速回滚整个数据目录」。但快照抓的是块设备在某瞬间的状态,如果应用还在写库,快照恢复出来的是「崩溃恢复视角」的数据——PG 能靠 WAL 把它推到一致点,但要配合 pg_backup_start() / pg_backup_stop()(旧名 pg_start_backup() / pg_stop_backup())这样的 API 或直接停写,才能构成应用级一致的备份。
  • 逻辑/物理备份 + WAL 归档:pg_dump 系列与基础备份 + WAL 归档(pgBackRest、WAL-G 等)构成 PITR 能力,可以恢复到任意时间点,是真正的灾备手段。异地容灾的完整方法(offsite 策略、RPO/RTO 权衡)见专页:

延伸阅读

异地备份与灾备策略请见 异地容灾与 offsite 策略。

在 K8s Operator 形态里,备份通常由 Operator 调度到对象存储(CNPG 与 Zalando Operator 都内置了这类能力),但「Operator 帮你备份了」不等于「恢复演练做过了」——后者无法自动化,只能排进日程。

可观测性 ​

云原生环境的可观测性三件套:指标(Prometheus)、日志(stdout + 采集器)、告警。PG18 在这三条线上都有增量:

  • 指标:postgres_exporter 抓取的查询要适配 PG18 的视图变化——pg_stat_io 新增 read_bytes / write_bytes / extend_bytes,pg_stat_wal 删除了 wal_write 等四列(迁移到 pg_stat_io),pg_stat_checkpointer 新增 num_done。监控体系搭建详见 Prometheus 监控方案。
  • 日志:容器里 PG 日志走 stdout,由采集器(如 Loki、Fluent Bit)收集。PG18 的 log_connections 支持更细粒度并可报告连接各阶段耗时,log_line_prefix 新增 %L 输出客户端 IP——在「连接来自 NAT 后的 Sidecar/代理」的云环境里,这个转义符对排障价值极高。
  • 每后端视图:pg_stat_get_backend_io() 与 pg_stat_get_backend_wal() 让「定位单个连接的 I/O/WAL 消耗」成为可能。
  • 进度视图:pg_stat_progress_vacuum / pg_stat_progress_analyze 现在包含代价延迟(cost delay)时间(需 track_cost_delay_timing),长作业的「在等什么」一目了然。

最后提醒一点:云原生环境的可观测性是「三层拼图」——PG 的统计视图、容器的资源指标、网络与存储的延迟指标缺一不可。数据库看起来慢时,先确认慢在等待 I/O(pg_stat_io)、等待 CPU(资源限额)、还是网络往返(pg_stat_activity 的 wait event),再动手优化——在容器里,很多「数据库问题」的真相在数据库之外。

大版本升级在云上的路径 ​

PG18 把升级工具箱补强到历年来最齐:

  • pg_upgrade 保留优化器统计:升级完第一天不再「全表顺序扫描等待 autovacuum 救场」;注意扩展统计(extended statistics)不保留。
  • --jobs 并行检查、--swap 交换目录:升级窗口进一步压缩;配合官方镜像的版本化 PGDATA,pg_upgrade --link 的硬链接加速在容器卷上更易实现。
  • 逻辑复制在线迁移:跨大版本、跨云、跨自建/托管的通用解法,方法见 PG16 逻辑复制增强。
  • 托管服务的版本升级:通常由厂商提供蓝绿或快照回滚方案,但 PG 主版本升级多数仍需用户主动触发并停写。

无论哪条路,升级专页的流程与检查清单依然适用:大版本升级实战。

网络与连接管理 ​

容器与 K8s 环境「连接」一层的特殊之处在于:客户端到 PG 之间几乎总隔着代理层(Service、负载均衡、Sidecar、连接池),过去排障时「日志里看到的 IP 是谁」因此变得模糊。PG18 在这条线上给了三件武器:

能力说明
log_line_prefix 新增 %L日志前缀可直接输出客户端 IP——穿过代理后依然可知源头
log_connections 细化支持更细粒度取值,并可报告连接各阶段耗时(握手/认证/启动各花多久)
search_path 变更通知服务端主动把 search_path 变化告知客户端,连接池复用连接时的 schema 漂移有了协议层解法

TLS 侧也有两个配置更新:ssl_ecdh_curve 更名为 ssl_groups(旧名仍可用),允许配置多组 ECDH 曲线,且默认值包含 X25519;新增 ssl_tls13_ciphers 用于指定 TLS 1.3 的密码套件(冒号分隔多个)。云上做传输加密合规整改时,这两个参数就是你要找的开关。

连接池本身(PgBouncer 等)不属于 PG 内核范畴,但 PG18 的每后端视图(pg_stat_get_backend_io() / pg_stat_get_backend_wal())让「池里哪个连接在消耗资源」变得可查——池化环境下排障的视角从「实例级」细化到了「连接级」。顺带一提,search_path 变更通知对连接池场景是隐性但重要的修复:过去池子复用连接后「上一位用户设置的 search_path 还在生效」这类问题,如今协议层就会把变化告知客户端。

Kubernetes 有状态部署的通用要点 ​

无论选哪个 Operator 或自建 StatefulSet,下面这份清单都适用(定性描述,具体做法以所用平台文档为准):

要点常见做法与 PG 的关联
稳定存储StatefulSet + PersistentVolumeClaim,存储类选 SSD/高性能网络盘PGDATA 必须落在 PV 上;存储延迟直接影响 AIO 收益
优先级与驱逐PriorityClass、PodDisruptionBudget数据库 Pod 不应被节点维护「顺手」驱逐
反亲和Pod anti-affinity / topology spread一主两备不要落在同一台宿主机或同一可用区
资源请求requests/limits 明确 CPU 与内存io_workers、并行 worker 都吃额外进程与内存
健康检查readiness 区分「进程活着」与「主库可写」failover 期间的探针语义需要精细设计
备份调度Operator 内置或 pgBackRest 定时任务备份目标通常是对象存储
大版本升级Operator 编排的 pg_upgrade 或逻辑复制迁移PG18 的统计保留/--jobs/--swap 直接受益

通用原则只有一条:有状态负载的每一项配置都要回答「Pod 被杀后会发生什么」——数据在 PV 里、拓扑在 Operator 里、凭据在 Secret 里,Pod 本身应当是「随时可重建」的。

镜像选择的细节:变体、标签与不可变部署 ​

官方镜像提供 Debian 与 Alpine 两类变体(postgres:18 与 postgres:18-alpine)。两者的差异是基础 C 库(glibc 与 musl)与包生态的差异,对 PG 的实际影响主要体现在区域设置(locale/collation 行为)与扩展兼容性上——生产环境选型后保持一致,避免「开发用 Alpine、生产用 Debian」这类隐性漂移。

标签策略上有两个层次:

  • 次级标签(postgres:18)跟随 minor 更新:适合开发与测试环境,minor 升级是官方定义的零风险操作;
  • 摘要固定(postgres@sha256:...):生产环境可固定到具体摘要实现不可变部署,升级变成显式的、可审计的变更。

如果出于合规需要自建镜像,注意两点:一是保持与官方 entrypoint 的兼容(docker-entrypoint-initdb.d 等约定已内化到无数部署脚本);二是想要 io_method = io_uring 就必须确认构建参数里带了 liburing 支持——不确认的话,老老实实用默认的 worker。

安全基线:认证、校验和与密钥 ​

PG18 时代的安全基线可以这样概括:

  • 认证:默认 SCRAM-SHA-256(官方镜像 14+ 即默认),MD5 进入弃用通道(设置 MD5 密码会告警,可用 md5_password_warnings = off 关闭,但未来大版本将移除);有企业 IdP 的团队可以把 OAuth 认证列入规划——pg_hba.conf 的 oauth 方法、oauth_validator_libraries 验证器库与 libpq 的 OAuth 选项构成完整链路,短期令牌与集中撤销在容器化环境尤其有价值。
  • 数据完整性:PG18 的 initdb 默认开启校验和,官方镜像初始化的集群天然受益;老集群升级时用 pg_controldata 对比新旧设置,保持一致。
  • 密钥管理:POSTGRES_PASSWORD 等凭据一律来自 Secret 系统;POSTGRES_HOST_AUTH_METHOD=trust 在生产环境视为事故级别配置。
  • 取消密钥加固:线协议 3.2 下取消请求密钥提升为 256 位——需要服务端与客户端同时支持 3.2,属于「升级两端后自动获得」的改进。
  • 传输加密可调:ssl_groups 与 ssl_tls13_ciphers 让 TLS 曲线与套件的选择权回到运维手里,合规基线可以精确声明。

io_workers 与并行度的协调 ​

容器里做 I/O 相关调优时,要分清两套「worker」的分工:

组件数量由谁定干什么
I/O worker(io_workers)io_method = worker 时的专用进程,默认 3替后端执行异步 I/O 操作本身
并行查询 worker(max_parallel_maintenance_workers 等)计划与维护操作的并行度承担扫描/构建等计算的并行化

两者是互补关系:并行 worker 发起 I/O 请求,I/O worker 负责把请求变成数据。 sizing 的定性原则是——io_workers 覆盖「同时排队 I/O 的吞吐」,io_workers 不足表现为请求排队(可从 pg_aios 观察到队列形态);并行度则决定「多少个执行流在同时发起请求」。先用默认值跑基准,再按瓶颈逐项调整,比拍脑袋配大值靠谱。

备份工具链速览 ​

云上把「备份」讲清楚,先分清四类工具的分工(均为定性描述):

工具类型定位
pg_dump / pg_dumpall逻辑备份跨版本可移植,恢复慢于物理备份,适合小库与对象级抽取
pg_basebackup物理基础备份内置的整实例基础备份,PITR 的原料
pgBackRest / WAL-G物理备份 + 归档生产级并行备份、压缩、加密、对象存储集成的事实标准
卷快照存储层秒级、便宜,做回滚与快速克隆,但要按上文方式圈备份窗口

PG18 对这条链路的增量集中在工具细节上:pg_verifybackup 支持 tar 格式校验;pg_combinebackup -k/--link 在合并增量备份时硬链接共享文件;pg_dump --statistics 系列让统计可以独立迁移;vacuumdb --missing-stats-only 只补缺失统计。这些能力在「备份即代码」的流水线里都能直接用。

云上的最小权限与网络隔离 ​

部署视角的安全清单(定性,逐项展开见安全与权限阶段):

  • 网络层:数据库端口不对公网暴露;K8s 里用 NetworkPolicy 限定「哪些 Pod 能连 5432」;跨可用区/跨区域副本链路走内网或专线。
  • 认证层:默认 SCRAM-SHA-256;不使用 trust;机器账号与应用账号分离;凭据轮换纳入 Secret 管理。
  • 授权层:应用账号只授予所需库表的最小权限;模式与扩展安装使用独立的管理账号。
  • 传输层:强制 TLS(ssl_groups、ssl_tls13_ciphers 是 PG18 的配置入口),内部链路同样加密。
  • 审计层:利用 PG18 的 log_connections 细粒度与 %L 客户端 IP,把「谁、从哪、何时连上」记全。

上线前的十项检查 ​

把本章内容收敛成一份可以贴在工单里的清单:

  1. 卷挂载对准 /var/lib/postgresql,PGDATA 显式声明;
  2. POSTGRES_PASSWORD 来自 Secret,未使用 trust;
  3. initdb 校验和设置与升级路径一致(新旧集群对齐);
  4. io_method 已按存储形态选定并写入清单(启动级参数);
  5. idle_replication_slot_timeout 与 max_slot_wal_keep_size 已配置;
  6. 备份流水线含基础备份 + WAL 归档,恢复演练在日程内;
  7. 监控查询已适配 PG18 视图(pg_stat_io 字节列、num_done 等);
  8. 日志采集接好 stdout,%L 与连接阶段耗时已启用;
  9. 大版本升级路径(pg_upgrade 参数组合或逻辑复制)已演练;
  10. 托管环境(如适用)确认 PG18 可用性与参数白名单。

云托管选型的决策路径 ​

把选型收敛成一个简单的决策链,避免「功能清单焦虑」:

text
需要多少运维责任?
├── 全部自己扛 → 官方镜像/源码 + Patroni/pgBackRest 自建(对照本页与高可用阶段)
├── 有人兜底,但保留控制权 → 发行版 + 支持合同,跑在自己的虚拟机/专有网络
└── 尽量不管 → DBaaS(托管服务)
        ├── 数据规模与负载可预测 → 通用托管(RDS/阿里云 RDS/Cloud SQL)
        └── 强弹性、存算分离诉求 → 云原生形态(如 Aurora 类架构、Neon)

决策之后,用下面四个问题做最终验证:

  1. PG18 现在能用吗? 不能的话,路线图是什么;
  2. 我需要的参数能设吗? 逐个核对 io_method、idle_replication_slot_timeout 等新参数;
  3. 我需要的扩展装了吗? 版本多新(见第三页);
  4. 指标能导出来吗? 能否接入自己的 Prometheus 与告警体系。

四个问题都过关,再谈价格——顺序反了通常要多付一次迁移成本。

Operator 形态的日常运维(day-2) ​

Operator 解决的是「装起来」,day-2 运维仍然是你的责任,只是工具变了:

日常动作Operator 时代的做法依赖的 PG 能力
主从切换演练触发 Operator 的 failover 流程流复制 + Patroni 类组件(见 Patroni)
扩缩读副本改 CRD 实例数字段流复制、热备
minor 升级Operator 滚动重启minor 兼容、热备排队
major 升级Operator 编排 pg_upgrade / 逻辑复制PG18 统计保留、--jobs、--swap
备份验证定期恢复到临时集簇跑校验基础备份 + WAL 归档
容量观测接 Prometheus 的自定义查询pg_stat_io 字节级指标

核心心法:Operator 把「操作」自动化了,把「验证」留给了你——failover 演练、恢复演练这类动作无法外包,只能排进日程。

实战示例 ​

示例一:用 docker compose 跑一套可持久化的 PG18 ​

yaml
# docker-compose.yml
services:
  pg18:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?required}
      POSTGRES_DB: appdb
      # 显式写 PGDATA,不依赖镜像默认值,避免跨版本歧义
      PGDATA: /var/lib/postgresql/18/docker
    volumes:
      - pg18-data:/var/lib/postgresql
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  pg18-data: {}
bash
export POSTGRES_PASSWORD='s3cret'
docker compose up -d
docker compose exec pg18 psql -U postgres -c "SELECT version();"
text
PostgreSQL 18.x (Debian ...) on x86_64-pc-linux-gnu, ...

验证数据持久化:docker compose down && docker compose up -d 后数据仍在——因为卷挂在 /var/lib/postgresql,覆盖了版本化的 18/docker 子目录。再把 POSTGRES_PASSWORD 换成 Secret 引用(K8s 或 compose 的 secrets 配置),这套最小部署就具备了进入准生产的基本形态。

示例二:容器内验证异步 I/O ​

bash
docker compose exec pg18 psql -U postgres -c "SHOW io_method;"
text
 io_method
-----------
 worker
(1 row)
sql
-- 一个会话跑顺序扫描,另一个会话观察 AIO 队列
SELECT count(*) FROM big_table;
sql
SELECT backend_pid, io_task, count(*)
FROM pg_aios
GROUP BY 1, 2
ORDER BY 3 DESC;

若想尝试 io_uring,先确认两件事:镜像里的二进制构建时带了 liburing(官方 Debian 镜像近年已默认启用,但请以镜像说明为准),且内核与容器运行时放行 io_uring 系统调用;任一不满足就退回 worker。

示例三:声明一个 Operator 管理的 PG18 集群(示意) ​

以 CNPG 风格为例(字段名与版本以官方文档为准,此处只表达「声明式」的形态):

yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: app-db
spec:
  imageName: ghcr.io/cloudnative-pg/postgresql:18
  instances: 3
  storage:
    size: 100Gi
  backup:
    barmanObjectStore:
      destinationPath: s3://app-db-backups/
  postgresql:
    parameters:
      idle_replication_slot_timeout: "2h"

Operator 会据此拉起一主两备、配置流复制、接备份管道——具体字段、镜像地址与备份写法请以所用 Operator 的官方文档为准,不要照抄本文示例。

示例四:升级前后的一致性检查 ​

sql
-- 1) 校验和设置(pg_upgrade 前必须确认新旧一致)
SELECT * FROM pg_control_checkpoint();  -- 只示意;更直接的方式是查 pg_controldata 输出
bash
# 新旧集群各跑一次,对比 Data page checksum 字段
pg_controldata /var/lib/postgresql/17/docker | grep -i checksum
pg_controldata /var/lib/postgresql/18/docker | grep -i checksum
sql
-- 2) 升级后确认优化器统计被保留(PG18 起应为非空)
SELECT count(*) FROM pg_stats WHERE schemaname = 'public';

若统计缺失,用 vacuumdb --missing-stats-only --all 快速补齐(PG18 新选项),而不是全库 ANALYZE。

示例五:应用级一致的快照备份 ​

存储快照要成为「可恢复的备份」,必须圈定 PG 的备份窗口:

sql
-- 会话 1:进入在线备份状态(PG15+ 的函数名;更早版本为 pg_start_backup)
SELECT pg_backup_start(label => 'daily-snapshot', fast => true);
bash
# 会话 2(或脚本):对数据卷打快照(以各云平台 CLI 为准,此处仅示意流程)
# <snapshot the volume>
sql
-- 会话 1:结束备份状态
SELECT * FROM pg_backup_stop();

pg_backup_start() 到 pg_backup_stop() 之间打的快照才带有一致性元数据,恢复时 PG 能把数据推到一致点。纯快照(不打备份标记)只适合「接受崩溃恢复语义」的回滚场景。

示例六:把监控查询对准 PG18 ​

sql
-- pg_stat_io:字节级 I/O 观测(PG18 新增 read_bytes/write_bytes/extend_bytes)
SELECT backend_type, context, object,
       read_bytes, write_bytes, extend_bytes
FROM pg_stat_io
WHERE backend_type = 'client backend'
  AND read_bytes > 0
ORDER BY read_bytes DESC
LIMIT 5;
sql
-- 检查点完成数(PG18 新增 num_done:只统计真正完成的检查点)
SELECT num_timed, num_requested, num_done, slru_written
FROM pg_stat_checkpointer;
sql
-- 定位单个连接的 I/O/WAL 消耗(PG18 新增每后端统计)
SELECT pid, io_summary.*
FROM pg_stat_activity a
CROSS JOIN LATERAL pg_stat_get_backend_io(a.pid) AS io_summary
LIMIT 5;

托管环境把自定义查询贴进 postgres_exporter 的查询配置前,先在 PG18 实例上跑通——列名对不上是升级后监控报警的第一来源。

注意事项 ​

PGDATA 路径变更是硬性断裂。 PG18 官方镜像的数据目录与 VOLUME 都变了。沿用「挂 /var/lib/postgresql/data」老配置启动 PG18 镜像,数据会写进匿名卷或错误位置,容器重建即「丢数据」(数据其实还在匿名卷里,但不再被复用)。迁移时按官方指引把数据挪进 18/docker 子目录。

POSTGRES_PASSWORD 是必填项。 除非显式设置 POSTGRES_HOST_AUTH_METHOD=trust(生产禁止),镜像拒绝在无密码时初始化。凭据应来自 Secret 管理系统,而非明文 compose/CI。

新镜像默认 checksums,旧集群升级要显式对齐。 pg_upgrade 要求新旧集群 checksum 设置一致,这是 PG18 升级失败的新增经典原因,升级演练时先跑 pg_controldata 对比。

io_method 只能启动时设置。 在容器/K8s 里改动它意味着重建 Pod 或重启容器,要提前写进镜像环境变量或 Operator 的参数区,别指望热改。

io_uring 是三重门槛。 构建期要有 liburing、内核要支持 io_uring(该接口自 Linux 5.1 引入)、容器运行时的安全策略要放行相关系统调用。三者缺一则回退 worker——它本来就是默认值。

托管服务的参数白名单不完全开放。 PG18 新参数(如 io_method、idle_replication_slot_timeout)在云厂商环境未必可设;迁移到托管前先确认关键参数的可用性。

快照不等于备份。 卷快照若没有配合 pg_backup_start()/pg_backup_stop() 或停写窗口,恢复结果的一致性责任在你;PITR 必须依赖基础备份 + WAL 归档。

升级后监控面板要同步改。 pg_stat_wal 四列被移除、op_bytes 消失、pg_backend_memory_contexts.parent 被删——升级完成后导出的自定义 SQL 查询会直接报错,属于「升级成功但监控挂了」的典型。

镜像变体与自建镜像的默认值可能不同。 Alpine 与 Debian 变体的 locale 行为、自建镜像的编译参数(如是否带 liburing)都会改变运行时表现;判断「某个特性在容器里能不能用」,以镜像的构建说明为准,不要按官方源码包的默认假设推理。

托管环境的 minor 与 major 责任不同。 minor 升级通常由厂商自动滚动执行,major 升级多数需要你主动触发并停写;把「下一个大版本什么时候可用、怎么触发」写进与厂商的沟通清单,而不是等到 EOL 前。

初始化脚本只在首次启动执行。 /docker-entrypoint-initdb.d/ 下的脚本只在数据目录为空(首次 initdb)时运行;容器重建或换镜像不会重跑它们。初始化逻辑应当幂等并纳入版本管理,不要依赖「容器每次启动都执行一遍」。

别用 fsync=off 换性能。 容器与云盘的延迟问题应通过存储类选择与 I/O 配置(含 PG18 的 AIO)解决;关闭刷盘等于把持久性换成速度,数据库领域几乎没有合理场景。

最佳实践 ​

  1. 挂载卷对准 /var/lib/postgresql,并显式声明 PGDATA。 官方镜像 PG18 起的版本化目录设计就是为多版本并存与 pg_upgrade --link 服务的;显式写 PGDATA 让配置自文档化,跨镜像版本不踩坑。
  2. 把 io_method 与 io_workers 写进部署清单而不是靠默认值。 它们只能启动时设置,改一次等于重启一次;提前想清楚容器环境的存储形态再定值,用 sync 做过对照再谈优化。
  3. checksums 开启,升级前对齐设置。 新集群享受 PG18 默认开启的完整性保护;升级老集群时把「是否借机开启 checksums」作为一个显式决策写进升级方案,而不是留给 pg_upgrade 报错。
  4. 给所有复制槽配 idle_replication_slot_timeout。 云上副本随时可能被调度走或失联,槽的空闲超时与 max_slot_wal_keep_size 一起构成 WAL 磁盘的最后一道护栏。
  5. K8s 上优先选 Operator 而不是手写 StatefulSet。 failover、备份、滚动升级这些运维知识已经沉淀在 CNPG / Zalando Operator / Patroni 里,手写一遍不会更好,还会漏掉恢复演练环节。
  6. 托管服务选型先验证三件事:PG 大版本可用性、参数与扩展白名单、监控能否导出到自己的 Prometheus——功能列表会骗人,这三项不会。
  7. 凭据只走 Secret,配置分四层管理。 基础参数进配置文件与版本管理,热调整用 ALTER SYSTEM,会话/角色级微调用 ALTER ROLE / ALTER DATABASE;每层的「谁在什么时候改了什么」都可追溯。
  8. 快照做回滚、备份做灾备,两条线都要有恢复演练。 快照 + pg_backup_start()/pg_backup_stop() 保证应用级一致;WAL 归档到对象存储保证 PITR;演练恢复流程的频率以季度为单位。
  9. 升级走「pg_upgrade 保留统计 + --jobs + --swap/--link」的组合拳。 配合版本化 PGDATA,把大版本升级窗口压到分钟级;升级后用 pg_stats 验证统计,用 vacuumdb --missing-stats-only 查漏。
  10. 监控查询随版本走。 把自定义巡检 SQL 纳入版本管理并在 PG18 环境回归一遍,替换掉 pg_stat_wal 旧列与 op_bytes 引用,补上 pg_stat_io 字节级指标与每后端 I/O/WAL 视图。
  11. 容器日志按 stdout 交付,日志格式为采集器优化。 利用 log_connections 的新粒度与 %L(客户端 IP)转义符,让「连接从哪来、哪个阶段慢」在日志系统里可查。
  12. 所有「云上能不能这样跑」的结论,以官方文档与自己的演练为准。 镜像文档、Operator 文档、云厂商文档都在演进;本页给出的是已核实的基线,落地前请对准你所用版本的最新文档。

下一节

继续学习:PG18:生态与展望

参考链接 ​