NAS 上 Immich 升级翻车:相册索引、数据库和 Compose 回滚记录

这次记录一个自托管相册的升级现场。

环境是一台 NAS 加一台小主机,Immich 用 Docker Compose 跑。升级前服务正常,照片上传、缩略图、人脸识别都没问题。升级后 docker compose up -d 没报错,页面也能打开,但新照片没有缩略图,重复照片任务也没动静。

一开始我也以为是 Immich 新版本的问题。后来按层拆,发现真正有用的顺序是:镜像版本先固定,数据库备份先确认,UPLOAD_LOCATION 再检查,最后才看 machine learning 和任务队列。

先把 Compose 现场留住

自托管服务升级前,我现在会先做三件事:

bash 复制代码
cp docker-compose.yml docker-compose.yml.$(date +%Y%m%d-%H%M)
cp .env .env.$(date +%Y%m%d-%H%M)
docker compose ps

如果 .env 里用的是:

env 复制代码
IMMICH_VERSION=v2

它的好处是跟随 v2 主版本,坏处是复盘时不够精确。维护窗口里我更倾向于先记下当前实际镜像:

bash 复制代码
docker image ls | grep immich
docker compose config | sed -n '/image:/p'

镜像拉取只是一层,但这一层要先过

Immich 的 Compose 里不是一个镜像。常见会涉及:

  • ghcr.io/immich-app/immich-server
  • ghcr.io/immich-app/immich-machine-learning
  • ghcr.io/immich-app/postgres
  • docker.io/valkey/valkey

NAS 网络环境如果访问 GHCR 不稳,就会在升级时制造很隐蔽的问题:server 镜像拉到了,machine learning 没拉到;database 镜像还是旧的;或者不同机器上镜像 tag 看起来一样,实际 digest 不一致。

所以我会先把镜像层单独验掉:

bash 复制代码
docker pull ghcr.1ms.run/immich-app/immich-server:v2
docker pull ghcr.1ms.run/immich-app/immich-machine-learning:v2
docker pull ghcr.1ms.run/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0

这里用毫秒镜像只是为了把 GHCR 镜像入口跑稳。它不解决挂载权限,也不解决数据库迁移。镜像层过了,后面继续排。

我的 Compose 里会这样写:

yaml 复制代码
services:
  immich-server:
    image: ghcr.1ms.run/immich-app/immich-server:${IMMICH_VERSION:-v2}
    volumes:
      - ${UPLOAD_LOCATION}:/data
      - /etc/localtime:/etc/localtime:ro

  immich-machine-learning:
    image: ghcr.1ms.run/immich-app/immich-machine-learning:${IMMICH_VERSION:-v2}
    volumes:
      - model-cache:/cache

  database:
    image: ghcr.1ms.run/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
    volumes:
      - ${DB_DATA_LOCATION}:/var/lib/postgresql/data

数据库和照片目录要分开备份

自托管相册最容易犯的错,是以为"备份了数据库就等于备份了照片"。Immich 官方文档说得很明确:数据库里有路径和用户元数据,但数据库备份不包含照片和视频原文件。

我的升级前检查表现在是这样:

bash 复制代码
grep -n "UPLOAD_LOCATION\\|DB_DATA_LOCATION\\|IMMICH_VERSION" .env
du -sh "$UPLOAD_LOCATION" "$DB_DATA_LOCATION"
ls -lah "$UPLOAD_LOCATION/backups" | tail

同时确认这些目录还在:

text 复制代码
backups
encoded-video
library
profile
thumbs
upload

如果 NAS 外接盘、NFS、SMB、iSCSI 这类存储在升级前后路径变化,Immich 页面能打开也没用,后台任务会对着空目录或无权限目录工作。

索引卡住不一定是卡死

这次最容易误判的地方是数据库索引。

Immich 官方升级文档提到,VectorChord 相关迁移中,Reindexing clip_index、Reindexing face_index 在照片量大或硬件比较弱时可能持续一段时间。也就是说,看到这两行不代表一定挂了。

我会这样看:

bash 复制代码
docker compose logs -f immich-server
docker compose logs -f database

如果日志只是停在 reindex,没有报错,就先看 CPU、磁盘 IO 和数据库容器状态:

bash 复制代码
docker stats
docker compose ps database

如果出现连接失败、迁移失败、权限错误,再进入下一层。

存储权限比想象中常见

升级后缩略图不生成,我最先看 /data:

bash 复制代码
docker compose exec immich-server sh -lc 'ls -lah /data | head'
docker compose exec immich-server sh -lc 'touch /data/.write-test && rm /data/.write-test'

如果这里写不进去,后面就不用排 ML 了。相册服务能打开,只说明 server 启动了,不说明它能写缩略图、转码文件和缓存。

常见问题有几个:

现象 常见原因
/data 为空 UPLOAD_LOCATION 相对路径变了
thumbs 不更新 目录权限不对
外部图库消失 挂载路径变化
新照片不处理 job queue 卡住或无法写派生文件
人脸识别不动 machine learning 容器异常

回滚不要只回滚容器

如果确实需要回滚,不要只把镜像 tag 改回去。Immich 官方文档提醒过,切回更早版本并不受支持,尤其涉及数据库迁移时风险更高。

我的处理原则:

  1. 没有数据库备份,不做破坏性回滚。
  2. 先保留当前日志和 Compose 文件。
  3. 确认备份版本和目标版本匹配。
  4. 如果要恢复,数据库和 UPLOAD_LOCATION 要一起考虑。
  5. 先在临时目录或测试实例恢复一遍,再动主服务。

复盘

Immich 这种自托管相册,升级难点不在"容器能不能启动",而在"照片业务能不能继续运转"。页面能打开只是第一步,缩略图、搜索、人脸、重复照片、备份和权限才是后面的长链路。

毫秒镜像在这次排查里只出现一次:GHCR 镜像入口预检。它把升级窗口里最基础的镜像拉取问题提前排掉,让后面的时间集中在数据库、存储和任务队列上。这个边界要清楚,文章也更像工程复盘,而不是把所有问题都归到镜像源。

相关推荐
Wx-bishekaifayuan4 小时前
springboot桂味美食分享系统40540-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
彭亚川Allen5 小时前
从零手搓 RAG 之检索全流程,给大模型接上自己的知识库
前端·后端·ai编程
IT_陈寒5 小时前
别让Java字符串拼接偷偷吃掉你的内存
前端·人工智能·后端
_Evan_Yao5 小时前
前后端联调怎么排查问题?从 Network 到后端日志,一步步定位错误
开发语言·后端·团队开发·需求分析
程序员梅雨5 小时前
ZooKeeper面经总结
java·大数据·linux·分布式·后端·zookeeper·中间件
蜗牛互联网6 小时前
Java 17 调用视觉 Responses API:JSON 约束与人工复核路由
java·人工智能·后端
高频因子挖掘机7 小时前
股票分红送转后价格“断层”:前复权、后复权和不复权该怎么选?
后端·github·api
一条泥憨鱼7 小时前
【Redis | 黑马点评】短信登录功能 源码深度分析
java·redis·后端·session·黑马点评
威哥爱编程7 小时前
【AI全栈12-12】Spring Boot 3.x → 4.x 迁移实操:Jakarta 11、Jackson 3 与 AI 2.0
java·spring boot·后端
威哥爱编程7 小时前
【AI全栈12-11】Spring Boot 把 AI 接口真正上线扛量:限流 / 降级 / 可观测
java·spring boot·后端