首页
/ claude-mem Docker 测试容器完全指南:构建、认证、版本锁定与运行模式解析

claude-mem Docker 测试容器完全指南:构建、认证、版本锁定与运行模式解析

2026-09-06 10:10:25作者:明树来

docker/claude-mem 是 claude-mem 仓库内置的一个最小化 Docker 测试容器(harness):它在隔离的环境里启动 Claude Code CLI 与本地构建的插件,让 AI 生成的 observations 落入一个可丢弃的 SQLite 库,结束后你可以直接把数据库拿到宿主机上检查。读完本文,你将掌握该镜像的完整构建流程、三级认证回退机制、可复现的版本锁定参数、容器三种运行模式(server / worker / shell)的切换方式,以及手动 docker run 的全部变体。

一、Docker harness 的定位与文件组成

该目录的设计目标很明确(见 README):"A minimal container for exercising claude-mem end-to-end without polluting your host"——它不是开发环境,只提供启动 claude 并捕获 observations 所需的最小运行时。目录内共 4 个文件,各司其职:

文件 职责
Dockerfile 镜像定义(node:20 + Bun + uv + Claude Code CLI + 本地 plugin/
build.sh 先执行 npm run build 再执行 docker build,镜像 tag 默认为 claude-mem:basic
entrypoint.sh 容器内入口。若挂载了 OAuth 凭据则写入 $HOME/.claude/,然后 exec "$@" 或按模式启动服务
run.sh 宿主机侧启动器。按优先级提取凭据(Keychain → 文件 → 环境变量),挂载持久化数据目录,进入交互 shell

build.sh 的实际逻辑(build.sh)会先切换到仓库根目录执行 npm run build,保证 plugin/ 目录是最新编译产物后再交给 docker buildrun.sh 则在运行时通过 SCRIPT_DIR/../.. 推导仓库根目录,并据此设置默认数据目录 $REPO_ROOT/.docker-claude-mem-datarun.sh)。

二、快速上手:构建与运行

从仓库根目录执行:

docker/claude-mem/build.sh
docker/claude-mem/run.sh

run.sh 会把你带进容器内的 bash,其中 claude 已在 PATH 上,插件预置于 /opt/claude-mem。启动会话时使用:

claude --plugin-dir /opt/claude-mem

会话结束后,SQLite 数据库留在宿主机的 ./.docker-claude-mem-data/claude-mem.db,可用 sqlite3 直接验证 observations 是否被捕获:

sqlite3 .docker-claude-mem-data/claude-mem.db 'select count(*) from observations'

需要注意一个入口行为:从 entrypoint.sh 的源码看,CLAUDE_MEM_CONTAINER_MODE 的默认值是 server,此时容器会 exec bun /opt/claude-mem/scripts/server-service.cjs --daemon 启动 server-beta 运行时而不是进入 shell。若要获得 README 快速开始中描述的交互 shell 体验,需要把模式切到 shell(或别名 tooling),该模式在无参数时 exec bash,有参数时 exec "$@"

三、镜像解剖:运行时、层级与缓存设计

README 说明镜像布局对标 anthropics/claude-code 的 devcontainer:FROM node:20、非 root 的 node 用户、全局安装 @anthropic-ai/claude-code;同时去掉了防火墙、zsh、fzf、delta、git-hist 等编辑向工具,因为"这个镜像是为了跑 claude-mem,而不是写代码"。

对照 Dockerfile 逐层验证:

  1. 基础层(L2-L17):node:20 + apt 安装 git curl ca-certificates unzip jq less procps uuid-runtime sqlite3,其中 sqlite3 正是快速开始里检查 DB 所依赖的客户端。
  2. Bun 运行时(L19-L23):通过官方 bun.sh/install 脚本安装到 /usr/local/bun,这是 claude-mem worker/service 脚本(如 server-service.cjs)的运行环境,PATH 已前置。
  3. uv(L25-L29):通过版本化安装脚本装到 /usr/local/bin,为 Chroma 向量检索提供 Python 运行时。
  4. Claude Code CLI(L31-L38):先切到 node 用户再执行 npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION},npm 全局前缀指向 /usr/local/share/npm-global
  5. 插件层(L41-L46):以 root 身份 COPY plugin/ /opt/claude-mem/ 并归还属主,再以 node 用户执行 npm install --omit=dev --legacy-peer-deps
  6. 挂载点预创建(L49-L50):/home/node/.claude/home/node/.claude-mem/data/claude-mem
  7. 入口与模式(L52-L67):entrypoint 拷入 /usr/local/bin/claude-mem-entrypoint,并预置 CLAUDE_MEM_CONTAINER_MODE=serverCLAUDE_MEM_RUNTIME=server-beta

README 特别强调层级顺序是刻意为之:插件文件放在 npm install 层之后,这样在插件上反复迭代时不会击穿 CLI 安装层的构建缓存,显著提升开发迭代速度。

四、版本锁定:用 build-arg 换取可复现性

镜像中一切影响可复现性的组件都暴露为 --build-arg——需要复现时锁定,追求最新时省略即可:

docker build \
  -f docker/claude-mem/Dockerfile \
  --build-arg BUN_VERSION=1.3.12 \
  --build-arg UV_VERSION=0.11.7 \
  --build-arg CLAUDE_CODE_VERSION=1.2.3 \
  -t claude-mem:basic .
Arg 默认值 说明
BUN_VERSION 1.3.12 通过官方 bun.sh/install 脚本安装,tag 为 bun-v${BUN_VERSION}
UV_VERSION 0.11.7 通过带版本号的 astral.sh/uv/${UV_VERSION}/install.sh 安装
CLAUDE_CODE_VERSION latest npm tag 或精确版本号。建议在 CI 中锁定,本地可让其浮动

这三个默认值与 Dockerfile 中的 ARG BUN_VERSION=1.3.12ARG UV_VERSION=0.11.7ARG CLAUDE_CODE_VERSION=latest 一一对应。其中 Bun 的安装命令带 -s "bun-v${BUN_VERSION}" 参数(L21),uv 的安装 URL 直接嵌入版本号(L28),因此两个默认值天然是可复现的;而 CLAUDE_CODE_VERSION=latest 意味着每次构建的 CLI 版本可能不同,README 给出的实践建议是"CI 锁定、本地浮动"。

五、认证链:三级回退与临时凭据的安全处理

run.sh 按固定顺序选择第一个可用的认证源(run.sh):

  1. ANTHROPIC_API_KEY 环境变量——直接挂载进容器(CREDS_MOUNT_ARGS=(-e ANTHROPIC_API_KEY)),跳过 OAuth 凭据提取;
  2. macOS Keychain——仅在 unameDarwin 时执行 security find-generic-password -s 'Claude Code-credentials' -w
  3. ~/.claude/.credentials.json——旧版磁盘形式,仍存在于一些老 CLI 安装和迁移后的机器上。

当走凭据文件路径时,安全处理链条如下:

  • 凭据先写入 mktemp 生成的临时文件,并 chmod 600
  • 只读方式挂载到容器内 /auth/.credentials.json,同时注入 -e CLAUDE_MEM_CREDENTIALS_FILE=/auth/.credentials.json
  • 容器端 entrypoint.sh 在启动时检查该文件存在(缺失则报错退出),cp$HOME/.claude/.credentials.json 并再次 chmod 600
  • run.sh 通过 trap 'rm -f "$CREDS_FILE"' EXIT 在返回时删除宿主机临时文件。README 特别指出 docker run 被刻意没有 exec,目的正是让 EXIT trap 有机会触发。

若三级认证源全部落空,run.sh 会以错误退出,提示先在宿主机执行 claude login 或设置 ANTHROPIC_API_KEYrun.sh)。

六、手动 docker run(不经过 run.sh)

需要完全控制挂载与环境变量时,可以绕过 run.sh 直接调用镜像。OAuth 凭据文件方式:

docker run --rm -it \
  -v $(mktemp -d):/home/node/.claude-mem \
  -e CLAUDE_MEM_CREDENTIALS_FILE=/auth/.credentials.json \
  -v /path/to/creds.json:/auth/.credentials.json:ro \
  claude-mem:basic

API key 方式:

docker run --rm -it \
  -v $(mktemp -d):/home/node/.claude-mem \
  -e ANTHROPIC_API_KEY \
  claude-mem:basic

两个示例都把 /home/node/.claude-mem 挂到一个 mktemp -d 目录,保证数据落盘在宿主机且随时可弃;-e ANTHROPIC_API_KEY 不带值的形式表示透传宿主机已导出的同名变量。另外注意 run.sh 中有对应的 TTY 处理([[ -t 0 && -t 1 ]] 才加 -itrun.sh),手动调用时非交互场景应去掉 -it

七、环境变量速查表

变量 作用位置 用途
TAG build.shrun.sh 覆盖镜像 tag(默认 claude-mem:basic
HOST_MEM_DIR run.sh 覆盖宿主机持久化 .claude-mem 卷路径(默认 $REPO_ROOT/.docker-claude-mem-data
ANTHROPIC_API_KEY run.sh、entrypoint API key 认证,跳过 OAuth 凭据提取
CLAUDE_MEM_CREDENTIALS_FILE entrypoint 容器内已挂载 OAuth 凭据 JSON 的路径,启动时复制到 $HOME/.claude/.credentials.json

补充两个未在表中列出但由源码确认的容器内变量:

  • CLAUDE_MEM_DOCKER=1:entrypoint 强制导出(entrypoint.sh)。在服务端代码 create-server-service.ts 中,detectDockerEnvironment 会把 CLAUDE_MEM_DOCKER=1/true/.dockerenv 存在性都识别为 Docker 环境,其后果是环境校验拒绝 local-dev 认证旁路——"从源码结构看",因为容器可通过服务间网络与暴露端口被访问,回环地址假设不再成立;
  • CLAUDE_MEM_RUNTIME:entrypoint 以 server-beta 为默认导出,服务端校验只接受 server 或旧字面量 server-betacreate-server-service.ts)。

八、参数透传与清理

run.sh 后面的任何参数都会作为命令转发进容器,例如免交互直接提问:

docker/claude-mem/run.sh claude --plugin-dir /opt/claude-mem --print "what did we learn yesterday?"

用完后的清理动作:

rm -rf .docker-claude-mem-data   # 抹掉持久化 DB + Chroma 存储
docker rmi claude-mem:basic       # 删除镜像

九、容器运行模式与 server-beta 运行时

entrypoint.sh 通过 CLAUDE_MEM_CONTAINER_MODE 实现了三模式分发:

  • server(默认)exec bun /opt/claude-mem/scripts/server-service.cjs --daemon,运行 HTTP server-beta 运行时,不启动 legacy worker;
  • workerexec bun ... worker start,只跑 BullMQ 生成 worker(无 HTTP),并强制 unset CLAUDE_MEM_GENERATION_DISABLED——因为 worker 进程本身就是生成进程;
  • shell / tooling:落入 "$@",无参数时进入 bash,用于插件调试等工具类场景;
  • 其他值:打印 ERROR: unknown CLAUDE_MEM_CONTAINER_MODE=...exit 1

README 还给出了生产化拆分思路:在本服务上设置 CLAUDE_MEM_GENERATION_DISABLED=true,把生成任务拆到兄弟容器中的 claude-mem server worker start 进程里,实现 HTTP 服务与生成 worker 的水平分离。

与根目录 docker-compose.yml 的全量部署(见 docs/docker.md)相比,本 harness 是"单机验证"路线:compose 栈带 Valkey sidecar 与 api-key 认证、监听 37777 端口的 /healthz;而本目录镜像面向端到端观察捕获验证,两者共用同一套 CLAUDE_MEM_DOCKER / CLAUDE_MEM_RUNTIME 环境契约,但用途不重叠。

十、小结

docker/claude-mem 展示了测试容器设计的几个可复用要点:以 build-arg 显式暴露所有版本旋钮以换取可复现性;用"插件层后置"的层级顺序保护昂贵的 CLI 安装缓存;认证链按 Keychain → 磁盘文件 → 环境变量的确定优先级回退,并配合 chmod 600、只读挂载与 EXIT trap 形成完整的临时凭据生命周期;再以一个环境变量(CLAUDE_MEM_CONTAINER_MODE)切换 server / worker / shell 三种前台进程,让同一镜像既能做交互调试,也能拆分为服务与 worker 两个部署单元。所有脚本与镜像定义均为可读的 shell/多行 Dockerfile,适合作为自研 agent 插件的容器化测试参考。

登录后查看全文
热门项目推荐
相关项目推荐