Immich 数据库从 NFS 迁移到 Ubuntu 本地(完整实战)

本文以 Docker + docker-compose 部署的 Immich 为例,记录一次 从群晖 NFS 迁移 PostgreSQL 数据库到本地磁盘 的完整过程,适用于 ESXi / PVE / 物理机环境。


一、背景与问题

原始架构

  • ESXi
  • Ubuntu Server(虚拟机)
  • Docker + docker-compose
  • 群晖 NAS 通过 NFS 提供存储
  • Immich 运行在 Ubuntu 上

初始问题

  • PostgreSQL 数据目录位于 NFS
  • 群晖不常开机
  • 群晖关机 → NFS 不可达
  • Immich / Emby 卡死
  • 只能通过 重启虚拟机 恢复

核心原则

数据库必须放在本地磁盘 NFS 只适合:

  • 成品文件(照片 / 视频)
  • 可丢失缓存(ML cache)

二、目标架构

内容 存储位置
PostgreSQL(pgdata) Ubuntu 本地
Immich cache / geodata / i18n Ubuntu 本地
照片(upload) 群晖 NFS
ML cache 群晖 NFS(可丢失)

三、准备工作

:one: 停止 Immich

cd /root/docker/immich
docker compose down

:two: 创建本地目录

mkdir -p /root/docker/immich/{pgdata,geodata,cache}

:three: 复制 geodata(非数据库,可直接拷贝)

rsync -avh /mnt/immich/geodata/ /root/docker/immich/geodata/

四、导出旧数据库(NFS → SQL)

:warning: 注意 PostgreSQL 禁止直接复制 pgdata 目录,NFS 上物理复制极易损坏数据。 必须使用 逻辑备份(pg_dump)


:one: 启动旧数据库(仍然指向 NFS)

docker compose up -d database

:two: 使用示例凭据导出数据库

示例参数(请自行替换):

数据库用户:DB_USER
数据库名称:DB_NAME
数据库密码:DB_PASSWORD

导出命令:

docker exec -e PGPASSWORD='DB_PASSWORD' -t immich_db \
  pg_dump -U DB_USER -d DB_NAME \
  > /root/docker/immich/immich.sql \
  2> /root/docker/immich/pg_dump.err

校验:

ls -lh immich.sql pg_dump.err

正常情况:

  • immich.sql:几十 MB ~ 数百 MB
  • pg_dump.err:空

五、切换数据库到本地磁盘

:one: 修改 docker-compose.yml

将 database 的 volume 从:

- /mnt/immich/pgdata:/var/lib/postgresql/data

改为:

- ./pgdata:/var/lib/postgresql/data

:two: 启动新的本地数据库(空库)

docker compose up -d database

查看日志:

docker logs --tail=50 immich_db

出现 initdb / CREATE DATABASE 表示新库初始化成功。


六、导入数据库到本地

cat /root/docker/immich/immich.sql | \
docker exec -e PGPASSWORD='DB_PASSWORD' -i immich_db \
psql -U DB_USER -d DB_NAME

导入完成后检查数据体积:

du -sh /root/docker/immich/pgdata

七、验证导入是否成功

Immich 用户表验证

Immich 使用的是 public."user"(注意是保留关键字):

docker exec -e PGPASSWORD='DB_PASSWORD' -it immich_db \
psql -U DB_USER -d DB_NAME \
-c 'select count(*) from public."user";'

如果返回 ≥ 1,说明数据已成功导入。


八、启动 Immich 全套服务

cd /root/docker/immich
docker compose up -d

九、最终校验(非常重要)

数据库是否已完全本地化

docker inspect immich_db --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

期望结果:

/root/docker/immich/pgdata -> /var/lib/postgresql/data

十、NFS 挂载建议(示例)

NAS_IP:/photos   /mnt/photos  nfs  rw,soft,noatime,_netdev,x-systemd.automount,timeo=600,retrans=5  0  0

关键点

  • :cross_mark: 禁止 hard
  • :white_check_mark: 使用 soft
  • :white_check_mark: 使用 x-systemd.automount
  • 群晖关机 ≠ 系统卡死

十一、最终效果

  • 群晖关机:
    • Immich 数据库正常
    • Ubuntu 不再卡死
  • Immich 稳定性显著提升
  • NFS 仅作为“文件存储层”

十二、一句话总结

数据库永远不要跑在 NFS 上。 NFS 适合文件,不适合有状态服务。