流程执行说明:
- 步骤 1-3:用户创建 Session 时,Web 服务通过 Sandbox CRD 向 Controller 申请一个沙箱 Pod,Controller 负责调度和启动
- 步骤 4-6:Pod 启动时平台注入 LiteLLM 的连接信息(地址、鉴权 Key),Pod 就绪后用户获得 TTY WebSocket Token
- 步骤 7-10:用户通过 WebSocket 与沙箱交互,Agent 在沙箱中执行任务
- 步骤 11-14:Agent 调用模型时通过 LiteLLM 网关路由,LiteLLM 持有真实 API Key 并转发到模型供应商
- 步骤 15-17:执行结果通过 WebSocket 实时推送到浏览器
三层分离
| | |
|---|
| | Agent 管理、Session 编排、Sandbox 生命周期 |
| | |
| |
隔离的 Agent 执行环境,每个 Session 一个 Pod |
关键设计原则:平台不持有模型 API Key,只有 LiteLLM 网关持有。沙箱只知道 LiteLLM 的地址和鉴权 Key,无法直接访问模型供应商。
1.3 适用场景
2. 环境准备与安装
2.1 环境要求
本次部署的实际环境:
- 容器运行时:Docker Desktop 29.1.2
- Kubernetes:Docker Desktop 内置 K8s v1.34.1
- 节点:单节点(docker-desktop),16 核 CPU
- 网络:需要可用的 HTTP 代理(本次使用 127.0.0.1:7078)
- 磁盘空间:至少 20GB 可用(镜像和构建缓存占用较大)
最低要求(推测):
2.2 基础设施部署
步骤 1 — 确认 K8s 集群可用
kubectl config current-context# 输出:docker-desktop
kubectl get nodes# 输出:NAME STATUS ROLES AGE VERSION# docker-desktop Ready control-plane 9d v1.34.1
如果 current-context 不是 docker-desktop,切换过去:
kubectl config use-context docker-desktop
步骤 2 — 启动 Postgres 数据库
使用项目自带的 docker-compose 启动 Postgres:
cd litellm-agent-platformdocker compose up -d postgres
验证数据库可访问:
docker exec litellm-agents-postgres pg_isready -U litellm -d litellm_agents# 输出:/var/run/postgresql:5432 - accepting connections
Postgres 配置(docker-compose.yml 中定义):
步骤 3 — 数据库迁移
先构建 Prisma 镜像并运行迁移:
docker build --target prisma -t litellm-agent-platform:prisma .
docker run --rm --network host \ -e DATABASE_URL="postgresql://litellm:litellm@localhost:5432/litellm_agents" \ litellm-agent-platform:prisma \ npx prisma db push --accept-data-loss --skip-generate
预期输出:
The database is already in sync with the Prisma schema.
2.3 K8s 核心组件安装
步骤 4 — 安装 agent-sandbox CRD 和 Controller
# 核心 CRD(Sandbox)kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.4.5/manifest.yaml
# 扩展 CRD(SandboxTemplate、SandboxClaim、SandboxWarmPool)kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.4.5/extensions.yaml
验证安装:
kubectl get crd | grep sandboxkubectl get pods -n agent-sandbox-system# 输出:agent-sandbox-controller-xxx 1/1 Running
步骤 5 — 应用 RBAC 和 PriorityClass
kubectl apply -f k8s/rbac-platform.yamlkubectl apply -f k8s/priority-classes.yamlPriorityClass 优先级体系:
- platform-critical(2000000):Web + Worker,永不被驱逐
- sandbox-active(1000):活跃会话 Pod
- sandbox-warm(100):预热池 Pod,优先被驱逐
步骤 6 — 创建 litellm-env Secret
kubectl create secret generic litellm-env \ --from-literal=MASTER_KEY='' \ --from-literal=DATABASE_URL='postgresql://litellm:litellm@192.168.65.3:5432/litellm_agents' \ --from-literal=LITELLM_API_BASE='http://litellm.default.svc.cluster.local:4000' \ --from-literal=LITELLM_API_KEY='sk-litellm-local' \ --from-literal=LITELLM_DEFAULT_MODEL='claude-sonnet-4-6' \ --from-literal=K8S_HARNESS_IMAGE='claude-agent-sdk-sandbox:dev' \ --from-literal=K8S_NODEPORT_MIN='30000' \ --from-literal=K8S_NODEPORT_MAX='30099' \ --from-literal=WARM_POOL_SIZE='0' \ --from-literal=CONTAINER_ENV_HARNESS_AUTH_TOKEN=''
说明:192.168.65.3 是 Docker Desktop K8s 节点的 InternalIP,K8s Pod 通过此 IP 访问宿主机的 Postgres(端口 5432 已通过 docker-compose 暴露)。
2.4 平台镜像构建
步骤 7 — 构建平台镜像
由于 Docker Hub 在中国大陆访问受限,需要先配置代理(见第 4.2 节),然后构建:
docker build --target runner -t litellm-agent-platform:dev .
构建过程分多个阶段(多阶段 Dockerfile):
- deps:npm ci(安装依赖,约 10 分钟)
- builder:Next.js 编译 + TypeScript 检查 + Prisma 生成(约 5 分钟)
- runner:组装 standalone 运行时(约 0.5 分钟)
构建完成后验证:
docker images litellm-agent-platform:dev# 输出:litellm-agent-platform dev 1.79GB
2.5 平台服务部署
步骤 8 — 部署 Web 和 Worker
使用 Docker Desktop 专用的 K8s 清单(去掉了 AWS ALB 注解,改用 NodePort Service,镜像改为本地构建的
litellm-agent-platform:dev)。这些文件(k8s/web-dd.yaml、k8s/worker-dd.yaml、k8s/sandbox-template-dd.yaml)不在项目上游仓库中,需要从 k8s/web.yaml、k8s/worker.yaml 等文件手动修改得到。
kubectl apply -f k8s/web-dd.yamlkubectl apply -f k8s/worker-dd.yaml
验证所有 Pod 运行正常:
kubectl get pods# 输出:# NAMEREADYSTATUSRESTARTS AGE# litellm-web-xxx1/1Running0 10s# litellm-worker-xxx1/1Running0 10s
测试 Web 服务:
curl http://127.0.0.1:30080/api/v1/health/k8s \ -H "Authorization: Bearer $MASTER_KEY"# 输出:{"ok":true,"elapsed_ms":13}
2.6 LiteLLM 网关部署
步骤 9 — 创建 LiteLLM ConfigMap
kubectl create configmap litellm-config \ --from-file=proxy_server_config.yaml=/path/to/litellm_config.yaml
配置文件内容:
model_list:
- model_name: claude-sonnet-4-6 litellm_params: model: anthropic/claude-sonnet-4-6 api_key: sk-ant-你的真实Key
general_settings: master_key: sk-litellm-local
litellm_settings: drop_params: true set_verbose: false
关键点:ConfigMap 的 key 名必须是 proxy_server_config.yaml,这是 LiteLLM 镜像的默认配置文件名。挂载到 /app/proxy_server_config.yaml 即可覆盖内置配置。
步骤 10 — 部署 LiteLLM
kubectl apply -f k8s/litellm.yaml
验证:
curl http://127.0.0.1:30040/v1/models \ -H "Authorization: Bearer sk-litellm-local"# 输出:{"data":[{"id":"claude-sonnet-4-6","object":"model",...}],"object":"list"}
2.7 Harness 镜像构建
步骤 11 — 构建 Harness 基础镜像
docker build -f harnesses/base/Dockerfile -t harnesses/base:dev .
基础镜像包含:Node.js 20 + Debian Bookworm + gh CLI 2.92.0 + uv 0.5.13 + Jaeger 1.62.0 + Vault CA。构建时间约 20 分钟(取决于代理速度)。
步骤 12 — 构建 claude-agent-sdk Harness
docker build -f harnesses/claude-agent-sdk/Dockerfile \ -t claude-agent-sdk-sandbox:dev .
包含:Claude Agent SDK + Playwright Chromium + gitleaks。构建时间约 30 分钟。
步骤 13 — 应用 SandboxTemplate
kubectl apply -f k8s/sandbox-template-dd.yaml
验证:
kubectl get sandboxtemplates# 输出:NAME AGE# claude-agent-sdk 3s
3. 配置与定制
3.1 平台配置
平台通过 .env 文件和 litellm-env K8s Secret 配置,主要变量:
| | |
|---|
| | |
| | postgresql://litellm:litellm@192.168.65.3:5432/litellm_agents |
| | http://litellm.default.svc.cluster.local:4000 |
| | |
| 默认模型(与 LiteLLM model_name 一致) | |
| | claude-agent-sdk-sandbox:dev |
| | |
| | |
| |
|
| | |
3.2 LiteLLM 配置
LiteLLM 配置文件核心结构:
- model_list:模型列表,每项包含 model_name(Agent 调用时的名称)和 litellm_params(实际模型标识和 API Key)
- general_settings:网关自身的 master_key,所有请求需携带此 Key
- litellm_settings:运行时行为,drop_params 自动丢弃不支持的参数
3.3 K8s Secret 管理
Secret 更新后必须重启相关 Pod 才能生效:
kubectl patch secret litellm-env --type='json' -p='[...]'kubectl rollout restart deployment/litellm-web deployment/litellm-worker
查看 Secret 内容:
kubectl get secret litellm-env -o jsonpath='{.data.MASTER_KEY}' | base64 -d
4. 问题排查与修复
本次部署过程中遇到了 7 个问题,以下是根因和解决方案。
4.1 K8s 集群 TLS 证书问题
现象:kubectl 命令报错 x509: certificate signed by unknown authority
根因:kubeconfig 中 current-context 指向 rancher-desktop(已停止),而 Docker Desktop 是实际运行的集群。Rancher Desktop 的证书与 Docker Desktop 的 API Server 不匹配。
解决:切换到正确的 context:
kubectl config use-context docker-desktop
如果证书仍有问题,可临时跳过 TLS 验证:
kubectl config set-cluster docker-desktop --insecure-skip-tls-verify=true
4.2 Docker Hub 网络不通
现象:docker pull 持续 "Waiting",下载速度 ~50 B/s,超时后报 EOF
根因:Docker Hub 在中国大陆访问受限,所有已配置的镜像加速器(中科大、网易、DaoCloud、阿里云)均不可用。系统中存在一个本地 HTTP 代理 127.0.0.1:7078,但 Docker Daemon 未配置使用它。
解决:三步配置 Docker Desktop 代理。
第一步,编辑 Docker Desktop 配置文件 %APPDATA%\Docker\settings.json:
{ "proxyHttpMode": "manual", "httpProxy": "http://host.docker.internal:7078", "httpsProxy": "http://host.docker.internal:7078", "proxyExclude": "localhost,127.0.0.1,192.168.65.0/24,.internal"}
第二步,验证代理可达:
docker run --rm alpine:latest sh -c "ping -c1 host.docker.internal"# host.docker.internal → 192.168.65.254,可达
第三步,拉取失败时用本地缓存构建。对于 node:20-bookworm-slim(约 110MB),如果拉取太慢可以用已缓存的基础镜像替代:
# debian:bookworm-slim 已缓存(74.8MB),直接安装 Node.jsdocker build -f - -t node:20-bookworm-slim . <'DEOF'FROM debian:bookworm-slimRUN apt-get update && apt-get install -y curl xz-utils ca-certificates && \ curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ apt-get install -y nodejs && rm -rf /var/lib/apt/lists/*DEOF
4.3 Worker 启动崩溃(tsconfig 缺失)
现象:Worker Pod 报错 Error: Cannot resolve tsconfig at path: /app/tsconfig.worker.json
根因:Dockerfile 的 runner 和 worker 两个 target 的 COPY 指令只复制了 tsconfig.json,遗漏了 tsconfig.worker.json。Worker 启动脚本 npm run worker 执行 tsx --tsconfig tsconfig.worker.json src/worker/index.ts,找不到文件直接崩溃。
修复:在 Dockerfile 的 worker target(第 68 行)和 runner target(第 107 行)各添加 tsconfig.worker.json:
# 修复前COPY --from=builder /app/package.json /app/package-lock.json /app/tsconfig.json ./
# 修复后COPY --from=builder /app/package.json /app/package-lock.json /app/tsconfig.json /app/tsconfig.worker.json ./
4.4 Worker 启动崩溃(src/lib 缺失)
现象:Worker Pod 报错 Cannot find module '@/lib/egress-hosts'
根因:src/server/types.ts 引用了 @/lib/egress-hosts(路径映射 @/* → ./src/*),但 Dockerfile 只复制了 src/server/ 和 src/worker/,遗漏了 src/lib/。
修复:在 worker 和 runner target 中各添加一行:
COPY --from=builder --chown=nextjs:nodejs /app/src/lib ./src/lib
4.5 LiteLLM ConfigMap 文件名不匹配
现象:LiteLLM 日志显示加载了内置的 Azure 示例配置,而非我们自定义的 Claude 模型配置。
根因:ConfigMap 的 data key 名为 litellm_config.yaml,但 Pod args 指向 /etc/litellm/config.yaml,ConfigMap 挂载后实际文件名为 /etc/litellm/litellm_config.yaml,路径不匹配。
修复:ConfigMap data key 必须与挂载目标文件名一致:
kubectl create configmap litellm-config \ --from-file=proxy_server_config.yaml=/path/to/litellm_config.yaml
4.6 LiteLLM 健康探针导致重启循环
现象:main-stable 镜像的 Pod 持续 CrashLoopBackOff,无日志输出
根因:main-stable 镜像的 Litellm 服务器未暴露 /health/liveliness 端点(返回 404),K8s livenessProbe 判定失败后不断重启容器。
解决:本地开发环境下可以移除探针以确保稳定运行(正式部署时应配置 TCP 探针或正确的 HTTP 健康检查路径)。使用 main 镜像(pip install 耗时较长)时需要给足启动时间。
4.7 LiteLLM 默认配置覆盖自定义配置
现象:即使正确挂载了配置文件,LiteLLM 仍加载内置的 Azure 模型配置
根因:经过多轮排查,发现需要同时满足以下条件:
- ConfigMap data key 必须是
proxy_server_config.yaml(LiteLLM 镜像默认配置文件名) - 通过
subPath 挂载到 /app/proxy_server_config.yaml(覆盖内置配置) - 不能使用
--config 参数或 LITELLM_CONFIG_PATH 环境变量指定其他路径,因为 LiteLLM 镜像入口脚本对自定义配置路径的支持不稳定
最终可工作的 Pod 配置:
spec: containers: - name: litellm image: ghcr.io/berriai/litellm:main args: ["--port", "4000"] volumeMounts: - name: config mountPath: /app/proxy_server_config.yaml subPath: proxy_server_config.yaml volumes: - name: config configMap: name: litellm-config
5. 使用技巧与最佳实践
5.1 代理加速镜像拉取
在受限网络环境下,优先利用已缓存的基础镜像构建派生镜像:
- 使用
debian:bookworm-slim(74.8MB)替代 node:20-bookworm-slim(需从 Docker Hub 拉取) - 将自定义构建的基础镜像 tag 为官方镜像名,避免修改 Dockerfile
5.2 构建缓存复用
多阶段 Dockerfile 的各层独立缓存。修改 Dockerfile 时遵循以下原则可以最大化缓存复用:
- 将不常变化的 COPY 放在前面(如 package.json)
- 多个构建命令共享同一个基础镜像时,并行构建会自动共享缓存
本次部署体验:npm ci 约 10 分钟(首次),后续构建为 CACHED(数秒内完成)。
5.3 部署顺序建议
推荐的部署顺序(避免依赖等待):
1. Postgres → 确保数据库可用2. DB 迁移 → Schema 就绪3. K8s CRD + Controller → 沙箱基础设施4. RBAC + PriorityClass → 权限和调度5. Secret → 配置就绪6. 平台镜像构建 → Web + Worker7. Harness 镜像构建 → Sandbox 运行时8. SandboxTemplate → 沙箱模板9. LiteLLM 网关 → 模型路由10. 平台服务部署 → Web + Worker11. 验证端到端
6. 总结
6.1 部署成果
| | |
|---|
| | |
| agent-sandbox CRD + Controller | | |
| | litellm-platform SA, 3 级优先级 |
| | |
| | |
| | |
| | |
| | |
|
| | |
| | |
| | claude-agent-sdk-sandbox:dev (2GB) |
| | tsconfig.worker.json、src/lib/、COPY 修复 |
6.2 关键收获
- 三层架构清晰分离:平台层(Agent 管理)、网关层(模型路由)、沙箱层(隔离执行),各层独立部署和扩展
- K8s 部署需注意 8 个核心组件:CRD、Controller、RBAC、PriorityClass、Secret、SandboxTemplate、Deployment(Web/Worker/LiteLLM)、Service
- 网络受限环境下的核心策略:利用已缓存基础镜像 + 本地代理 + 镜像 tag 重定向
- Dockerfile 中的 COPY 遗漏是常见的运行时故障来源,应充分测试 Worker 和 Web 两个 target
- LiteLLM 的 ConfigMap 挂载需要精确匹配文件名和路径,条件缺一不可
6.3 快速部署速查
# 1. 确认集群kubectl config use-context docker-desktop && kubectl get nodes
# 2. 启动 Postgres
docker compose up -d postgres
# 3. 安装 CRDkubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.4.5/manifest.yamlkubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.4.5/extensions.yaml
# 4. 应用 K8s 配置kubectl apply -f k8s/rbac-platform.yamlkubectl apply -f k8s/priority-classes.yaml
# 5. 创建 Secret(替换 MASTER_KEY 为实际值)kubectl create secret generic litellm-env \ --from-literal=MASTER_KEY='<64位hex>' \ --from-literal=DATABASE_URL='postgresql://litellm:litellm@192.168.65.3:5432/litellm_agents' \ --from-literal=LITELLM_API_BASE='http://litellm.default.svc.cluster.local:4000' \ --from-literal=LITELLM_API_KEY='sk-litellm-local' \ --from-literal=LITELLM_DEFAULT_MODEL='claude-sonnet-4-6' \ --from-literal=K8S_HARNESS_IMAGE='claude-agent-sdk-sandbox:dev' \ --from-literal=K8S_NODEPORT_MIN='30000' \ --from-literal=K8S_NODEPORT_MAX='30099' \ --from-literal=WARM_POOL_SIZE='0' \ --from-literal=CONTAINER_ENV_HARNESS_AUTH_TOKEN='<16字节hex>'
# 6. 构建镜像docker build --target runner -t litellm-agent-platform:dev .docker build -f harnesses/base/Dockerfile -t harnesses/base:dev .docker build -f harnesses/claude-agent-sdk/Dockerfile -t claude-agent-sdk-sandbox:dev .
# 7. 部署 LiteLLMkubectl create configmap litellm-config --from-file=proxy_server_config.yaml=litellm_config.yamlkubectl apply -f k8s/litellm.yaml
# 8. 部署平台kubectl apply -f k8s/sandbox-template-dd.yamlkubectl apply -f k8s/web-dd.yamlkubectl apply -f k8s/worker-dd.yaml
# 9. 验证curl http://127.0.0.1:30080/api/v1/health/k8s -H "Authorization: Bearer $MASTER_KEY"curl http://127.0.0.1:30040/v1/models -H "Authorization: Bearer sk-litellm-local"
适用场景:本地开发测试、POC 验证、小团队共享 Agent 平台。不适合:大规模生产部署(建议使用项目自带的 EKS 生产方案)。
6.4 特殊说明:Postgres 为何非 K8s 部署
本次部署中 Postgres 使用 docker-compose 而非 K8s 部署,这一选择在本地开发场景下是合理的。以下是详细分析。
选择 docker-compose 的理由:
- 项目自身设计了
docker-compose.yml,Postgres 服务已定义好(镜像、用户、密码、健康检查),一条命令即可启动,无需额外编写 K8s 清单 - Docker Desktop K8s 在 Windows 上的 PV/PVC 支持存在兼容性问题,StatefulSet 管理 Postgres 需要额外维护存储卷清单
- 本地开发为单用户场景,不需要 K8s 的高可用和自动故障转移能力
- 减少本地资源消耗:一个 docker-compose 容器比一个 K8s StatefulSet Pod 更轻量
如果使用 K8s 部署 Postgres 需要额外做的工作:
- 编写 StatefulSet + PVC 清单,或安装 CloudNativePG Operator
- 配置持久化存储(Docker Desktop 可用 hostPath,但多节点场景不适用)
不同环境的 Postgres 部署策略:
本项目目标生产环境是 AWS EKS + Neon Serverless Postgres,数据库是完全托管的外部服务。生产环境中数据库通常不应放在 K8s 集群内,而是使用云厂商的托管数据库服务以获得更好的可靠性、自动备份和弹性伸缩能力。
参考文献
[1] litellm-agent-platform 项目仓库:https://github.com/BerriAI/litellm-agent-platform
[2] agent-sandbox CRD 项目:https://github.com/kubernetes-sigs/agent-sandbox
[3] LiteLLM 官方文档:https://docs.litellm.ai
[4] Docker Desktop K8s 文档:https://docs.docker.com/desktop/kubernetes/