背景
服务器的 PostgreSQL
实例通过 docker-compose
运行在 docker
环境中, 使用的官方镜像;
PostgreSQL
发布了 16
的版本, 兴冲冲的修改镜像ID准备升级, 运行后报错:
2023-10-11 16:34:29.913 CST [1] FATAL: database files are incompatible with server
2023-10-11 16:34:29.913 CST [1] DETAIL: The data directory was initialized by PostgreSQL version 15, which is not compatible with this version 16.0 (Debian 16.0-1.pgdg120+1).
数据库数据分版本, 不同主要版本之间不兼容;
阅读官方文档, 说可以使用 pg_dumpall
或 pg_upgrade
工具进行处理:
- pg_dumpall
pg_dumpall
是PostgreSQL
的转储工具, 通过再老版本转储后再新版本导入的方式可以实现数据升级; - pg_upgrade
pg_upgrade
是PostgreSQL
的专用升级工具, 大量数据的情况下比pg_dumpall
性能更好; 本文使用此工具进行操作;
升级
pg_upgrade
命令需要传入至少 4 个参数:
pg_upgrade -b oldbindir [-B newbindir] -d oldconfigdir -D newconfigdir [option...]
其中 oldbindir
是旧版本的 PostgreSQL
的可执行文件目录, 整个过程最主要的就是准备这个目录;
- 运行一次旧版本的
PostgreSQL
实例:
docker run --name postgres-old postgres:15.3
容器会报错退出, 但不用管它, 目标只是为了从容器拷贝文件.
- 挂载新版数据目录运行一次新版镜像初始化数据:
docker run --rm \
--name postgres-new \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=123456 \
-v ~/data/postgres/data/:/var/lib/postgresql/data/ \
postgres:16.0
- 运行新版版本的
PostgreSQL
实例终端, 并挂载数据目录:
docker run -ti --rm \
--name postgres-new \
-v ~/data/postgres/data-old/:/var/lib/postgresql/data-old/ \
-v ~/data/postgres/data/:/var/lib/postgresql/data/ \
postgres:16.0 bash
我这先将老数据目录改成
data-old
了;
总的来说就是新老目录都挂进去方便操作;
- 拷贝老版本的
bindir
到新版本的容器:
# 拷贝执行程序
docker cp postgres-old:/usr/lib/postgresql/15/ postgres-lib-old
docker cp postgres-lib-old postgres-new:/usr/lib/postgresql/15/
rm -rf postgres-lib-old
# 拷贝时区文件
docker cp postgres-old:/usr/share/postgresql/15/ postgres-share-old
docker cp postgres-share-old postgres-new:/usr/share/postgresql/15/
rm -rf postgres-share-old
上一步操作占用了终端, 这里新开一个进行操作;
docker
不支持容器间直接复制文件, 需要在本地转存一下;
执行pg_upgrade
时会启动旧版本服务, 需要/usr/share/postgresql/
下面的文件;
- 切回新版本的容器终端, 执行
pg_upgrade
进行升级:
# 先切到 postgres 用户, 并进入有写权限的目录, pg_upgrade 不允许以 root 用户执行
su postgres
cd ~
# 检查
pg_upgrade -b /usr/lib/postgresql/15/bin/ -B /usr/lib/postgresql/16/bin/ -d /var/lib/postgresql/data-old/ -D /var/lib/postgresql/data/ -c
# 升级
pg_upgrade -b /usr/lib/postgresql/15/bin/ -B /usr/lib/postgresql/16/bin/ -d /var/lib/postgresql/data-old/ -D /var/lib/postgresql/data/
pg_upgrade
检查和真正执行完会有一堆的ok
表示没有异常, 如果出现错误请通过日志分析;
完事后退出容器终端, 会自动删除容器;
- 删除老版本临时容器:
docker rm postgres-old