跳至主要内容

Claude Code 与 Docker:在容器中运行 AI 代理

学习如何在 Docker 中运行 Claude Code,构建隔离环境。本完整指南助您掌握面向自主 AI 代理的安全编码实践。
· 14分钟 阅读

使用 AI 探索

自主型AI 编码代理功能强大。它们可以浏览您的文件系统、执行 shell 命令、提交更改并修改文件,且无需您亲自敲下一行代码。但强大的能力也带来一个现实问题:一旦出错会怎样?万一代理修改了本不该动的配置文件,或安装了与您系统冲突的软件包,该怎么办?

大多数注重生产环境的开发者最终选择 Docker。我自己也在一次特定的会话后不断回到这个答案——当时 Claude Code 很“贴心”地清理了我项目的 .env 文件,因为它看起来“未被使用”。(其实它并非未用。) 

容器在代理与宿主机之间提供了清晰的边界,而这种边界让无人值守的代理运行从焦虑变得踏实。 

在本教程中,我将带您在 Docker 中运行 Claude Code:从构建最小基线镜像,到使用Docker Compose编排多服务应用。完成后,您将拥有一套可复用且安全的工作流,可应用于任何项目。

如果您对最新的 Anthropic 模型感兴趣,推荐阅读我们的 Claude Opus 4.6 和 Claude Sonnet 4.6 指南。

Claude Code 如何与 Docker 集成

要理解为什么 Docker 与 Claude Code 天然契合,先简单弄清各自做什么会很有帮助。

Claude Code 是 Anthropic 推出的命令行代理式编码工具,于 2025 年 5 月正式发布。它驻留在您的终端,读取代码库,并通过自然语言提示执行任务(重构、编写测试、管理 git 工作流)。我们的Claude Code 2.1 全面教程涵盖所需的一切。

Docker 是一个用于打包和运行应用的平台,它通过轻量、隔离的容器共享宿主 OS 内核,但保持严格的进程与文件系统边界。如果您对 Docker 完全陌生,建议先在免费的 Play with Docker 平台上试验。

Claude Code 需要一个可运行的环境,Docker 则提供了可复现、一次性的环境。二者结合威力强大,但要用好它们,您需要了解执行模型、安全默认值,以及最适合您场景的部署方式。

容器架构与执行流程

先从请求层面看一次容器化的 Claude Code 会话是如何工作的。

  1. 您在宿主终端发出一个提示(prompt)。 
  2. Docker 启动预装 Claude Code CLI 的容器,并将您的工作区以卷(volume)挂载。 
  3. Claude Code 从该挂载读取文件,理解代码库,在容器隔离的进程空间内执行命令,并将输出写回挂载卷。 
  4. 会话结束后,容器的临时文件系统(挂载之外的所有内容)会被丢弃。

关键在于区分临时状态与持久状态。写入容器但不在挂载卷中的任何内容,清理时都会被删除。您的工作区位于宿主并被挂载进容器,因此会持久化。 

这意味着临时依赖、构建产物和工具安装都会消失,但您的项目文件会如同 Claude 留下时那样保持不变。对我来说,这种分离让人安心:在理解这一点之前,我总是紧张地盯着代理会话。现在,我下达任务就去泡咖啡。

安全模型与安全默认

在理解执行流程后,值得明确说明 Docker 的隔离实际能保护什么、不能保护什么。

文件系统隔离是主要的安全收益。Claude Code 只能读写您明确挂载的路径。如果您没有将它们挂载进容器,您的SSH 密钥、~/.aws 凭证、宿主环境变量以及系统配置文件对代理都是不可见的,除非您主动暴露它们。不过,这种保护前提是您谨慎配置挂载。

一条关键规则:切勿将宿主的 Docker 套接字(/var/run/docker.sock)挂载到 Claude Code 容器中。如果代理能与宿主的 Docker 守护进程通信,它就可能启动特权容器、完全逃离沙箱,并获得对您机器的 root 级访问。 

这是一个众所周知且没有正当理由的提权路径。我在一些社区 Dockerfile 中看到过这种做法,目的是让代理“管理容器”。每次看到我都想给作者发一条措辞强烈的消息。

选择合适的部署路径

抛开安全默认不谈,在写任何代码之前,您还需做一个决定:哪种部署模型适合您的用例?主要有三种选项,彼此并非可互换。

部署方式

最适合

关键取舍

Docker 沙箱(单容器)

隔离的、一次性代理任务

无服务间网络通信

Docker Compose

开发期多服务应用

配置更多,攻击面更广

Devcontainers

团队级标准化环境

需要 VS Code 或兼容 IDE

对于大多数任务(针对单个仓库运行代理、调试脚本、重构模块),纯 Docker 沙箱是最安全的默认选择。 

当 Claude Code 需要与正在运行的数据库、API 或前端服务交互时,Docker Compose 就有意义了。 

Devcontainers 适用于团队范围的标准化环境,并预装 IDE 扩展。值得注意的是,Anthropic 官方参考 devcontainer 内置防火墙,将出站连接限制在可信白名单内,也正因这种隔离,才能安全地以完全无人值守方式运行带有 --dangerously-skip-permissions 的 Claude Code。 

本教程将同时介绍单容器沙箱和 Compose 设置。

为 Claude Code 准备 Docker 容器

既然架构和部署选项已明确,我们就先确保环境配置妥当再写代码。我见过太多人跳过这一步,而这也是此类教程半途失败的最常见原因。

系统与软件要求

在第一次运行 docker build 前,您需要具备以下条件:

  • Docker Desktop(macOS 或 Windows)或 Docker Engine(Linux),且守护进程处于运行状态。macOS 与 Windows 需在 BIOS/固件中启用虚拟化。Linux 上请将您的用户加入 docker 组(sudo usermod -aG docker $USER),或在每条 Docker 命令前加 sudo。

  • 宿主机安装 Node.js v18 或更高版本,因为 Claude Code CLI 是一个 npm 包。用 node --version 确认。

  • 一把 Anthropic API 密钥,您可在 Claude Console 生成。

继续之前,先快速做一次健全性检查,确认 Docker 本身工作正常:

docker run --rm hello-world

如果看到 Hello from Docker!,说明守护进程响应正常,可以继续。

认证与环境变量

确认守护进程健康后,下一个关键是凭证。将 Anthropic API 密钥作为运行时环境变量注入,比在容器内交互式登录安全得多。 

我就是吃了这方面的亏:交互式登录可能把凭证写进容器层或 shell 历史文件里,长久保留在磁盘上,等您忘了它们还在。

正确的做法是在运行时用 -e 传入密钥:

docker run --rm -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" my-claude-image

注意这里从宿主 shell 引用了 $ANTHROPIC_API_KEY。密钥既不会写进 Dockerfile,也不会被提交到版本控制,更不会出现在任何镜像层中。您只需在 shell 配置(~/.zshrc 或 ~/.bashrc)里设置一次,之后它就会在每次容器运行时自动传入。

工作区初始化

认证搞定后,最后一步是创建干净的工作区。我总会为每次代理会话单独建一个目录,而不是直接指向现有项目,这能避免代理“走神”到您并不打算让它修改的临近代码中。

mkdir ~/claude-docker-tutorial
cd ~/claude-docker-tutorial
echo "# My Project" > README.md
echo "def hello(): return 'world'" > app.py

保持此目录干净。不要把真实的 .env 或任何凭证拷进去。工作区应只包含您希望代理处理的代码,别的都不要。准备就绪后,我们开始构建。

在 Docker 中运行 Claude Code

环境与概念都已就绪,现在开始构建。本节将带您依次完成:先是最小单容器镜像,然后是一个可用的沙箱会话,最后是完整的多服务 Compose 栈。各步骤相互递进,建议按顺序进行,而非直接跳到后面。

1. 构建基线容器镜像

本节一切都建立在我们先前讨论的安全原则之上。下面这个最小 Dockerfile 将这些原则付诸实践:在精简的 Node.js 基础镜像上安装 Claude Code CLI。

FROM node:20-slim

# Create a non-root user for safer execution
RUN useradd -m -u 1001 claude

# Install Claude Code CLI globally
RUN npm install -g @anthropic-ai/claude-code

# Set the working directory
WORKDIR /workspace

# Switch to non-root user
USER claude

ENTRYPOINT ["claude"]

这里有几点设计取舍值得说明。我使用 node:20-slim 而非 node:20-alpine,因为 Alpine 采用 musl libc,偶尔会与原生 npm 包产生兼容性问题。 

我在第一次用 Alpine 时就踩了这个坑:Claude Code CLI 能装上,但首次运行就以一个莫名其妙的链接器错误崩溃,我花了一个小时才追溯到 musl。 

slim 变体基于 Debian:轻量、可靠,不会有这些幺蛾子。此外,我创建了专用的 claude 用户并在入口前切换到它,这样代理进程就不会以 root 权限运行,即便在容器内也能限制其能力范围。

用如下命令构建镜像:

docker build -t claude-code:latest .

首次构建时,Docker 会拉取基础镜像并安装 CLI。之后只要 Dockerfile 未变,您会在每层旁看到“CACHED”,一旦基线构建完成,重建几乎是瞬时的。

2. 启动隔离的沙箱会话

镜像就位后,开始第一次真正的会话。 

只读操作

对于列出或总结文件等只读任务,基础命令足够:

docker run --rm \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  -v $(pwd):/workspace \
  claude-code:latest \
  "List the files in this workspace and describe what each one does."

-v $(pwd):/workspace 将当前目录挂载进容器,因此该命令可在任一项目目录中运行。--rm 会在容器退出后自动删除它。

写入操作

写入操作需要另外两个参数。 

-u $(id -u):$(id -g) 会把宿主用户的 UID 和 GID 传入容器,赋予 claude 进程写入您挂载文件的权限。没有它,您会遇到只读文件系统错误,因为容器内的 claude 用户与宿主文件所有权不匹配。 

--dangerously-skip-permissions 会跳过 Claude Code 的交互式审批提示,而在容器内非交互运行时这是必要的。正是 Docker 的边界让这一行为是安全的。

docker run --rm \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  -v $(pwd):/workspace \
  -u $(id -u):$(id -g) \
  claude-code:latest \
  --dangerously-skip-permissions \
  "Add a docstring to the hello function in app.py."

Claude Code Docker write operation

Claude Code 在 Docker 中的写入操作

随后检查本地文件:cat app.py。如果您看到了文档字符串,说明卷挂载已双向生效,可以升级到多服务设置。

3. 编排多服务应用

单容器沙箱适合独立任务,但真实开发往往涉及多服务同时运行。这正是 Docker Compose 大显身手之处。

下面的配置将 Claude Code 代理与一个 Web 服务和 PostgreSQL 数据库联通,是很多后端项目的典型组合:

services:
  claude:
    build: .
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
    volumes:
      - ./workspace:/workspace
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network

  web:
    image: python:3.12-slim
    working_dir: /app
    volumes:
      - ./workspace:/app
    command: python -m http.server 8080
    ports:
      - "8080:8080"
    networks:
      - app-network

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

注意这里省略了 version,因为在现代 Docker Compose 中它已过时,包含它反而会触发警告。 

还有两点值得指出:

首先,claude 服务挂载的是 .:/workspace(当前目录),不是子目录。若使用 ./workspace,就需要单独的子文件夹存在,否则代理会看到空工作区。 

其次,需要显式传入 DATABASE_URL,这样代理才知道如何连接 Postgres。没有它,Claude 没有连接串,会向您索要。

user: "${UID}:${GID}" 这行与我们在独立 docker run 命令中用到的宿主 UID/GID 覆盖相同,确保文件写入正常。在运行前先导出二者:

export UID=$(id -u) GID=$(id -g)

claude 服务没有持久性的 command,因此不同于 web 与 db,它并不打算常驻运行。先启动支撑服务,再通过 docker compose run 按需调用 Claude:

# Start the database and web service
docker compose up -d web db

# Run a one-off Claude task
docker compose run --rm \
  claude \
  --dangerously-skip-permissions \
  "Check the database connection and summarize the schema in README.md."

使用 Docker Compose 的 Claude Code

先用 docker compose up -d web db 启动支撑服务,再用 docker compose logs -f 观察日志。留意带有 condition: service_healthy 的 depends_on。 

我在早期一个项目中没加健康检查,结果花了 20 分钟追查数据库连接错误,最后才发现 Claude 先于 Postgres 就绪而启动。健康检查几乎没成本,却能省去这种麻烦。

4. 管理会话清理

会话完成后,清理与初始设置同样重要。孤立容器会占用内存并干扰后续运行。以我的经验,这一步往往被开发者忽视,直到出现异常行为。

以下是最常用的命令,以及各自的使用场景:

命令

作用

使用时机

docker compose down

停止并移除栈中的所有容器

每次 Compose 会话结束后

docker container prune

移除所有已停止的容器

如果独立运行时忘了加 --rm

docker compose down -v

移除容器、网络和命名卷

完全重置,清空数据库状态

docker ps

列出正在运行的容器

确认没有残留活动

需要注意的是 docker compose down 的 -v 标志。它会删除命名卷,意味着在 Postgres 中累积的任何数据库数据都会丢失。只有在我确实需要从零开始时才会使用它。其他情况下,仅 docker compose down 就足够了。

Claude Code 与 Docker 的集成与故障排查

在核心工作流稳定运行后,接下来看看如何扩展它,以及在出问题时如何调试。

集成本地模型与扩展

Claude Code 支持通过 ANTHROPIC_BASE_URL 将推理重定向到任意与 Anthropic 兼容的本地端点。内置于 Docker Desktop 的 Docker Model Runner 正好暴露了这样的 API,使集成天然契合 Docker 生态。

拉取模型并将 Claude Code 指向本地端点:

docker model pull ai/smollm2
ANTHROPIC_BASE_URL=http://localhost:12434 claude --model ai/smollm2 "List the files of the repository."

这和前面介绍的沙箱容器方法不同。此处,Claude Code 在您的宿主机上运行,推理通过 Docker Model Runner 留在本地,因此不会有 API 调用离开您的机器。

除了本地模型,您还可以通过 MCP(模型上下文协议)服务器扩展 Claude Code 的能力。如果您还不熟悉,参阅我们的MCP 指南是很好的起点。

Docker 的 MCP Toolkit 提供 200 多个预构建、容器化的 MCP 服务器,涵盖 GitHub、Jira、Supabase 等,让 Claude Code 在不暴露原始 API 凭证的前提下,获得对这些工具的受控访问。 

二者结合,让您既能控制推理发生在何处,也能控制代理可访问哪些外部服务。

优化构建性能

随着 Dockerfile 体量增长,构建时间可能成为瓶颈。多阶段构建通过将安装与运行时镜像分离来解决这个问题:

# Build stage
FROM node:20-slim AS builder
RUN npm install -g @anthropic-ai/claude-code

# Runtime stage
FROM node:20-slim
COPY --from=builder /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=builder /usr/local/bin/claude /usr/local/bin/claude
RUN useradd -m -u 1001 claude
USER claude
WORKDIR /workspace
ENTRYPOINT ["claude"]

层的顺序与结构同样重要,而我在这方面走了不少弯路。 

较少变化的指令(如安装系统包)应放在靠上位置;变化频繁的指令(如复制源文件)应放在靠下位置。这样可最大化缓存命中率,把 30 秒的重建压缩到近乎瞬时。

调试常见的集成故障

即便结构良好,也难免出错。以下是我最常遇到问题的可重复调试循环:先描述症状,再给出要运行的命令。

  • 出站网络被阻断:Claude Code 无法访问 Anthropic API。运行 docker run --rm alpine wget -qO- https://api.anthropic.com 验证出站访问。如果失败,检查 docker network inspect bridge 的代理设置。

  • 卷挂载不正确:Claude Code 报告找不到文件。运行 docker run --rm -v $(pwd):/workspace alpine ls /workspace。若列表为空,说明路径错误。先确认目录确实存在。

  • 构建缓存陈旧:您更新了 Dockerfile,但行为没变化。用 docker build --no-cache -t claude-code:latest . 强制全量重建。

  • Compose 中的服务间连接失败:某服务无法访问另一服务。服务之间通过服务名(db、web)通信,而不是 localhost。运行 docker compose exec web ping db 测试可达性。如失败,说明服务不在同一网络。

结语

在 Docker 中运行 Claude Code 带来真正的价值:您可以让自主代理自由工作,同时明确它能接触到的范围被严格限制。 

本教程介绍了如何构建最小的非 root 容器镜像、管理工作区卷、用 Docker Compose 编排多服务应用,以及诊断最常见的集成故障。 

这套设置我花了一个下午才打磨到位,但它完全改变了我使用代理辅助开发的方式。我现在会委派完整任务,而不是盯着每一步,Docker 的边界让这一切成为可能。

接下来,有两条方向值得探索:

首先,考察适合您团队的 devcontainer 模板。GitHub 上的Claude Code 参考 devcontainer 内置预配置的防火墙,将出站连接限制在可信域名。其次,试验 Docker MCP Toolkit,为 Claude Code 提供对您现有工具(GitHub、数据库、项目管理系统等)的结构化访问。

最后,记得定期更新基础镜像。Docker 镜像会随时间累积漏洞,执行一次 docker pull node:20-slim 并重建只需几分钟。

如果您对开发 AI 应用感兴趣,强烈建议报名我们的 AI Engineering with LangChain 技能路径。课程均为 AI 原生,您将获得一位陪伴式导师,根据您的实际水平帮助您以自己的节奏达成目标。

Claude Code Docker 常见问题

如何将 Claude Code 与 Docker Compose 集成?

在 Compose 文件中添加一个 claude 服务,将您的 API 密钥作为环境变量传入,并把项目目录作为卷挂载。使用 docker compose run --rm claude 按需调用它,而不是像 Web 或数据库服务那样让它持续运行。

Claude Code 在容器中如何处理权限与安全问题?

默认情况下,Claude Code 在写入文件前会请求确认。在容器内无法交互式应答这些提示,因此需要传入 --dangerously-skip-permissions 以跳过。Docker 的边界本身提供了安全保障:代理只能接触到您挂载的工作区文件。

Claude Code 只能使用 Anthropic 模型吗,能否使用自定义模型?

Claude Code 支持通过 ANTHROPIC_BASE_URL 自定义推理端点。您可以将其指向 Docker Model Runner,在本机上运行如 ai/smollm2 等模型,所有调用都不会离开宿主机。

在 Docker 中处理大型代码库的最佳实践是什么?

仅挂载代理所需的子目录,而非整个仓库;使用 CLAUDE.md 为代理提供项目结构的上下文;在会话内先运行 /init 让 Claude Code 索引代码库,再开始工作。

在复杂架构中使用 Claude Code 有哪些限制?

主要限制在于上下文窗口大小。Claude Code 只能推理其活动上下文能容纳的内容,因此非常大的代码库需要将任务限定在特定模块。对于多服务架构,服务必须位于同一 Docker 网络上,且 claude 服务需要显式提供任何所需的数据库或 API 连接串环境变量。

Benito Martin

作者

Benito Martin

作为 Martin Data Solutions 的创始人兼自由职业数据科学家、ML 与 AI 工程师,我在回归、分类、NLP、LLM、RAG、神经网络、集成方法和计算机视觉等领域拥有多元项目经验。

  • 成功交付多项端到端机器学习项目,覆盖数据清洗、分析、建模与在 AWS 和 GCP 上的部署,提供具备影响力且可扩展的解决方案。
  • 使用 Streamlit 和 Gradio 构建交互式、可扩展的网页应用,服务于不同行业场景。
  • 教授并指导数据科学与数据分析学员,通过个性化学习路径促进其职业成长。
  • 为企业级需求设计检索增强生成(RAG)应用课程内容。
  • 撰写高影响力的 AI 与 ML 技术博客,涵盖 MLOps、向量数据库和 LLM 等主题,并获得显著关注。

在我参与的每个项目中,我都会应用最新的软件工程与 DevOps 实践,如 CI/CD、代码规范检查、格式化、模型监控、实验追踪以及健壮的错误处理。我致力于交付完整的解决方案,将数据洞察转化为切实可行的策略,帮助企业成长,并充分发挥数据科学、机器学习与 AI 的价值。

主题