0%

更新 Docker 运行的 PostgreSQL 实例的版本

背景

服务器的 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_dumpallpg_upgrade 工具进行处理:

  • pg_dumpall
    pg_dumpallPostgreSQL 的转储工具, 通过再老版本转储后再新版本导入的方式可以实现数据升级;
  • pg_upgrade
    pg_upgradePostgreSQL 的专用升级工具, 大量数据的情况下比 pg_dumpall 性能更好; 本文使用此工具进行操作;

升级

pg_upgrade 命令需要传入至少 4 个参数:

pg_upgrade -b oldbindir [-B newbindir] -d oldconfigdir -D newconfigdir [option...]

其中 oldbindir 是旧版本的 PostgreSQL 的可执行文件目录, 整个过程最主要的就是准备这个目录;

  1. 运行一次旧版本的 PostgreSQL 实例:
docker run --name postgres-old postgres:15.3

容器会报错退出, 但不用管它, 目标只是为了从容器拷贝文件.

  1. 挂载新版数据目录运行一次新版镜像初始化数据:
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
  1. 运行新版版本的 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 了;
总的来说就是新老目录都挂进去方便操作;

  1. 拷贝老版本的 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/ 下面的文件;

  1. 切回新版本的容器终端, 执行 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 表示没有异常, 如果出现错误请通过日志分析;
完事后退出容器终端, 会自动删除容器;

  1. 删除老版本临时容器:
docker rm postgres-old

参考:

  • 本文作者: 6x
  • 本文链接: https://6xyun.cn/article/187
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!