Immich 数据库迁移到统一 PostgreSQL 容器(完整流程 + 脚本)

本文记录了将 Immich 从原本独立的 immich-postgres 数据库迁移到新的统一 PostgreSQL 数据库容器的完整步骤。迁移目标是让多个项目共享同一个公用数据库容器,以简

Share

本文记录了将 Immich 从原本独立的 immich-postgres 数据库迁移到新的统一 PostgreSQL 数据库容器的完整步骤。迁移目标是让多个项目共享同一个公用数据库容器,以简化维护、提高性能并统一备份策略。

以下流程适用于基于 Docker + Portainer 环境的部署。


📌 目录

  1. 创建新的 PostgreSQL 公用容器
  2. 从旧的 immich-postgres 中导出数据
  3. 在新库中创建用户与数据库(空库)
  4. 为新数据库安装扩展、配置权限
  5. 恢复数据到新库(必须使用超级用户)
  6. 验证恢复结果
  7. 修改 Immich 服务配置,使其使用新的数据库(基于 URL 连接方式)
  8. 迁移检查与收尾

1. 创建新的 PostgreSQL 公用容器(global-postgres)

1.1 创建共享网络(global-net)

docker network create global-net

或在 Portainer:
Networks → Add network → Name: global-net → Create

1.2 在 Portainer 中创建新的 PostgreSQL Stack

这里使用 Immich 官方镜像的 PostgreSQL 扩展版(包含 pgvector、vchord、cube 等)。

docker-compose.yml

version: "3.9"

services:
  postgres:
    container_name: global-postgres
    image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: super_strong_password
    volumes:
      - /opt/global-postgres/data:/var/lib/postgresql/data
    networks:
      - global-net

networks:
  global-net:
    external: true

在 Portainer 中:

Stacks → Add Stack → 粘贴上方 compose → Deploy

2. 从旧的 immich-postgres 中导出数据库备份

假设旧容器名为:immich_postgres
以下命令在宿主机执行。

docker exec immich_postgres \
  pg_dump -U postgres immich > /root/immich_backup.sql

根据你的实际用户/数据库名调整 postgresimmich

3. 在新 PostgreSQL 中创建用户与数据库(空库)

3.1 创建需要的用户

docker exec -it global-postgres \
  psql -U postgres -c "CREATE USER immich_user WITH PASSWORD 'immich_password';"

3.2 创建空库(暂由 postgres 拥有)

docker exec -it global-postgres \
  psql -U postgres -c "CREATE DATABASE immich;"

4. 在空库中安装 Immich 所需扩展

进入新数据库:

docker exec -it global-postgres psql -U postgres -d immich

安装扩展(按 Immich 官方要求):

CREATE EXTENSION cube;
CREATE EXTENSION earthdistance;
CREATE EXTENSION vector;
CREATE EXTENSION vchord;
\q

5. 恢复备份文件到新数据库(必须使用 postgres)

5.1 将备份复制到容器

docker cp /root/immich_backup.sql global-postgres:/tmp/immich_backup.sql

5.2 用超级用户恢复(不可用 immich_user)

docker exec -it global-postgres \
  psql -U postgres -d immich -f /tmp/immich_backup.sql

⚠️ 注意:
如果恢复过程中大量 ERROR 提示“某类型不存在”,说明扩展未成功安装,需要返回「步骤 4」重新执行。

6. 数据恢复后验证内容是否正确导入

6.1 查看所有扩展

docker exec -it global-postgres \
  psql -U postgres -d immich -c "\dx"

应至少看到:

vector
vchord
cube
earthdistance

6.2 查看表数量

docker exec -it global-postgres \
  psql -U postgres -d immich -c "\dt"

应看到大量表,例如:

assets
albums
users
face_search
smart_search
...

6.3 检查表数量是否合理

docker exec -it global-postgres \
  psql -U postgres -d immich -c "SELECT COUNT(*) FROM pg_tables WHERE schemaname='public';"

7. 修改 Immich 服务器,使其使用新的 PostgreSQL

⚠️ Immich 官方文档要求使用 DB_URL,而非 DB_HOST。

示例配置:

7.1 修改 immich-server 的环境变量

将:

DB_HOST=immich_postgres
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=password
DB_DATABASE_NAME=immich

改为:

DB_URL=postgresql://immich_user:immich_password@global-postgres:5432/immich

7.2 让 Immich 容器加入 global-net

在 docker-compose 或 Portainer stack 中添加:

networks:
  - global-net

确保:

networks:
  global-net:
    external: true

7.3 最终示例(immich-server 部分)

services:
  immich-server:
    ...
    environment:
      DB_URL: postgresql://immich_user:immich_password@global-postgres:5432/immich
    networks:
      - default
      - global-net

然后在 Portainer 中:

Update Stack → Immich 自动重建

8. 启动 Immich 并验证

进入 Immich Web:

  • 能看到全部照片
  • 用户账户存在
  • 地图功能正常(earthdistance)
  • 人脸识别功能正常(vector + vchord)
  • 搜索功能可正常使用

说明迁移成功。

确认无误后,可删除旧容器:

docker stop immich_postgres
docker rm immich_postgres

📦 完整流程来源说明(可用于 Blog 注脚)

迁移流程参考了以下来源与最佳实践:

  • Immich 官方文档数据库配置章节
  • PostgreSQL 官方扩展安装文档
  • Docker 官方文档关于容器数据迁移方法
  • pg_dump/psql 官方备份恢复流程
  • 社区在 Immich + pgvector 场景下的迁移案例

🎉 结语

通过以上流程,你已经成功实现:

✔ 把 Immich 数据库迁移到统一 PostgreSQL 服务
✔ 实现多个项目共享数据库容器
✔ 清晰控制用户权限
✔ 正确处理扩展,包括 vector、vchord、cube、earthdistance
✔ 使用官方推荐的 URL 连接方式配置 Immich
✔ 未来可以轻松扩展到 Plausible、Paperless 等项目

相关代码:

CREATE USER immich_user WITH PASSWORD 'immich_password';
CREATE DATABASE immich OWNER immich_user;
GRANT ALL PRIVILEGES ON DATABASE immich TO immich_user;
\c immich

GRANT ALL ON SCHEMA public TO immich_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL ON TABLES TO immich_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL ON SEQUENCES TO immich_user;


SELECT datname, datdba::regrole FROM pg_database WHERE datname='immich';


CREATE EXTENSION IF NOT EXISTS cube;
CREATE EXTENSION IF NOT EXISTS earthdistance;
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS vchord;
\q
docker exec immich_postgres \
  pg_dump -U postgres immich > immich_backup.sql

docker cp immich_backup.sql global-postgres:/tmp/immich_backup.sql

docker exec -it global-postgres \
  psql -U immich_user -d immich -f /tmp/immich_backup.sql


docker exec -it global-postgres \
  psql -U postgres -d immich -f /tmp/immich_backup.sql

Read more

第六阶段回头看:原来中医的"诊断",从头到尾在做一件事——反查源头

第六阶段回头看:原来中医的"诊断",从头到尾在做一件事——反查源头

写在最前:这是我读《黄帝内经》的学习笔记,不是教学。我读得慢、读得浅,会读错,下面这条把五篇缝在一起的理解,也可能是我的过度解读,欢迎指正——但请不要把我写的任何内容当作就医建议。 阶段小结:回看第六阶段第三十五到第三十九篇,《脉要精微论》《平人气象论》《至真要大论·病机十九条》《热论》《举痛论》。这也是整条主线的收官。 为什么停下来回头看 第六阶段读完了,第三十五到第三十九篇,五篇,主题是"诊法与病机"。 读到这儿,一件大事发生了:主线四十篇,到头了。 从第一篇"法于阴阳"到这一阶段,断断续续读了大半年。所以这一篇回头看,我想看两层:一是第六阶段这五篇讲了什么,二是——读完整条主线,对我这个学渣到底意味着什么。 先说五篇。它们表面上一个讲脉、一个讲正常值、一个讲病机口诀、一个讲发烧、

By Tranmoolee
第三十九篇:痛,多半不是哪里坏了,是哪里堵了——而堵的源头常是情绪

第三十九篇:痛,多半不是哪里坏了,是哪里堵了——而堵的源头常是情绪

写在最前:这是我读《黄帝内经》的学习笔记,不是教学。我读得慢、读得浅,会读错。看到不对的地方欢迎指正——但请不要把我写的任何内容当作就医建议。 今天这段 经脉流行不止,环周不休,寒气入经而稽迟,泣而不行,客于脉外则血少,客于脉中则气不通,故卒然而痛。 余知百病生于气也。怒则气上,喜则气缓,悲则气消,恐则气下,寒则气收,炅则气泄,惊则气乱,劳则气耗,思则气结。 ——《素问·举痛论》 痛是怎么来的:不是"坏了",是"堵了" 主线倒数第二篇,讲一个谁都躲不开的事——痛。 我一直以为,痛 = 哪里坏了、伤了。但这一篇给的解释是另一个字:堵。 经脉流行不止,环周不休,

By Tranmoolee
第三十八篇:发烧原来有剧本——以及为什么刚退烧那顿千万别嘴馋

第三十八篇:发烧原来有剧本——以及为什么刚退烧那顿千万别嘴馋

写在最前:这是我读《黄帝内经》的学习笔记,不是教学。我读得慢、读得浅,会读错。看到不对的地方欢迎指正——但请不要把我写的任何内容当作就医建议。 今天这段 今夫热病者,皆伤寒之类也…… 伤寒一日,巨阳受之,故头项痛,腰脊强。二日阳明受之……三日少阳受之……三阳经络皆受其病,而未入于脏者,故可汗而已。 四日太阴受之……五日少阴受之……六日厥阴受之…… 其未满三日者,可汗而已;其满三日者,可泄而已。 病热少愈,食肉则复,多食则遗,此其禁也。 ——《素问·热论》 先说一件我亲身栽过的事 先讲个糗事。有年冬天我重感冒,烧了两天,第三天觉得好多了,人一轻松,嘴就馋——晚上约了朋友吃火锅,涮肉、喝汤、吃到撑。结果当天半夜,烧又上来了,比之前还难受,多躺了三四天才彻底缓过来。

By Tranmoolee
第三十七篇:一份两千年前的"症状→根源"查找表,但最关键的是末尾那句

第三十七篇:一份两千年前的"症状→根源"查找表,但最关键的是末尾那句

写在最前:这是我读《黄帝内经》的学习笔记,不是教学。我读得慢、读得浅,会读错。看到不对的地方欢迎指正——但请不要把我写的任何内容当作就医建议。 今天这段 诸风掉眩,皆属于肝。诸寒收引,皆属于肾。诸气膹郁,皆属于肺。诸湿肿满,皆属于脾。诸热瞀瘛,皆属于火。诸痛痒疮,皆属于心。诸厥固泄,皆属于下。诸痿喘呕,皆属于上。诸禁鼓栗,如丧神守,皆属于火。诸痉项强,皆属于湿。诸逆冲上,皆属于火。诸胀腹大,皆属于热。诸躁狂越,皆属于火。诸暴强直,皆属于风。诸病有声,鼓之如鼓,皆属于热。诸病胕肿,疼酸惊骇,皆属于火。诸转反戾,水液浑浊,皆属于热。诸病水液,

By Tranmoolee