openGym教练镜像构建指南:如何读懂 default 与 coach 双目标 Dockerfile
openGym教练镜像构建指南如何读懂 default 与 coach 双目标 Dockerfile【免费下载链接】openGymSelf-hosted gym body-weight tracker — plan routines, log workouts (supersets, warm-ups, cardio), see which muscles are trained, fatigued or detrained, import from FitNotes/Strong/Hevy, passkey login. Your data, your server.项目地址: https://gitcode.com/GitHub_Trending/op/openGymopenGym 是一款可自托管的健身与体重追踪应用规划训练计划、记录训练支持超级组、热身、有氧、查看哪些肌肉在被训练、疲劳或退化并可从 FitNotes / Strong / Hevy 导入数据支持 Passkey 登录。它的 AI Coach 功能内置在同一个 Dockerfile 里却拆成了两个构建目标default和coach——前者是不含任何 AI 运行时的“干净”镜像后者额外打包了 Claude Agent SDK 和 Codex CLI。本文带你快速搞懂这两个目标的设计思路以及构建、切换的正确姿势。一张镜像两种形态为什么要有双目标打开 api/Dockerfile 的第一行注释就是答案default不指定--target时的默认目标——每个实例一直都在用的形态没有 AI 运行时没有 AI 依赖coach——在同一个镜像基础上加上 Claude Agent SDK。设计动机非常务实default目标使用npm ci --omitoptional安装依赖从而完全跳过 api/package.json 中optionalDependencies里的anthropic-ai/claude-agent-sdk及其平台专属运行时。不想用 AI 教练的部署者镜像里就一个字节的 AI 运行时都没有。coach目标只多做了一件事去掉--omitoptional再补装 Codex CLI 及其沙箱依赖 bubblewrap。构建顺序也有讲究Docker 在未指定目标时会构建最后一个阶段所以default被刻意放在文件末尾coach位于它上面。普通docker build ./api产出的永远是轻量镜像。default 目标做对了哪些事default目标并非简单删东西而是几处刻意的取舍安全加固的coach用户。api/Dockerfile 中通过adduser -D -H -s /sbin/nologin coach创建了一个无权访问/data的非特权用户。它读取不到用户数据、Passkey 和会话密钥——即使 AI 任务在容器内以该用户运行也天然被隔离在数据之外。移除 npm 本体。镜像最终rm -rf掉了 npm 和 npx。原因写在注释里历史漏洞扫描报告里的问题全部来自 npm 自带的依赖树而应用只通过node server.js启动根本不跑 npm——教练目标保留 npmCodex CLI 需要默认目标则彻底清除。逐文件 COPY 而非整目录拷贝。api/Dockerfile 的COPY server.js push-messages.js …一行精确列出了 server.js 需要的每个根级模块。配套还有 api/test/dockerfile-copy.test.js 这个测试自动比对 import 链和 COPY 清单——漏掉任何一个模块只在镜像启动时才以ERR_MODULE_NOT_FOUND暴露测试则能在提交前发现。构建时升级 Alpine 包。apk upgrade --no-cache在构建时同步 Alpine 的安全补丁不依赖 node 基础镜像的重新构建节奏。构建 coach 镜像两条命令就够了通过 docker compose 构建推荐docs/SELF_HOSTING.md 的标准自托管流程是docker compose pull docker compose up -d。若要启用 AI 教练运行时docker-compose.yml 已经用API_TARGET变量预留好了开关API_TARGETcoach docker compose up -d --build api--build不能省compose 文件里同时声明了预构建image:和build:没有--build时 compose 会直接拉取默认的预构建镜像你的API_TARGETcoach形同虚设。直接 docker build 构建docker build --target coach ./api两条路径等价任选其一。前端镜像的构建则完全独立见 web/Dockerfile。coach 目标多了什么三个关键差异coach阶段从base派生新增内容可以数得过来差异点说明AI 运行时npm ci --omitdev不再省略 optional拉入 Claude Agent SDK 及 musl 平台运行时版本由 lockfile 锁定Codex CLI bubblewrapCodex 以 CLI 而非库形式存在需apk add bubblewrap其沙箱要求加全局安装 CLI/coach-auth卷Codex 的登录缓存目录归属coach用户、权限0700其中/coach-auth的位置值得注意它被刻意设计为./data的兄弟目录而非子目录——因为 docs/SELF_HOSTING.md 推荐的备份方式是tar czf … data/一个存活的 refresh token 不该搭备份的便车出现在每一份归档里。compose 文件中对应的挂载也写得很明白volumes: - ./data:/data # 用户、passkey、状态、会话密钥 —— 务必备份 - ./coach-auth:/coach-auth # 丢不了重新登录即可选哪个目标一张表说清根据 docs/AI_COACH.md 的 Provider 分类选择逻辑其实很简单你要用的 Provider需要的镜像Anthropic / OpenAI / Gemini API 密钥default一次 HTTPS 请求无子进程兼容端点Ollama、LM Studio、vLLM 等自托管模型defaultClaudeClaude Agent SDK走订阅 setup-tokencoachCodexOpenAI容器内设备登录coach也就是说只要用 API 密钥或本地模型default就够了只有想让 AI 运行时跑在容器内才需要coach镜像。常见问题速查构建后 Coach 卡片仍不出现先确认coach镜像真的生效docker compose config查看target再检查管理后台 AI Coach 卡片的总开关是否打开。docker compose restart改了.env不生效重启不会重读.env需用docker compose up -d。换回轻量镜像API_TARGETdefault docker compose up --build api或直接删除API_TARGET变量即可数据卷不受影响。镜像健康状态怎么看两个目标都继承了 base 阶段的HEALTHCHECK每 5 分钟探测/api/healthdocker inspect的State.Health一目了然。一个 Dockerfile、两种形态、按需启用——openGym 的双目标设计把“要不要 AI”这个决定交给了部署者而不是替你打包进镜像。读透 api/Dockerfile 里的注释你会看到不少值得借鉴的自托管工程细节。【免费下载链接】openGymSelf-hosted gym body-weight tracker — plan routines, log workouts (supersets, warm-ups, cardio), see which muscles are trained, fatigued or detrained, import from FitNotes/Strong/Hevy, passkey login. Your data, your server.项目地址: https://gitcode.com/GitHub_Trending/op/openGym创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考