Immich Dev Containers 开发环境指南:用 Docker 容器一键搭建后端、前端与 ML 联调环境
【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immich
Dev Containers 让 Immich 的开发者在 Mac、Linux、Windows 或云端环境中获得完全一致、可复现的开发环境。本文基于仓库中的 devcontainers.md 展开,并结合.devcontainer/、docker/docker-compose.dev.yml 与 server/Dockerfile.dev 的实际实现,讲解容器服务的组成、环境变量注入机制、启动脚本的自动初始化流程,以及测试、调试与排障的完整操作路径。读完后你可以独立搭建 Immich 容器化开发环境,理解端口转发、UPLOAD_LOCATION卷挂载与调试端口的底层配置,并在容器内直接运行测试与调试器。
一、前置条件与备选工具链
在开始之前,文档要求确认以下环境已就绪:
- Docker Desktop(最新版):支持 Mac、Windows(推荐 WSL2 后端)与 Linux;
- VS Code+ Dev Containers 扩展;
- Git用于克隆仓库;
- 内存:至少 8GB(推荐 16GB);
- 磁盘:至少 20GB 空闲空间。
文档同时列出了除 VS Code 之外的可选工具链,可按团队习惯选择:
| 类别 | 工具 |
|---|---|
| 本地编辑器 | IntelliJ IDEA、neovim(nvim-remote-containers)、Emacs(lsp-docker)、DevContainer CLI |
| 云端方案 | GitHub Codespaces、GitPod |
| 可自托管 | Coder、DevPod(对 devcontainer.json 支持良好,见下文快速上手) |
这些工具的共性是都遵循 devcontainer 规范,因此 Immich 仓库中同一份.devcontainer配置在它们之间基本通用。
二、容器服务组成
Immich 的 Dev Container 由一组 Docker Compose 服务构成,进入的"主容器"是immich-server。文档给出的服务表如下:
| 服务 | 容器名 | 说明 | 端口 |
|---|---|---|---|
| Server & Web | immich-server | 开发模式下同时运行 API 服务与 Web 前端 | 2283 (API)、3000 (Web)、9230 (Workers 调试)、9231 (API 调试) |
| 数据库 | database | PostgreSQL | 5432 |
| 缓存 | redis | Valkey 缓存服务 | 6379 |
| 机器学习 | immich-machine-learning | Immich ML 模型推理服务 | 3003 |
仓库中的.devcontainer/devcontainer.json证实了这一结构:runServices声明为immich-init、immich-server、redis、database、immich-machine-learning五个服务,且 Compose 文件是两层叠加的——基础层 docker/docker-compose.dev.yml 加覆盖层.devcontainer/server/container-compose-overrides.yml(见该文件第 11-14 行的dockerComposeFile字段)。
从基础 Compose 文件可以看到各服务的真实形态:
immich-init(第 36-59 行):一个"初始化门卫"容器,命令是mise install(安装各语言工具链),完成后touch /tmp/init-complete并挂起;其余服务通过depends_on: condition: service_healthy等它健康检查通过后才启动,健康检查就是探测/tmp/init-complete文件是否存在。database(第 161-177 行):使用ghcr.io/immich-app/postgres:14-vectorchord...-pgvectors...定制镜像(PostgreSQL 14 + vectorchord + pgvectors 扩展,用于向量检索),shm_size: 128mb,初始化参数带--data-checksums。redis(第 155-159 行):实际是 Valkey 9 镜像,健康检查为redis-cli ping。immich-machine-learning(第 131-153 行):构建自 machine-learning/Dockerfile,默认DEVICE=cpu,把 Python 源码目录挂载进容器便于热改。
三、快速上手
3.1 克隆仓库
克隆 Immich 仓库后进入目录(克隆地址以仓库页面的 Clone 地址为准):
git clone <immich 仓库克隆地址> cd immich3.2 配置环境变量(先于启动容器)
关键机制:Immich 的 Dev Container 从你的 shell 环境读取环境变量,而不是从.env文件。文档明确强调:本地运行时若希望使用自定义的数据/照片存储目录,必须在启动 Dev Container之前在 shell 环境中设置UPLOAD_LOCATION:
# 仅对当前会话临时生效 export UPLOAD_LOCATION=/opt/dev_upload_folder # 或写入 shell 配置以实现持久化(~/.bashrc、~/.zshrc 等) echo 'export UPLOAD_LOCATION=/opt/dev_upload_folder' >> ~/.bashrc source ~/.bashrc3.3 启动方式
文档提示了一个重要限制:由于 Immich 开发深度依赖其定制的 base 镜像,无法使用 VS Code 的 "Clone Repository in a Container Volume" 命令,必须先在宿主机克隆仓库再重开进容器。三种启动方式:
方式一:VS Code 命令面板
- 在 VS Code 中打开已克隆的仓库;
- 按
F1(或Ctrl/Cmd+Shift+P)打开命令面板; - 执行 "Dev Containers: Rebuild and Reopen in Container";
- 选择 "Immich - Backend, Frontend and ML";
- 等待构建完成(首次运行可能需要数分钟)。
方式二:VS Code 快捷弹窗打开仓库后点击弹出的 "Reopen in Container"。
方式三:命令行
# 使用 DevContainer CLI devcontainer up --workspace-folder .方式四:DevPod + Docker(文档中的快速上手小节)
# Step 1: 克隆仓库 git clone <immich 仓库克隆地址> cd immich # Step 2: 配置 DevPod provider(如尚未配置) devpod provider add docker devpod provider use docker # Step 3: 先手动构建 'immich-server-dev' 镜像 docker build -f server/Dockerfile.dev -t immich-server-dev . # Step 4: 启动 devcontainer devpod up .注意 Step 3 是必要的:DevContainer 的service指向immich-server,其镜像immich-server-dev:latest由 server/Dockerfile.dev 的dev-container-server目标构建而来。
四、环境变量机制:remoteEnv与${localEnv:...}语法
与基于 Docker Compose +.env的传统开发者设置不同,Dev Container 通过 devcontainer 规范把宿主机 shell 变量"搬运"进容器。.devcontainer/devcontainer.json中的实际配置为:
"remoteEnv": { "UPLOAD_LOCATION": "${localEnv:UPLOAD_LOCATION:./library}", "DB_PASSWORD": "${localEnv:DB_PASSWORD:postgres}", "DB_USERNAME": "${localEnv:DB_USERNAME:postgres}", "DB_DATABASE_NAME": "${localEnv:DB_DATABASE_NAME:immich}" }其中${localEnv:VARIABLE:default}的含义是"读取本地 shell 中的VARIABLE,未设置时回退到默认值"。各变量的默认值与说明:
| 变量 | 默认值 | 说明 |
|---|---|---|
UPLOAD_LOCATION | ./library | 上传文件与数据库数据的存放位置(可设为绝对路径) |
DB_PASSWORD | postgres | PostgreSQL 密码(建议仅使用A-Za-z0-9字符) |
DB_USERNAME | postgres | PostgreSQL 用户名 |
DB_DATABASE_NAME | immich | 数据库名 |
4.1UPLOAD_LOCATION的路径解析(源码级印证)
文档描述的默认解析结果为<immich-root>/docker/Library。从仓库当前源码看,实际的覆盖层.devcontainer/server/container-compose-overrides.yml采用了比文档更完善的双模式设计:
# immich-server 的挂载(第 16 行) - ${UPLOAD_LOCATION:-upload-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data # database 的挂载(第 33 行) - ${UPLOAD_LOCATION:-postgres-devcontainer-volume}${UPLOAD_LOCATION:+/postgres}:/var/lib/postgresql/data这段 Compose 表达式可以拆解为两个分支:
- 未设置
UPLOAD_LOCATION时:挂载名为upload-devcontainer-volume/postgres-devcontainer-volume的命名 Docker 卷(文件末尾volumes:段落声明了它们)。容器照常工作,只是数据落在 Docker 管理的卷里,适合云端等无需持久化到宿主目录的场景——这正是文档所说"在云环境中无需预配置也能运行"的实现基础; - 设置了
UPLOAD_LOCATION时:挂载宿主机的${UPLOAD_LOCATION}/photos到容器/data、${UPLOAD_LOCATION}/postgres到/var/lib/postgresql/data,照片与数据库数据均可直接在宿主机上访问和备份。
因此,如果你希望"数据落在自己指定的宿主目录",就必须按第 3.2 节所述在 shell 中导出UPLOAD_LOCATION;不设置也能启动,但数据会进入 Docker 命名卷。
数据库变量则通过覆盖层注入(container-compose-overrides.yml第 26-31 行):POSTGRES_PASSWORD/POSTGRES_USER/POSTGRES_DB分别映射${DB_PASSWORD-postgres}、${DB_USERNAME-postgres}、${DB_DATABASE_NAME-immich},并显式设置POSTGRES_HOST_AUTH_METHOD: md5。
五、镜像构建与自动启动流程
5.1 开发镜像:server/Dockerfile.dev
Dev Container 的容器基于该 Dockerfile 构建,关键目标:
dev(第 2-26 行):基于 Immich 官方定制基础镜像ghcr.io/immich-app/base-server-dev,预装 mise 工具管理器;把 pnpm store、node-gyp 与 mise 数据目录全部指向/buildcache,该目录与 Compose 中的build_cache卷对应,跨容器复用依赖缓存以加速重复安装;dev-container-server(第 28-40 行):后端/前端 Dev Container 使用的最终目标,安装 OpenJDK 21、vim 等工具,把.devcontainer/server/*.sh脚本复制进/immich-devcontainer/,工作目录设为/workspaces/immich(符号链接指向/usr/src/app);dev-container-mobile(第 42-81 行):在 server 目标之上加装指定版本的 Flutter SDK 与 dcm 构建缓存工具,供 .devcontainer/mobile/devcontainer.json 定义的移动端 Dev Container 使用(remoteUser为node,并预装 Dart/Flutter/dcm 扩展)。
5.2 VS Code Tasks 驱动的常驻服务
.devcontainer/devcontainer.json通过customizations.vscode.settings.tasks注入了三个任务,其中两个标记了runOptions.runOn: "folderOpen",即打开容器时自动启动,并且都是isBackground常驻任务:
- Immich API Server (Nest)→ 执行
/immich-devcontainer/container-start-backend.sh; - Immich Web Server (Vite)→ 执行
/immich-devcontainer/container-start-frontend.sh; - Build Immich CLI→
pnpm --filter @immich/cli build:dev(按需手动运行)。
对照文档"自动设置"小节的描述,从源码看当前仓库的实际初始化分工是:依赖安装与启动全部收敛在这两个启动脚本里(文档提到的container-server-post-create.sh脚本在当前仓库中已不存在,其职责被下述脚本与immich-init容器取代)。
5.3 启动脚本的实现细节
container-common.sh 提供公共逻辑:IMMICH_WORKSPACE=/usr/src/app、API 端口IMMICH_PORT(默认 2283)、Web 端口DEV_PORT(默认 3000),并把所有命令输出带时间戳写入$HOME/immich-devcontainer.log便于事后排障。
container-start-backend.sh 的核心循环:
run_cmd pnpm --filter immich install # 安装后端依赖 cd "${IMMICH_WORKSPACE}/server" while true; do run_cmd pnpm --filter immich exec nest start --debug "0.0.0.0:9230" --watch # 崩溃后 3 秒自动重启 sleep 3 done即 Nest API 以--watch热重载模式启动,进程异常退出会被自动拉起重启。
container-start-frontend.sh 则体现了一条有依赖顺序的启动链:先pnpm --filter @immich/sdk install/build(TypeScript SDK)、@immich/plugin-sdk install/build(插件 SDK),再pnpm --filter immich-web install;随后轮询等待 API 就绪——反复请求http://127.0.0.1:2283/api/server/config直到成功,最后以vite dev --host 0.0.0.0 --port 3000循环拉起 Web 前端。这也解释了为什么 Web 任务不担心与 API 竞争启动顺序。
5.4 端口转发
devcontainer.json的forwardPorts: [3000, 9231, 9230, 2283]与portsAttributes标注了各端口语义(第 91-110 行):3000 为前端 HTTP(配置了onAutoForward: "openBrowserOnce",首次转发时自动打开浏览器),2283 为 API,9231 为 API 调试,9230 为 Workers 调试。
六、开发工作流与服务访问
6.1 运行中服务的访问地址
| 服务 | 地址 | 说明 |
|---|---|---|
| Web UI | http://localhost:3000 | 主界面;其/api路径反向代理到后端 |
| API | http://localhost:2283 | REST API(通常不直接访问) |
| PostgreSQL | localhost:5432 | 默认用户postgres |
6.2 代码变更的反馈方式
- 服务端代码(
server/):nest start --watch触发自动重编译;进程崩溃由启动脚本 3 秒后自动重启; - Web 代码(
web/):Vite 提供热模块替换(HMR); - 数据库迁移:运行
mise //server:sql同步 schema; - API 变更后:用
mise //:open-api重新生成 OpenAPI 规范与 SDK。
文档特别指出:Dev Container 方案取代了传统设置中的mise dev命令——所有服务在打开容器时自动启动。
6.3 连接移动 App 联调
把手机/模拟器连到 Dev Container:
- 查宿主机局域网 IP:macOS 用
ipconfig getifaddr en0,Linux 用hostname -I,Windows(WSL2) 用ip addr show eth0; - 在移动 App 中配置服务器地址
http://YOUR_IP:2283/api(文档中另一处写作http://YOUR_IP:3000/api,两者最终都可达后端:3000 由 Web 层代理/api,2283 直连 Nest API;实际防火墙需放行的端口与所用地址一致); - 移动端更完整的开发流程(Flutter 环境、模拟器运行、移动端调试)参见 setup.md;仓库还单独提供了移动端专用 Dev Container 配置 .devcontainer/mobile/devcontainer.json,其镜像目标
dev-container-mobile已内置 Flutter SDK 与 dcm。
七、测试与常用命令
Dev Container 内的终端可直接使用 mise 任务(容器内已预装 mise 与工具链):
# Server mise //server:test # 单元测试 mise //server:test-medium # 中等/集成测试 # Web mise //web:test # 单元测试 # E2E mise //e2e:test # API 测试 mise //e2e:test-web # Web UI 测试(Playwright) # 对某组件执行完整检查清单 mise //server:checklist mise //web:checklist # API 生成 mise //:open-api # 生成 OpenAPI 规范 mise //:open-api-typescript # 生成 TypeScript SDK mise //:open-api-dart # 生成 Dart SDK # 数据库 mise //server:sql # 同步数据库 schema对应的测试代码可在 server/test/medium/(中型集成测试)、e2e/src/specs/(API 与 Web 的端到端测试)中找到,与上述命令一一对应。
八、调试(Debugging)
Dev Container 预配置了 Node.js 远程调试端口,与devcontainer.json中portsAttributes的标注一致:
- API 服务调试:在 VS Code 中设置断点,按
F5打开 "Run and Debug",选择 "Attach to Server" 配置;调试端口9231。对照 container-start-backend.sh,Nest 以--debug "0.0.0.0:9230"参数启动,端口参数在 Compose 中同时映射了 9230 与 9231 两个调试入口; - Workers 调试:使用 "Attach to Workers" 配置,调试端口9230;
- Web 调试:使用浏览器 DevTools;VS Code 也支持对 Chrome/Edge 扩展进行调试。
九、Git 认证与提交签名
SSH 密钥转发:在宿主机启动 ssh-agent 并加载密钥:
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_rsa # 或你的密钥路径VS Code 会自动把宿主机 SSH agent 转发进容器,容器内的git push/fetch即可复用你的 GitHub 凭据。
提交签名(Commit Signing):如需在容器内用 SSH 密钥签名提交,按 GitHub 官方文档配置user.signingkey与commit.gpgsign即可;签名相关配置同样来自你 shell 中的 git 全局配置或GIT_CONFIG_*环境变量。
十、排障指南
文档整理了五类常见问题,结合仓库实现给出验证路径:
权限错误(EACCES)
后端 Dev Container 以root身份进入(devcontainer.json中remoteUser: "root"),而工作区挂载卷的属主可能不同,导致node用户写文件失败。解决:确认宿主目录属主,或执行 "Dev Containers: Rebuild Container" 重建容器;检查日志文件$HOME/immich-devcontainer.log(由container-common.sh写入)定位具体失败命令。
容器无法启动
docker ps确认 Docker 在运行;docker system prune -a清理资源;- 检查磁盘空间(至少 20GB);
- 检查 Docker Desktop 资源上限(内存/CPU)。首次构建
immich-server-dev镜像体积较大,资源不足时最容易卡死在构建阶段。
端口被占用("Port 3000/2283 is already in use")
lsof -i :3000(macOS/Linux)查冲突进程;- 停掉冲突服务或修改端口映射(同时改
docker-compose.dev.yml的ports与devcontainer.json的forwardPorts); - 重启 Docker Desktop。
UPLOAD_LOCATION未设置
容器可以启动(数据落入命名卷),但若报缺失/写入错误:
export UPLOAD_LOCATION=./Library(或绝对路径);- 写入 shell 配置持久化;
- 重启终端与 VS Code,然后 Rebuild 容器。
数据库连接失败
docker ps确认immich_postgres在运行;- 查看 "Dev Containers: Show Container Log";
- 核对
DB_PASSWORD/DB_USERNAME/DB_DATABASE_NAME与POSTGRES_*注入值一致(见container-compose-overrides.yml第 26-31 行)。
求助路径:View → Output → "Dev Containers" 查看日志;"Rebuild Container Without Cache" 强制无缓存重建;仍无法解决可在 Immich 官方 Discord 的#contributing频道提问。
十一、进阶配置
11.1 自定义 VS Code 扩展
在 .devcontainer/devcontainer.json 的customizations.vscode.extensions数组中追加扩展 ID。当前仓库已预装 ESLint、Prettier、Svelte、Playwright、Docker 等 12 个扩展,可直接照葫芦画瓢。
11.2 添加额外服务
若要在 Dev Container 中新增服务(例如 Redis 可视化工具),需要同时改两处:
- docker/docker-compose.dev.yml —— 添加服务定义;
.devcontainer/server/container-compose-overrides.yml—— 按需添加覆盖(例如重置env_file、调整volumes),并把服务名加入devcontainer.json的runServices。
11.3 资源限制
macOS/Windows 在 Docker Desktop → Settings → Resources 调整;Linux 修改 Docker daemon 配置。文档给出的最低建议:4 核 CPU、8GB 内存、20GB 磁盘。
十二、延伸阅读与关键文件索引
- 架构总览:architecture.mdx
- 数据库迁移:database-migrations.md
- 传统 Compose 开发环境:setup.md
- 开发者排障:troubleshooting.md
本文涉及的关键仓库文件:
| 文件 | 作用 |
|---|---|
| docs/docs/developer/devcontainers.md | 本文依据的官方 Dev Container 指南 |
| .devcontainer/devcontainer.json | 主 Dev Container 配置(服务、端口、remoteEnv、tasks) |
| .devcontainer/server/container-compose-overrides.yml | 覆盖层:挂载解析与 Postgres 变量注入 |
| docker/docker-compose.dev.yml | 开发 Compose 基础定义(init/server/web/ML/redis/db) |
| server/Dockerfile.dev | 开发镜像:dev / dev-container-server / dev-container-mobile 三目标 |
| .devcontainer/server/container-start-backend.sh | API 服务安装与常驻启动脚本 |
| .devcontainer/server/container-start-frontend.sh | SDK 构建、API 就绪等待与 Vite 启动脚本 |
| .devcontainer/mobile/devcontainer.json | 移动端 Dev Container 配置 |
适用前提提示:本文描述基于当前仓库快照中的.devcontainer与 Compose 配置;Dev Container 方案要求 Docker 可用且能拉取 Immich 定制基础镜像(PostgreSQL 定制镜像、ML 镜像构建较重),首次构建耗时明显长于普通项目,建议按前置条件一节预留内存与磁盘。
【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immich
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考