Claude-Mem Docker 部署实战:server-beta 运行时、Postgres/Valkey 栈与 HTTP/Worker 分离架构
本文基于仓库中的 docs/docker.md 及配套 Compose 文件、Dockerfile 与入口脚本,讲解如何用 Docker 部署 Claude-Mem 的 server-beta 运行时:一条 docker compose up --build 拉起「Postgres(持久存储)+ Valkey(BullMQ 队列)+ HTTP 服务 + 生成 Worker」的完整栈,通过 /healthz 验证健康状态,并创建 API Key 打通受保护的 V1 写路由。读完本文,你将掌握该 Docker 栈的全部必填密钥、关键环境变量含义、server/worker 分离原理,以及容器内鉴权与安全约束。
一、快速启动:最小可运行流程
docs/docker.md 给出的核心操作只有四步:
docker compose up --build
curl http://127.0.0.1:37777/healthz
仓库根目录的 docker-compose.yml 定义了这套可部署栈(注释中称为 "Phase 10 — server-beta deployable runtime")。文档中列出的容器关键环境变量是:
CLAUDE_MEM_WORKER_HOST=0.0.0.0CLAUDE_MEM_DATA_DIR=/data/claude-memCLAUDE_MEM_QUEUE_ENGINE=bullmqCLAUDE_MEM_REDIS_URL=redis://valkey:6379CLAUDE_MEM_AUTH_MODE=api-key
以及最后一条硬性要求:在使用受保护的 V1 写路由之前,必须先在容器内创建 API Key。
需要说明一个版本差异:docs/docker.md 示例中的探测端口是 37777,而当前仓库的 docker-compose.yml 实际映射并健康检查的端口是 37877(ports: "37877:37877",healthcheck 执行 curl -fsS http://127.0.0.1:37877/healthz)。因此以当前 Compose 文件为准,验证命令应为:
curl http://127.0.0.1:37877/healthz
健康检查路由本身在 ServerV1Routes.ts 中注册,无需鉴权,直接返回 { status: 'ok' };/v1/info 也会暴露服务名、版本、运行时和当前 authMode。
二、栈的组成:四个服务与三个命名卷
docker-compose.yml 实际包含四个服务,比文档的「Server + Valkey sidecar」描述更完整:
| 服务 | 镜像/构建 | 职责 |
|---|---|---|
postgres |
postgres:17-alpine |
规范存储(canonical storage),数据落在 postgres-data 卷 |
valkey |
valkey/valkey:8-alpine |
BullMQ 队列后端,启用 AOF(--appendonly yes --appendfsync everysec)与 --maxmemory-policy noeviction,数据落在 valkey-data 卷 |
claude-mem-server |
由 docker/claude-mem/Dockerfile 构建 | HTTP 服务,CLAUDE_MEM_GENERATION_DISABLED=true,不做生成 |
claude-mem-worker |
同一镜像 | BullMQ 生成消费者,从队列消费并产出观察(observations) |
几个工程细节值得注意(均来自 docker-compose.yml 头部注释与服务定义):
- 崩溃自愈:所有长驻服务声明
restart: unless-stopped,容器因 OOM、panic 或依赖瞬时故障崩溃后会自动拉起; - 启动顺序:server 通过
depends_on的condition: service_healthy等待 Postgres 与 Valkey 的健康检查通过,worker 又额外等待 server 健康(L96-L100、L146-L152); - Redis URL 有兜底:
CLAUDE_MEM_REDIS_URL: ${CLAUDE_MEM_REDIS_URL:-redis://valkey:6379},未设置时默认指向栈内 valkey,可通过同名变量覆盖为外部 Redis; - 数据卷:server 与 worker 共享
claude-mem-data卷,挂载到/data/claude-mem,与CLAUDE_MEM_DATA_DIR=/data/claude-mem对应; - legacy 运行时永不启动:注释明确说明旧版
worker-service.cjs运行时在这套栈中 NEVER spawned,server 容器跑server-beta-service.cjs --daemon,worker 容器跑server-beta-service.cjs worker start。
三、必填密钥:缺一个就拒绝启动
Compose 文件把 Postgres 凭据定义为「无默认值的必填环境变量」,使用了 ${VAR:?message} 的 fail-fast 语法(docker-compose.yml):
POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
POSTGRES_DB: ${POSTGRES_DB:?POSTGRES_DB is required}
因此启动方式必须二选一:
# 方式一:.env 文件
echo 'POSTGRES_USER=mem
POSTGRES_PASSWORD=change-me
POSTGRES_DB=mem' > .env
docker compose up --build
# 方式二:内联传入
POSTGRES_USER=mem POSTGRES_PASSWORD=change-me POSTGRES_DB=mem docker compose up --build
文件头注释明确警告:此文件不得原样部署到任何公网可达环境(包括 VPN 可达的 staging),缺失任一必填密钥时栈会直接拒绝启动。此外还支持(注释掉的可选配置)通过 CREDENTIALS_FILE 把提供者/API 密钥以只读文件挂载到 /run/secrets/claude-mem-credentials,替代内联环境变量。
四、环境变量全解:server 与 worker 的差异
文档列出的 5 个变量是精简版;结合 docker-compose.yml,完整的关键变量如下:
| 变量 | 取值(server) | 说明 |
|---|---|---|
CLAUDE_MEM_CONTAINER_MODE |
server / worker |
容器模式选择,决定 entrypoint 分支(见下一节) |
CLAUDE_MEM_DOCKER |
"1" |
标记容器环境,启动校验会据此拒绝 local-dev 鉴权并强制完整 Postgres+Valkey 配置 |
CLAUDE_MEM_RUNTIME |
server-beta |
固定运行时,由 validateServerBetaEnv() 启动时校验 |
CLAUDE_MEM_HOST / CLAUDE_MEM_SERVER_HOST |
0.0.0.0 |
监听地址,容器内必须放开到 0.0.0.0 才能被端口映射访问 |
CLAUDE_MEM_SERVER_PORT |
"37877" |
server-beta 运行时端口,即 compose 映射与 healthcheck 使用的端口 |
CLAUDE_MEM_WORKER_HOST / CLAUDE_MEM_WORKER_PORT |
0.0.0.0 / "37877" |
注释标注为「旧库仍在读取的 legacy 变量」,与 server 端口保持对齐,保证既有 E2E 驱动与 viewer 继续工作 |
CLAUDE_MEM_DATA_DIR |
/data/claude-mem |
数据目录,对应 claude-mem-data 卷 |
CLAUDE_MEM_QUEUE_ENGINE |
bullmq |
队列引擎,绑定 Valkey |
CLAUDE_MEM_REDIS_URL |
redis://valkey:6379(可覆盖) |
队列后端地址 |
CLAUDE_MEM_REDIS_MODE |
docker |
Redis 连接模式 |
CLAUDE_MEM_SERVER_DATABASE_URL |
postgres://user:pass@postgres:5432/db |
由必填密钥拼装出的数据库连接串 |
CLAUDE_MEM_AUTH_MODE |
api-key |
Docker 内唯一被允许的鉴权模式,local-dev 会被启动校验拒绝 |
CLAUDE_MEM_CHROMA_ENABLED |
"false" |
栈内不启用 Chroma 向量存储 |
CLAUDE_MEM_GENERATION_DISABLED |
"true"(仅 server) |
HTTP 服务不消费 BullMQ 任务,避免 provider 调用拖慢 HTTP 延迟;worker 端由 entrypoint 主动 unset 该变量强制启用生成 |
worker 服务额外注入生成所需的 provider 配置(docker-compose.yml):
CLAUDE_MEM_SERVER_PROVIDER: ${CLAUDE_MEM_SERVER_PROVIDER:-claude}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
CLAUDE_MEM_ANTHROPIC_API_KEY: ${CLAUDE_MEM_ANTHROPIC_API_KEY:-}
GEMINI_API_KEY: ${GEMINI_API_KEY:-}
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
注释说明:ANTHROPIC_API_KEY(或 CLAUDE_MEM_ANTHROPIC_API_KEY)是真实生成所必需的,缺失时 worker 保持运行但不会产出任何观察。
Compose 头部还解释了两种鉴权路径的成本差异(docker-compose.yml):
- API-KEY 模式(本栈默认):每个请求携带
server api-key create创建的 bearer key,生成消耗配置的 provider API key,按 token 计费,高观察量下可能费用可观; - SUBSCRIPTION 模式:把生成 provider 指向 Claude 订阅/Pro 会话而非按量计费的 API key,以规避 token 成本;HTTP 侧的 bearer 鉴权契约不变。
五、一个镜像,三种角色:entrypoint 如何切换模式
server 和 worker 使用同一份 Dockerfile 构建的行为差异,全部由 entrypoint.sh 通过 CLAUDE_MEM_CONTAINER_MODE 分派(L37-L60):
# CLAUDE_MEM_CONTAINER_MODE=server (默认) — HTTP server-beta,无 worker
# CLAUDE_MEM_CONTAINER_MODE=worker — 仅 BullMQ 生成 worker
# CLAUDE_MEM_CONTAINER_MODE=shell — 透传到 "$@",用于运维工具
case "$MODE" in
server) exec bun "$SERVER_BETA_SCRIPT" --daemon ;;
worker) unset CLAUDE_MEM_GENERATION_DISABLED
exec bun "$SERVER_BETA_SCRIPT" worker start ;;
shell|tooling) exec "$@" ;;
esac
其中 $SERVER_BETA_SCRIPT 指向 /opt/claude-mem/scripts/server-service.cjs(即仓库中打包后的 plugin/scripts/server-service.cjs)。worker 分支里那句 unset CLAUDE_MEM_GENERATION_DISABLED 很关键:它保证即使共享的 compose 文件给全局设置了「禁用生成」,worker 进程自身一定是生成进程。
entrypoint 还处理了凭据注入:若设置了 CLAUDE_MEM_CREDENTIALS_FILE 且文件存在,则把它复制为 $HOME/.claude/.credentials.json 并 chmod 600;文件不存在时直接报错退出。随后 entrypoint 会导出 CLAUDE_MEM_DOCKER=1 与默认 CLAUDE_MEM_RUNTIME=server-beta,与 /.dockerenv 的双重检测一起确保容器内环境校验严格生效(entrypoint.sh)。
六、镜像内容:Dockerfile 里装了什么
docker/claude-mem/Dockerfile 基于 node:20,安装顺序与要点:
- 系统依赖:
git curl ca-certificates unzip jq less procps uuid-runtime sqlite3; - Bun 1.3.12(
BUN_VERSIONbuild-arg 可覆盖)安装到/usr/local/bun,作为 server-beta 运行时的 JS 运行时; - uv 0.11.7(
UV_VERSIONbuild-arg)安装到/usr/local/bin,为可能需要的 Python 工具链提供环境; - 以
node用户全局安装@anthropic-ai/claude-code(CLAUDE_CODE_VERSIONbuild-arg,默认latest,建议 CI 中钉死版本); COPY plugin/ /opt/claude-mem/后执行npm install --omit=dev --legacy-peer-deps——分层顺序是刻意的:插件文件放在npm install层之后,迭代插件不会击穿 CLI 安装缓存(见 docker/claude-mem/README.md);- 预建
/home/node/.claude、/home/node/.claude-mem、/data/claude-mem三个挂载点,WORKDIR /home/node,ENTRYPOINT指向 entrypoint。
七、鉴权链路:从 API Key 创建到 V1 路由保护
docs/docker.md 的最后一句要求「先创建 API Key 再用 V1 写路由」。仓库中完整的做法是(参见 docs/server.md):
claude-mem server api-key create \
--name "ci" \
--scope memories:read,memories:write
- 原始 key 只显示一次,Postgres 的
api_keys.key_hash里只存 SHA-256 哈希; - 吊销用
claude-mem server api-key revoke <id>;每次请求都会按哈希重新加载数据库行做校验,没有可被投毒的内存缓存; - 路由层的对应实现在 ServerV1Routes.ts:读路由(如
GET /v1/projects)用requireServerAuth(..., { requiredScopes: ['memories:read'] }),写路由(如POST /v1/projects、POST /v1/sessions/start)要求memories:write;而/healthz与/v1/info在鉴权之外。项目级 key 被明确禁止创建项目(返回 403)。
安全约束上,docs/server.md 给出了 Docker 场景下最重要的一条红线:不要在容器内启用 CLAUDE_MEM_AUTH_MODE=local-dev——loopback 绕过依赖请求来自 127.0.0.1,这个边界在容器内没有意义;启动校验器对「Docker + local-dev」组合会直接以非零退出码拒绝启动。
八、横向扩展生成与 E2E 验证
生成吞吐通过扩 worker 容器数实现,这是 HTTP/生成分离架构的直接收益:
docker compose up -d --scale claude-mem-worker=N
仓库还自带一个 E2E 覆盖层 docker-compose.e2e.yml:新增一个 node:20-alpine 的一次性容器 server-e2e,等三个核心服务全部 healthy 后,以 E2E_BASE_URL=http://claude-mem-server:37877 跨 compose 网络调用 docker/e2e/server-e2e.mjs,配套的宿主机驱动脚本是 scripts/e2e-server-docker.sh。
九、区分:docker/claude-mem 下的单容器调试 harness
注意不要与根目录 Compose 栈混淆:docker/claude-mem/ 下的 run.sh + entrypoint.sh 是另一套单容器端到端调试工具——run.sh 按「ANTHROPIC_API_KEY → macOS Keychain → ~/.claude/.credentials.json」的顺序提取凭据,以只读文件挂载进容器,把宿主机的 .docker-claude-mem-data 目录持久化,退出后可以用 sqlite3 .docker-claude-mem-data/claude-mem.db 'select count(*) from observations' 检查捕获到的观察。它用于不污染宿主机地跑通 claude --plugin-dir /opt/claude-mem 全流程,而不是生产部署;生产与可部署验证请以根目录 docker-compose.yml 为准。
十、小结
这套 Docker 部署方案的要点可以浓缩为五条:
docker compose up --build拉起 Postgres 17 + Valkey 8 + server-beta HTTP 服务 + BullMQ worker 四件套,curl http://127.0.0.1:37877/healthz验证;POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB必填、无默认值,缺失即拒绝启动;CLAUDE_MEM_AUTH_MODE在容器内只能取api-key,local-dev会被启动校验拒绝;- 受保护 V1 路由使用前必须
claude-mem server api-key create,原始 key 仅显示一次,只存哈希; - HTTP 服务禁用生成、worker 容器专职消费队列,用
--scale claude-mem-worker=N横向扩展生成吞吐。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00