NAS Docker 服务恢复排查:卷权限、端口和反代

5 月 7 日恢复一台 NAS 上的容器服务:Jellyfin、PhotoPrism、Home Assistant 都在同一个 compose 项目里。docker compose up -d 返回正常,docker compose ps 里大部分服务也是 running,但页面表现并不一致:Jellyfin 媒体库为空,PhotoPrism 新照片没有进入索引,Home Assistant 的部分设备状态不更新。

这类问题不适合只从"镜像有没有拉下来"切入。镜像入口是第一层,但 NAS 容器更容易卡在 bind mount、权限、端口和反代。下面是这次排查链路。

1. 先拆出恢复链路

我把 NAS 容器恢复拆成六层:

text 复制代码
image -> compose -> volume -> permission -> port -> reverse proxy

对应的命令:

bash 复制代码
docker compose ps
docker compose logs --tail=120
df -h
docker system df

如果磁盘满了,后面所有应用日志都可能误导人。PhotoPrism、Jellyfin 这类服务写缩略图、元数据和缓存时,对 Docker 目录和媒体目录都比较敏感。

2. 镜像入口先单独预检

节后服务恢复经常遇到一个问题:compose 一次拉多个镜像,任何一个源卡住,整组服务恢复都会被拖住。我的处理是把基础镜像拆开。

bash 复制代码
docker pull docker.1ms.run/jellyfin/jellyfin:latest
docker pull docker.1ms.run/photoprism/photoprism:latest
docker pull ghcr.1ms.run/home-assistant/home-assistant:stable
docker pull docker.1ms.run/nginx:stable-alpine

毫秒镜像(1ms.run)在这一步承担的是多源镜像入口:Docker Hub 走 docker.1ms.run,GHCR 走 ghcr.1ms.run。它解决镜像拉取链路,后续的卷、权限和反代仍然要继续排。

预检通过后再跑:

bash 复制代码
docker compose pull
docker compose up -d

3. compose 里最该先看的不是 image,而是 volumes

NAS 上 Docker 服务的长期稳定性,很多时候取决于 volume 写得够不够明确。

yaml 复制代码
services:
  jellyfin:
    image: docker.1ms.run/jellyfin/jellyfin:latest
    ports:
      - "8096:8096"
    volumes:
      - /volume1/docker/jellyfin/config:/config
      - /volume1/media:/media:ro
    restart: unless-stopped

  photoprism:
    image: docker.1ms.run/photoprism/photoprism:latest
    ports:
      - "2342:2342"
    volumes:
      - /volume1/photos:/photoprism/originals
      - /volume1/docker/photoprism/storage:/photoprism/storage
    restart: unless-stopped

  homeassistant:
    image: ghcr.1ms.run/home-assistant/home-assistant:stable
    network_mode: host
    privileged: true
    volumes:
      - /volume1/docker/homeassistant:/config
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped

这里有两个判断:

  • Jellyfin 的媒体目录用 :ro,服务只读媒体文件,避免误写。
  • PhotoPrism 的 originals 和 storage 分开,避免把索引存储和原始照片混到一个目录里。

4. bind mount 要看容器实际拿到的路径

Docker bind mount 是把宿主机路径挂进容器。这个设计很直接,也意味着服务和宿主机目录结构强绑定。

排查时不要只看 compose 文件,直接看运行中的容器:

bash 复制代码
docker inspect jellyfin --format '{{json .Mounts}}'
docker inspect photoprism --format '{{json .Mounts}}'

再看宿主机目录:

bash 复制代码
ls -lah /volume1/media
ls -lah /volume1/photos
ls -lah /volume1/docker/photoprism/storage

如果日志里有这些词,优先回到权限和路径:

text 复制代码
permission denied
database is locked
cannot write
failed to scan directory
no such file or directory

NAS UI 里能访问目录,只代表当前登录用户能访问,不代表容器进程能访问。这个误判很常见。

5. 端口和反代分开测

Jellyfin 和 Home Assistant 这类服务,先测内网端口:

bash 复制代码
ss -lntp
curl -I http://127.0.0.1:8096
curl -I http://127.0.0.1:8123

如果本机端口通,再测 NAS 局域网 IP。如果局域网 IP 通,再看反代。这个顺序可以避免把 Caddy/Nginx、证书、DDNS、路由器映射全部混在一起。

反代日志:

bash 复制代码
docker logs --tail=120 nginx
docker logs --tail=120 caddy

我这次遇到的实际情况是:Jellyfin 容器本身没问题,8096 内网可访问,问题在反代 upstream 还指向了旧容器名。这个错误和镜像完全无关。

6. PhotoPrism 索引阶段要留出时间

节后导入照片和视频,PhotoPrism 的 CPU、内存、磁盘 IO 都会升高。不要看到缩略图没出来就重启容器。

bash 复制代码
docker stats
docker compose logs --tail=200 photoprism

如果日志是索引、缩略图、导入相关记录,且没有持续权限报错,可以先等任务跑完。真正要处理的是 storage 不可写、originals 不可读、数据库连接异常。

7. 复盘

这次恢复最后确认了三类问题:

层级 现象 处理
image GHCR 镜像拉取慢 换成 ghcr.1ms.run 预检
volume Jellyfin 媒体库为空 修正 /volume1/media 挂载路径
proxy 域名访问 502 改 Nginx upstream 容器名

NAS Docker 服务恢复的关键不是"把镜像换个前缀就完事",而是用镜像预检排除第一层不确定性,然后继续看宿主机目录、权限、端口和入口。

下次我会把这套顺序固定到恢复文档里:

text 复制代码
df -> docker pull -> compose ps -> inspect mounts -> logs -> ss -> proxy logs

它不复杂,但能避免在错误层级反复重启容器。

相关推荐
RISCV_Explorer3 分钟前
RISC-V RVV向量编程模型机制解析——vsetvl配置、掩码与尾元素策略及长度无关编程
后端·risc-v
对象存储与RustFS10 分钟前
升级 RustFS 二进制不停机:一条一条换,留一条退路
后端·rust·开源
hasty14 分钟前
限制写了却没生效:OpenTelemetry Go 的 Unicode 截断边界
开发语言·后端·golang
SensorFlow3 小时前
看板有漏斗阶段,为什么转化率仍可能是假的?用 ClickHouse 检查演示埋点
后端
LucianaiB3 小时前
【TextIn xParse 与 Workbuddy实践】我把答辩材料丢给 AI 审了一遍,它开始追着我要证据
后端
王中阳Go3 小时前
读者问"你用的什么 Agent":3 个 AI 员工的分工表和工具链
人工智能·后端·ai编程
BadQiang3 小时前
Java 调用 Python 服务,报错后该从哪里查起?
后端
Hashan3 小时前
Vibe Coding 下前后端怎么对接接口?后端不给力的兜底方案
前端·后端·vibecoding
小蒜学长3 小时前
基于SpringBoot+Vue的小学数学智能出题系统(代码+数据库+LW)
java·数据库·spring boot·后端·智能出题系统
小朱爱编程1234 小时前
我用 Jev 做了三个实用工具:整理标签页、分诊飞书反馈、找回 GitHub 收藏
java·开发语言·人工智能·后端·python·架构·ai编程