SnowLuma
部署

Docker 持久化数据迁移

将现有 Docker 数据安全迁移到当前持久化布局

新版本统一了容器内的持久化布局。Docker 不会自动把已有命名卷的数据复制到新的命名卷,因此,从旧版 Docker 配置升级时需要迁移一次。

迁移会保留 SnowLuma 配置、OneBot 配置、QQ 登录状态和 QQ 本地数据。整个过程不会删除旧数据卷。

开始前

  • 保留旧容器,先不要执行 docker compose down 或删除容器。
  • 不要执行 docker compose down -v,它会删除 Compose 管理的数据卷。
  • 迁移时需要停止容器,请预留短暂停机时间。
  • 宿主机应留有足够空间,迁移期间新旧数据会同时存在。

1. 确认旧容器

以下命令默认容器名是 snowluma。如果你修改过容器名,请替换第一行。

CONTAINER=snowluma
docker inspect "$CONTAINER" >/dev/null
docker inspect "$CONTAINER" \
  --format '{{range .Mounts}}{{printf "%-24s %-8s %s\n" .Destination .Type .Name}}{{end}}'

输出中应能看到以下三个容器路径:

/app/snowluma-data
/app/.config
/app/.local/share

如果缺少任一路径,请停止迁移并检查原部署配置。

2. 停止容器

停止容器可以避免配置数据库或 QQ 登录数据在复制过程中继续变化。

docker stop "$CONTAINER"

不要删除这个容器。后续复制会直接读取它当前挂载的数据,因此不需要猜测 Compose 自动生成的卷名。

3. 创建当前数据卷

docker volume create qq-gateway-data
docker volume create qq-client-config
docker volume create qq-client-data

确认三个目标卷都是空的:

docker run --rm \
  -v qq-gateway-data:/check/gateway \
  -v qq-client-config:/check/config \
  -v qq-client-data:/check/share \
  alpine:3.21 sh -ec '
    for path in /check/gateway /check/config /check/share; do
      [ -z "$(ls -A "$path")" ] || {
        echo "目标数据卷不是空的:$path" >&2
        exit 1
      }
    done
  '

如果这里报错,请不要覆盖目标卷。先确认它是否来自之前未完成的迁移。

4. 复制并校验数据

下面的命令以只读方式挂载旧容器的数据卷,将数据复制到当前数据卷,并逐文件校验内容。首次运行可能需要下载体积较小的 alpine 镜像。

docker run --rm \
  --volumes-from "${CONTAINER}:ro" \
  -v qq-gateway-data:/migration/gateway \
  -v qq-client-config:/migration/config \
  -v qq-client-data:/migration/share \
  alpine:3.21 sh -ec '
    copy_tree() {
      source_path="$1"
      target_path="$2"
      label="$3"

      [ -d "$source_path" ] || {
        echo "缺少源目录:$source_path" >&2
        exit 1
      }

      (cd "$source_path" && tar -cf - .) |
        (cd "$target_path" && tar -xpf -)

      (cd "$source_path" && find . -type f -exec sha256sum {} \; | sort) > "/tmp/${label}.source"
      (cd "$target_path" && find . -type f -exec sha256sum {} \; | sort) > "/tmp/${label}.target"
      cmp "/tmp/${label}.source" "/tmp/${label}.target"
      echo "已校验:$label"
    }

    copy_tree /app/snowluma-data /migration/gateway gateway
    copy_tree /app/.config /migration/config config
    copy_tree /app/.local/share /migration/share share
  '

命令应依次输出:

已校验:gateway
已校验:config
已校验:share

任何一步失败都应停止迁移,不要继续启动新配置。旧数据仍保留在原数据卷中。

5. 更新 Compose 配置

将服务的数据卷挂载改为:

services:
  snowluma:
    volumes:
      - qq-gateway-data:/app/data
      - qq-client-config:/app/.config
      - qq-client-data:/app/.local/share

volumes:
  qq-gateway-data:
    name: qq-gateway-data
  qq-client-config:
    name: qq-client-config
  qq-client-data:
    name: qq-client-data

然后拉取并启动当前镜像:

docker compose pull
docker compose up -d

如果使用 docker run,先删除已停止的旧容器,再用相同端口和环境变量重新创建容器,并使用下面三个挂载:

-v qq-gateway-data:/app/data \
-v qq-client-config:/app/.config \
-v qq-client-data:/app/.local/share

6. 验证迁移结果

迁移完成后依次确认:

  1. 容器保持运行,日志中没有持续出现启动错误。
  2. WebUI 可以使用原凭据登录,原有设置仍然存在。
  3. QQ 保持原登录状态,不需要重新扫码。
  4. OneBot 的监听端、令牌和机器人连接均与迁移前一致。
  5. 实际收发一条测试消息,确认事件接收和消息发送正常。
docker ps --filter "name=${CONTAINER}"
docker logs --tail 100 "$CONTAINER"

保留回滚能力

确认服务稳定前,请保留旧容器配置和旧数据卷。需要回滚时,停止当前容器,恢复升级前的 Compose 文件和镜像版本,再重新启动即可。

旧数据卷不会被本流程自动删除。建议至少完成一次容器重启并再次确认登录状态后,再自行决定是否清理。

绑定目录与多账号

使用宿主机目录

如果第一步显示挂载类型为 bind,数据已经位于宿主机目录,不需要复制 Docker 命名卷。保留原宿主机目录,只将应用数据的容器目标从 /app/snowluma-data 改为 /app/data;QQ 的两个目标路径保持不变。

多账号

额外 QQ 账号的挂载路径仍是 /app/qq-acct2、/app/qq-acct3 等。如果希望同时更换这些命名卷,请为每个账号创建独立的新卷,重复第四步的复制与校验流程,并确保一个账号只挂载一个独立的完整 HOME。

这篇文档有帮助吗?

最后更新于

本页目录