背景
服务器的 PostgreSQL
实例通过 docker-compose
运行在 docker
环境中, 使用的官方镜像;
PostgreSQL
发布了新的主要的版本, 兴冲冲的修改镜像准备升级, 运行后报错:
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 16, which is not compatible with this version 16.0 (Debian 16.0-1.pgdg120+1).
这是
PostgreSQL 16
发布时候的时候的报错.
postgres-1 | 2024-10-10 01:57:26.786 UTC [1] FATAL: database files are incompatible with server
postgres-1 | 2024-10-10 01:57:26.786 UTC [1] DETAIL: The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.0 (Debian 17.0-1.pgdg120+1).
这是
PostgreSQL 17
发布时候的时候的报错.
原因是 PostgreSQL
数据库数据不同主要版本之间不兼容, 需要手动升级数据.
解决办法
阅读官方文档, 说可以使用 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...]
-b
: 旧版本的PostgreSQL
程序文件目录;-B
: 新版本的PostgreSQL
程序文件目录;-d
: 旧版本的数据目录;-D
: 新版本的数据目录;
整个操作过程需要准备以下材料:
- 老版本的
PostgreSQL
数据目录; - 老版本的
PostgreSQL
程序文件目录; - 新版本的
PostgreSQL
数据目录; - 新版本的
PostgreSQL
程序文件目录;
由于使用的是 docker
容器, 因此数据目录通过挂载不同的本地文件夹到容器中即可; 程序文件则通过 pull
不同版本的镜像即可得到.
下面开始操作.
操作前务必停止正在运行的实例, 否则可能导致数据损坏!!!
准备数据目录
# sudo rm -rf ~/data/postgres/data-old/
sudo cp -rf ~/data/postgres/data/ ~/data/postgres/data-backup/
sudo mv ~/data/postgres/data/ ~/data/postgres/data-old/
sudo mkdir -p ~/data/postgres/data/
直接将老版本的数据目录重命名, 并创建一个新的目录存放新版本数据库数据.
操作数据库事关重大, 请务必备份!!!
准备程序文件
docker pull postgres:16
docker pull postgres:17
将当前版本和新版本的
docker
镜像pull
下来, 以便提取程序文件.
docker run --rm -ti -v ~/data/postgres/upgrade/:/upgrade/ postgres:16 bash
启动老版本的
PostgreSQL
容器, 并挂载一个本地目录用以存放老版本程序数据以便后续升级使用;
镜像版本只要主要版本号一致都能用, 比如16
/16.4
; 但最好和数据文件保持一致;
mkdir -p /upgrade/16/
cp -rf /usr/lib/postgresql/16/ /upgrade/16/lib/
cp -rf /usr/share/postgresql/16/ /upgrade/16/share/
将老版本的程序文件拷贝到本地目录中;
# 检查一下文件
ls -lh /upgrade/
ls -lh /upgrade/16/
ls -lh /upgrade/16/lib/
ls -lh /upgrade/16/share/
# 完事退出容器
exit
拷贝完之后检查一下, 正常会有低版本的文件夹.
升级
docker run --rm -ti \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=123456 \
-v ~/data/postgres/data/:/var/lib/postgresql/data/ \
postgres:17
首先需要完成对新数据目录的初始化, 启动这个容器快速完成.
打印PostgreSQL init process complete; ready for start up.
这个之后就可以退出了.
这里的初始密码只是临时使用, 在数据升级完成之后会变成老数据的值.
docker run --rm -ti \
-v ~/data/postgres/upgrade/16/lib/:/usr/lib/postgresql/16/ \
-v ~/data/postgres/upgrade/16/share/:/usr/share/postgresql/16/ \
-v ~/data/postgres/data-old/:/var/lib/postgresql/data-old/ \
-v ~/data/postgres/data/:/var/lib/postgresql/data/ \
postgres:17 bash
挂载老版本程序目录 / 老版本数据目录 / 新版本数据目录准备升级;
# 先切到 postgres 用户, 并进入有写权限的目录, pg_upgrade 不允许以 root 用户执行
su postgres
cd ~
# 检查
pg_upgrade -b /usr/lib/postgresql/16/bin/ -B /usr/lib/postgresql/17/bin/ -d /var/lib/postgresql/data-old/ -D /var/lib/postgresql/data/ -c
# 升级
pg_upgrade -b /usr/lib/postgresql/16/bin/ -B /usr/lib/postgresql/17/bin/ -d /var/lib/postgresql/data-old/ -D /var/lib/postgresql/data/
# 完事退出容器
exit
pg_upgrade
检查和真正执行完会有一堆的ok
表示没有异常, 如果出现错误请通过日志分析.
清理数据
sudo rm -rf ~/data/postgres/data-old/
sudo rm -rf ~/data/postgres/data-backup/
sudo rm -rf ~/data/postgres/upgrade/
可选清理数据.