学习目标:掌握在Docker DevContainer中运行Claude Code的完整流程,从零搭建安全、可复现的AI辅助开发环境,适合希望用容器隔离AI Agent、统一团队开发环境的开发者。
适用人群:有一定终端操作基础的前端/后端/全栈开发者,了解基本Docker概念即可。
前置条件: - 操作系统:macOS / Linux / Windows(WSL2) - 已安装 Docker Desktop(≥24.0) - 已安装 VS Code(≥1.85)或支持DevContainer的编辑器 - Node.js ≥ 18(宿主机用于初始安装验证) - Anthropic API Key(需提前申请)
Claude Code是Anthropic推出的终端AI编程助手,它直接在你的项目中读取文件、运行命令、修改代码。这意味着它拥有与你相同的系统权限——这是便利,也是风险。
graph TB
subgraph 传统模式
A[宿主机文件系统] --> B[Claude Code]
B --> C[任意Shell命令]
C --> D[潜在风险:误删/越权/注入]
end
subgraph DevContainer模式
E[宿主机文件系统] -.挂载.-> F[容器内文件系统]
F --> G[Claude Code]
G --> H[受限Shell环境]
H --> I[安全隔离:资源受限/网络可控/权限最小化]
end
style D fill:#ff6b6b,color:#fff
style I fill:#51cf66,color:#fff
DevContainer带来的三大核心价值:
安全隔离。Claude Code在容器内运行,即使触发rm -rf也不会影响宿主机系统。容器内的用户是非root的appuser,文件系统权限被严格限制。
环境一致。团队成员共享同一个Dockerfile定义的镜像,消除"在我机器上能跑"的问题。Node.js版本、系统依赖、工具链完全统一。
权限放开。在容器内可以更放心地使用--dangerously-skip-permissions模式,因为爆炸半径被限制在容器内部。
# macOS(Homebrew)
brew install --cask docker
# Ubuntu/Debian
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# 验证安装
docker --version
# 预期输出: Docker version 28.x.x
docker run hello-world
安装后确保Docker Desktop正在运行(macOS查看菜单栏图标,Linux用systemctl status docker)。
在VS Code中安装两个扩展:
# 通过命令行安装
code --install-extension ms-vscode-remote.remote-containers
code --install-extension ms-vscode.docker
或打开VS Code → 扩展面板 → 搜索"Dev Containers"和"Docker" → 点击安装。
先在宿主机确认Claude Code可以正常安装:
npm install -g @anthropic-ai/claude-code
claude --version
# 预期输出: 2.x.x
注意:这一步仅用于验证,DevContainer内的Claude Code会在后续步骤中通过Dockerfile自动安装。
以一个Node.js + TypeScript项目为例:
mkdir my-claude-project && cd my-claude-project
git init
# 创建基础项目文件
cat > package.json << 'PKGJSON'
{
"name": "my-claude-project",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "tsx src/index.ts",
"build": "tsc",
"test": "vitest run"
}
}
PKGJSON
.devcontainer目录mkdir -p .devcontainer
这个目录是DevContainer规范的标准位置,VS Code会自动识别。
创建.devcontainer/Dockerfile:
# 使用官方Node.js镜像作为基础
FROM mcr.microsoft.com/devcontainers/typescript-node:22
# 安装系统级工具
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get install -y \
git \
curl \
ripgrep \
fd-find \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
# 安装Claude Code CLI
RUN npm install -g @anthropic-ai/claude-code
# 创建非root用户(安全最佳实践)
ARG USERNAME=appuser
ARG USER_UID=1000
ARG USER_GID=1000
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
&& apt-get update \
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME
# 设置工作目录
WORKDIR /workspace
# 切换到非root用户
USER $USERNAME
# 设置默认shell
ENV SHELL=/bin/bash
逐行解析关键设计决策:
mcr.microsoft.com/devcontainers/typescript-node:22:微软官方DevContainer镜像,预装Node.js 22、TypeScript、zsh等。选择官方镜像而非自定义基础镜像,减少维护成本。ripgrep和fd-find:Claude Code依赖这两个工具进行文件搜索。如果不安装,Claude Code的Grep和Glob工具会回退到较慢的搜索方式。appuser非root用户:Claude Code官方最佳实践要求非root运行。NOPASSWD:ALL给予sudo权限是为了安装额外的npm包,但在CI环境中可以移除。创建.devcontainer/devcontainer.json:
{
"name": "Claude Code Dev Environment",
"build": {
"dockerfile": "Dockerfile"
},
"forwardPorts": [3000, 5173],
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"vitest.explorer"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash"
}
}
},
"postCreateCommand": "npm install",
"remoteUser": "appuser",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
"workspaceFolder": "/workspace",
"mounts": [
"source=claude-code-history,target=/home/appuser/.claude,type=volume",
"source=claude-npm-cache,target=/home/appuser/.npm,type=volume"
],
"runArgs": [
"--memory=8g",
"--cpus=4"
]
}
关键字段解读:
| 字段 | 作用 | 为什么这样配置 |
|---|---|---|
forwardPorts |
端口转发 | 3000(HTTP服务)、5173(Vite HMR)是前端开发常用端口 |
postCreateCommand |
容器创建后执行 | 自动安装npm依赖,确保环境就绪 |
mounts |
持久化卷 | ~/.claude卷保存Claude Code的会话历史和配置,避免每次重建容器丢失数据;~/.npm卷缓存npm包加速安装 |
runArgs |
Docker运行参数 | 限制8GB内存、4个CPU核心,防止Claude Code跑满系统资源 |
创建.devcontainer/post-start.sh:
#!/bin/bash
# Claude Code认证配置(通过环境变量传递)
if [ -n "$ANTHROPIC_API_KEY" ]; then
echo "✓ API Key已配置"
else
echo "⚠ 未检测到ANTHROPIC_API_KEY环境变量"
echo " 请在devcontainer.json的remoteEnv中配置"
fi
# 配置Git(容器内首次使用需设置)
git config --global user.name "${GIT_USER_NAME:-Developer}"
git config --global user.email "${GIT_USER_EMAIL:-dev@example.com}"
# 创建项目级CLAUDE.md(如果不存在)
if [ ! -f /workspace/CLAUDE.md ]; then
cat > /workspace/CLAUDE.md << 'CLAUDE'
# 项目规范
## 技术栈
- Node.js 22 + TypeScript
- 测试框架: Vitest
- 包管理器: npm
## 开发约定
- 使用ES Module(import/export)
- 函数必须有类型注解
- 新功能必须附带测试
- 提交信息遵循Conventional Commits规范
CLAUDE
fi
更新devcontainer.json添加环境变量:
{
"remoteEnv": {
"ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}",
"GIT_USER_NAME": "${localEnv:GIT_USER_NAME}",
"GIT_USER_EMAIL": "${localEnv:GIT_USER_EMAIL}"
},
"postStartCommand": "bash .devcontainer/post-start.sh"
}
这种方式将宿主机的环境变量安全地传递进容器,避免在代码中硬编码API Key。
在VS Code中:
Cmd+Shift+P(macOS)或 Ctrl+Shift+P(Windows/Linux)Dev Containers: Reopen in Container或在项目根目录使用CLI:
# 使用VS Code CLI直接在容器中打开
code --remote container-folder .
容器启动后,在VS Code的集成终端中:
# 验证Claude Code已安装
claude --version
# 输出: 2.x.x
# 首次启动(交互式认证)
claude
# 会提示输入API Key或通过浏览器认证
首次认证有两种方式:
方式一——API Key直接输入:
export ANTHROPIC_API_KEY="sk-ant-xxxxx"
claude
方式二——OAuth浏览器认证(如果已通过claude login在宿主机认证过,且挂载了~/.claude卷,则自动继承认证)。
在Claude Code会话中测试:
> 请检查当前环境的操作系统信息
Claude Code会运行类似以下命令:
uname -a
# 预期输出类似: Linux abc123 5.15.x-microsoft # Docker容器内核
whoami
# 预期输出: appuser(非root)
pwd
# 预期输出: /workspace
如果看到这些输出,说明Claude Code已经正确运行在容器内。
> 尝试读取 /etc/shadow 文件
Claude Code应该收到权限拒绝:
cat /etc/shadow
# 预期输出: cat: /etc/shadow: Permission denied
这证明非root用户的权限限制生效。
用一个完整的项目演示DevContainer + Claude Code的工作流。
在容器内的Claude Code会话中输入:
> 我想创建一个Express + TypeScript的REST API项目,功能是管理书签。
支持CRUD操作,使用JSON文件作为持久化存储。
请初始化项目结构并安装依赖。
Claude Code会执行以下操作序列:
sequenceDiagram
participant U as 开发者
participant CC as Claude Code
participant FS as 容器文件系统
participant N as npm registry
U->>CC: 初始化书签API项目
CC->>N: npm install express cors uuid
CC->>N: npm install -D typescript @types/express @types/cors @types/uuid tsx vitest
CC->>FS: 创建 tsconfig.json
CC->>FS: 创建 src/index.ts (入口)
CC->>FS: 创建 src/routes/bookmarks.ts (路由)
CC->>FS: 创建 src/store.ts (JSON存储)
CC->>FS: 创建 CLAUDE.md (项目规范)
CC-->>U: 项目初始化完成,列出文件清单
继续在Claude Code中迭代:
> 现在请实现书签的CRUD接口,包含以下字段:
- id: UUID
- title: string
- url: string (必须是合法URL)
- tags: string[]
- createdAt: ISO时间戳
要求每个接口有输入验证,错误返回合适的HTTP状态码。
Claude Code生成的代码结构:
/workspace/
├── src/
│ ├── index.ts # Express服务器入口
│ ├── routes/
│ │ └── bookmarks.ts # 书签路由定义
│ ├── store.ts # JSON文件存储层
│ ├── validators.ts # 输入验证逻辑
│ └── types.ts # TypeScript类型定义
├── data/
│ └── bookmarks.json # 持久化存储文件
├── tests/
│ └── bookmarks.test.ts # 接口测试
├── package.json
├── tsconfig.json
└── CLAUDE.md
> 请运行项目并用curl测试所有接口
Claude Code会:
# 启动开发服务器(后台)
npm run dev &
# 测试创建书签
curl -X POST http://localhost:3000/api/bookmarks \
-H "Content-Type: application/json" \
-d '{"title":"Claude Code Docs","url":"https://docs.anthropic.com","tags":["ai","docs"]}'
# 预期输出:
# {"id":"a1b2c3d4-...","title":"Claude Code Docs","url":"https://docs.anthropic.com","tags":["ai","docs"],"createdAt":"2026-05-24T10:30:00.000Z"}
# 测试获取所有书签
curl http://localhost:3000/api/bookmarks
# 测试获取单个书签
curl http://localhost:3000/api/bookmarks/a1b2c3d4-...
# 测试更新
curl -X PUT http://localhost:3000/api/bookmarks/a1b2c3d4-... \
-H "Content-Type: application/json" \
-d '{"title":"Claude Code Official Docs","tags":["ai","docs","official"]}'
# 测试删除
curl -X DELETE http://localhost:3000/api/bookmarks/a1b2c3d4-...
# 测试输入验证(无效URL)
curl -X POST http://localhost:3000/api/bookmarks \
-H "Content-Type: application/json" \
-d '{"title":"Bad URL","url":"not-a-url"}'
# 预期输出: {"error":"Invalid URL format"} (400 Bad Request)
> 为书签CRUD编写完整的单元测试并运行
Claude Code会使用Vitest创建测试:
npm test
# 预期输出:
# ✓ tests/bookmarks.test.ts (8 tests) 42ms
# ✓ POST /api/bookmarks - 创建书签
# ✓ POST /api/bookmarks - 拒绝无效URL
# ✓ POST /api/bookmarks - 拒绝缺少必填字段
# ✓ GET /api/bookmarks - 获取所有书签
# ✓ GET /api/bookmarks/:id - 获取单个书签
# ✓ GET /api/bookmarks/:id - 404不存在的书签
# ✓ PUT /api/bookmarks/:id - 更新书签
# ✓ DELETE /api/bookmarks/:id - 删除书签
# Test Files 1 passed (1)
# Tests 8 passed (8)
将.devcontainer目录纳入Git版本管理:
# .gitignore中不要忽略.devcontainer
echo "!.devcontainer/" >> .gitignore
git add .devcontainer/
git commit -m "chore: add devcontainer configuration for Claude Code"
团队其他成员只需:
git clone <repo-url>
code .
# VS Code自动检测到.devcontainer,提示"Reopen in Container"
Anthropic在claude-code仓库中提供了官方DevContainer配置:
# 克隆官方配置
git clone --depth 1 https://github.com/anthropics/claude-code.git /tmp/claude-code
cp -r /tmp/claude-code/.devcontainer ./your-project/
官方模板的特点:
- 预配置了所有Claude Code依赖(ripgrep、fd-find等)
- 包含appuser非root用户设置
- 支持GitHub Codespaces一键启动
- 内存和CPU限制经过官方调优
在GitHub仓库中添加Codespaces配置(.devcontainer/devcontainer.json已被复用),团队成员可以通过浏览器直接使用:
# 在GitHub仓库页面
# Code → Codespaces → Create codespace on main
# 浏览器中打开VS Code,自动构建容器
# 在终端中运行 claude 即可开始
对于需要数据库等服务的项目,创建.devcontainer/docker-compose.yml:
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ..:/workspace:cached
- claude-history:/home/appuser/.claude
command: sleep infinity
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: bookmarks
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
claude-history:
pgdata:
更新devcontainer.json使用docker-compose:
{
"name": "Claude Code + PostgreSQL",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"forwardPorts": [3000, 5432],
"remoteUser": "appuser"
}
这样Claude Code可以直接连接PostgreSQL:
> 我需要将书签存储从JSON文件迁移到PostgreSQL数据库。
请安装pg驱动,创建数据库schema,并更新store.ts。
症状:容器内服务已启动,但宿主机浏览器无法访问。
解决方案:
# 在容器内检查服务是否监听0.0.0.0
netstat -tlnp | grep 3000
# 如果显示127.0.0.1:3000,需要改为0.0.0.0:3000
# Express示例
app.listen(3000, '0.0.0.0', () => { ... })
症状:每次重建容器后需要重新认证。
解决方案:确认devcontainer.json中的mounts配置了持久化卷:
"mounts": [
"source=claude-code-history,target=/home/appuser/.claude,type=volume"
]
重建容器后,~/.claude目录的数据会从卷恢复。
症状:每次打开DevContainer都要重新构建镜像。
解决方案:
# 在Dockerfile中最大化缓存层利用
# 先复制package.json并安装依赖(较少变化)
COPY package.json package-lock.json ./
RUN npm ci
# 再复制源代码(频繁变化)
COPY . .
症状:Claude Code尝试运行系统命令时提示"command not found"。
解决方案:在Dockerfile中添加所需工具:
# 按需添加开发工具
RUN apt-get update && apt-get install -y \
sqlite3 \ # 数据库客户端
redis-tools \ # Redis调试
jq \ # JSON处理
&& rm -rf /var/lib/apt/lists/*
症状:Claude Code处理大型文件时容器被杀。
解决方案:增加Docker资源限制:
"runArgs": [
"--memory=16g",
"--memory-swap=16g",
"--cpus=8"
]
graph LR
subgraph 宿主机
A[VS Code] --> B[DevContainer Extension]
C[环境变量<br/>ANTHROPIC_API_KEY]
D[项目源码<br/>bind mount]
end
subgraph Docker容器
E[appuser<br/>非root用户]
F[Claude Code CLI]
G[Node.js 22 + TypeScript]
H[npm依赖]
I[端口转发<br/>:3000 :5173]
end
subgraph 持久化卷
J[claude-history<br/>~/.claude]
K[npm-cache<br/>~/.npm]
L[pgdata<br/>PostgreSQL]
end
B --> E
C -->|remoteEnv| F
D -->|workspaceMount| G
F --> H
F --> I
E --> J
E --> K
E --> L
I -->|宿主机浏览器| A
style F fill:#7c3aed,color:#fff
style E fill:#51cf66,color:#fff
style J fill:#ffd43b,color:#333
style K fill:#ffd43b,color:#333
style L fill:#ffd43b,color:#333
训练营适用性评估: - 适合"云原生开发训练营"(中级,4课时) - 适合"AI辅助编程实战营"入门模块(初级,2课时) - 适合"DevOps工程师AI工具链"课程(中级,3课时) - 预计教学时长:含实操4-5小时(含Docker基础回顾)
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
