加载中

Loading...

文章背景图

Halo博客数据库升级:H2内嵌库迁移PostgreSQL 15.14实战记录

2026-05-14
19
-
- 分钟
|

先说说从H2内嵌库迁移到PostgreSQL的原因:

最大的原因是因为H2 是内嵌式文件数据库,设计初衷就是给本地开发、自测用的,官方明确不建议正式博客、生产环境长期使用,且H2 所有数据就存在单个本地文件里,没有完善的事务日志、崩溃恢复机制。

而我选择PostgreSQL是因为其支持索引优化、并发连接、复杂查询,后期数据再多也能流畅运行。

直接进入正题:

一、先检查现有 Halo 容器的完整配置

执行下面这一条命令,自动过滤出我们需要的端口、数据目录、环境变量所有信息:

查询容器名:docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}" | grep halo

提取关键配置:docker inspect halo | grep -A 10 -E '"HostPort"|"Source"|"Env":'

[root@ser586654970291 halo]# docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}" | grep halo
halo      registry.fit2cloud.com/halo/halo-pro:2.24   0.0.0.0:8090->8090/tcp, :::8090->8090/tcp
halodb    postgres:15.4                               0.0.0.0:5432->5432/tcp, :::5432->5432/tcp
[root@ser586654970291 halo]# docker inspect halo | grep -A 10 -E '"HostPort"|"Source"|"Env":'
                        "HostPort": "8090"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "on-failure",
                "MaximumRetryCount": 3
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
--
                "Source": "/www/wwwroot/halo-new-docker/halo2",
                "Destination": "/root/.halo2",
                "Mode": "rw",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
        "Config": {
            "Hostname": "8de18420a2cf",
            "Domainname": "",
            "User": "",
--
            "Env": [
                "JVM_OPTS=-Xmx256m -Xms256m",
                "PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "JAVA_HOME=/opt/java/openjdk",
                "LANG=en_US.UTF-8",
                "LANGUAGE=en_US:en",
                "LC_ALL=en_US.UTF-8",
                "JAVA_VERSION=jdk-21.0.10+7",
                "HALO_WORK_DIR=/root/.halo2",
                "SPRING_CONFIG_LOCATION=optional:classpath:/;optional:file:/root/.halo2/",
                "TZ=Asia/Shanghai"
--
                        "HostPort": "8090"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "8090"
                    }
                ]
            },
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",

二、无缝切换操作步骤

1. 最重要的肯定是先备份!

进入 Halo 后台 → 系统 → 备份 → 立即备份 → 下载完整备份包到本地电脑

2. 停止但不要删除原来的 Halo 容器

docker stop halo

生产环境下建议先不要删除,等新服务完全正常运行 24 小时后再删,留作最后的备份

3. 创建专门的目录存放compose配置

mkdir -p /www/wwwroot/halo-docker cd /www/wwwroot/halo-docker

4. 创建docker-compose.yml 文件

镜像、端口、数据目录、重启策略、时区最好全部和现状保持不变,无缝切换,让用户完全感知不到。

创建并编辑yml:vi docker-compose.yml

services:
  halo:
    container_name: halo
    image: registry.fit2cloud.com/halo/halo-pro:2.24
    restart: on-failure:3
    depends_on:
      halodb:
        condition: service_healthy
    networks:
      halo_network:
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 30s
    environment:
      - JVM_OPTS=-Xmx256m -Xms256m
    command:
      - --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
      - --spring.r2dbc.username=halo
      - --spring.r2dbc.password=halo
      - --spring.sql.init.platform=postgresql
      - --halo.external-url=http://localhost:8090/

  halodb:
    container_name: halodb
    image: postgres:15.4
    restart: on-failure:3
    networks:
      halo_network:
    ports:
      - "5432:5432"
    volumes:
      - ./db:/var/lib/postgresql/data
    healthcheck:
      test: [ "CMD", "pg_isready" ]
      interval: 10s
      timeout: 5s
      retries: 5
    environment:
      - POSTGRES_PASSWORD=halo
      - POSTGRES_USER=halo
      - POSTGRES_DB=halo

此配置没有暴露PostgreSQL 端口

我认为不需要给PostgreSQL添加端口映射,它只需要在内部网络和Halo通信即可,暴露到公网会有安全风险。

5. 启动新的服务栈

docker-compose up -d

6. 查看启动日志

查看PostgreSQL启动日志:docker-compose logs -f halo-postgres

查看Halo启动日志:docker-compose logs -f halo

若看到 Halo 输出Started HaloApplication in X seconds说明启动成功。

7. 恢复数据

访问Halo后台,此时会进入初始化页面:

  • 上传刚才下载的完整备份包

  • 等待恢复完成(根据数据量大小,大概在1-5 分钟)

8. 验证所有功能

  • 用原来的管理员账号密码登录

  • 检查所有文章、页面、评论是否完整

  • 检查所有附件、图片是否正常显示

可以看到数据库也已经从H2内嵌库转为PostgreSQL 15.14。

三、确认无误后的清理工作

等新服务正常运行 24 小时,确认没有任何问题后,再执行以下清理:

删除原来的旧Halo容器:docker rm halo

可选:删除旧的H2数据库文件(释放空间):rm -rf /root/.halo2/db/

四、日常管理命令

以后所有操作都在/www/wwwroot/halo-docker目录下执行:

# 启动所有服务
docker-compose up -d

# 停止所有服务
docker-compose down

# 重启所有服务
docker-compose restart

# 查看Halo日志
docker-compose logs -f halo

# 查看PostgreSQL日志
docker-compose logs -f halo-postgres

五、本次 Halo 数据库迁移踩坑记录与关键注意事项

  1. Halo官方至今只对 15.x系列做了最完整的兼容性测试。

  2. 宝塔所有版本的PostgreSQL安装路径统一是/www/server/pgsql/。

  3. 宝塔宿主机版对比Docker容器版,对于Docker化部署的Halo来说,宿主机版反而更麻烦:需要手动修改配置文件允许Docker网段访问;备份和恢复需要同时操作宝塔和Docker两个地方;升级和迁移都不如容器版方便。

  4. 容器之间不能用 127.0.0.1。若把Halo和PostgreSQL都部署在容器里,那么在Halo的数据库连接地址里绝对不能写127.0.0.1,因为那是 Halo容器自己的回环地址,根本访问不到PostgreSQL容器。

  5. 不能手动导出导入SQL。按照网上教程用pg_dump和h2dump工具手动导出导入SQL,这是极其危险的做法。H2和PostgreSQL的SQL语法、数据类型、函数都有很多差异,手动转换几乎一定会出现数据丢失或损坏的情况。

  6. 新的Halo容器一定要和原来的版本完全一致,不要在迁移的同时升级 Halo 版本,否则可能会出现兼容性问题。

  7. 我原来的容器用的是unless-stopped重启策略,比always更合理 —— 如果手动停止了容器,它不会在服务器重启后自动启动。

本文结束。

评论交流

文章目录