用 Claude Code 部署到 GCP Cloud Run:实战指南
用 Docker、IAM、Secret Manager、日志和回滚,把 Node.js API 安全部署到 Cloud Run。
Cloud Run 适合这样的场景:你想发布一个容器化的 HTTP 服务,但不想维护 Kubernetes、ECS 或一组虚拟机。和 Cloud Functions、Lambda 相比,它不要求你把应用拆成很多小函数。一个普通的 Express API、BFF 或 webhook 接收服务,只要能打成 Docker 镜像,就可以交给 Cloud Run 处理 HTTPS、版本、扩缩容和日志。
本文用 Claude Code 辅助完成一条完整链路:本地 Node.js/Express 服务、Dockerfile、本地测试、Artifact Registry、gcloud run deploy、服务账号、IAM、Secret Manager、并发数、最小实例、Cloud Logging、revision 回滚、成本陷阱和安全审查。
先把术语说清楚:Cloud Run 是“按 HTTP 请求运行容器的无服务器平台”;Artifact Registry 是“Docker 镜像仓库”;Secret Manager 是“保存密码和 API key 的保险箱”;IAM 是“决定哪个身份能访问哪个资源的权限系统”。
什么时候 Cloud Run 比 Functions 或 Lambda 更合适
Cloud Run 不是所有场景都优于 Cloud Functions 或 Lambda。非常小的事件处理函数,直接用函数平台可能更轻。但下面这些场景,Cloud Run 的开发体验通常更好。
| 用例 | Cloud Run 的优势 |
|---|---|
| Webhook 接收 API | Stripe、GitHub、LINE 等 HTTP POST 可以自然映射到 Express 路由 |
| 小型 BFF/API 服务 | 鉴权、中间件、路由和校验可以保留在一个 Node.js 应用里 |
| 定时批处理入口 | Cloud Scheduler 通过 HTTP 调用,不必额外搭一套任务框架 |
| 轻量 AI 或数据 API | 原生依赖、系统包、自定义二进制都可以放进容器 |
如果是长时间常驻 worker,要特别检查 CPU 分配和成本。Cloud Run 很适合请求驱动的服务,但不是所有后台循环任务的默认答案。
可运行的 Express 服务
Cloud Run 会通过 PORT 环境变量告诉容器监听哪个端口,所以代码不要写死端口。还要准备 /health,方便部署后检查。
{
"name": "cloud-run-claude-code-api",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "tsx src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"test": "node --test"
},
"dependencies": {
"express": "^4.19.2"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^22.10.0",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
}
}
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}
import express from "express";
const app = express();
app.use(express.json());
const requiredEnv = ["DATABASE_URL", "JWT_SECRET"];
for (const key of requiredEnv) {
if (!process.env[key]) {
console.error(`Missing required environment variable: ${key}`);
process.exit(1);
}
}
app.get("/health", (_req, res) => {
res.status(200).json({ ok: true, service: "myapp-api" });
});
app.post("/webhooks/example", (req, res) => {
console.log("webhook_received", {
eventType: req.body?.type ?? "unknown",
receivedAt: new Date().toISOString()
});
res.status(202).json({ accepted: true });
});
app.get("/config-check", (_req, res) => {
res.json({
nodeEnv: process.env.NODE_ENV ?? "development",
hasDatabaseUrl: Boolean(process.env.DATABASE_URL),
hasJwtSecret: Boolean(process.env.JWT_SECRET)
});
});
const port = Number(process.env.PORT ?? 8080);
const server = app.listen(port, () => {
console.log(`listening on ${port}`);
});
process.on("SIGTERM", () => {
console.log("SIGTERM received, closing HTTP server");
server.close(() => process.exit(0));
setTimeout(() => process.exit(1), 30000).unref();
});
本地先验证:
npm install
DATABASE_URL="postgresql://local" JWT_SECRET="local-secret" npm run dev
curl http://localhost:8080/health
curl -X POST http://localhost:8080/webhooks/example \
-H "Content-Type: application/json" \
-d '{"type":"demo.created"}'
Dockerfile 和 Claude Code 审查
不要只让 Claude Code“生成 Dockerfile”。更好的要求是“按 Cloud Run 生产环境审查”。重点包括运行镜像体积、只安装生产依赖、非 root 用户、.dockerignore、PORT 支持,以及安全和成本风险。
claude -p "
Review and improve this Cloud Run Docker setup.
Requirements:
- Node.js 22 LTS, TypeScript, Express
- production dependencies only in runtime image
- run as a non-root user
- listen on the PORT environment variable
- include .dockerignore
- explain any Cloud Run security or cost risks
Return the final Dockerfile and a short review checklist.
"
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=8080
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=builder /app/dist ./dist
USER appuser
EXPOSE 8080
CMD ["node", "--max-old-space-size=384", "dist/index.js"]
node_modules
dist
.env
.env.*
*.log
.git
.gitignore
Dockerfile
README.md
docker build -t myapp-api:local .
docker run --rm -p 8080:8080 \
-e PORT=8080 \
-e DATABASE_URL="postgresql://local" \
-e JWT_SECRET="local-secret" \
myapp-api:local
curl http://localhost:8080/health
Artifact Registry 和首次部署
Artifact Registry 是镜像仓库。先为目标区域配置 Docker 认证,再创建仓库、构建和推送镜像。
PROJECT_ID="my-project-123"
REGION="asia-northeast1"
REPOSITORY="myapp"
SERVICE="myapp-api"
IMAGE="$REGION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/api:v1.0.0"
gcloud config set project "$PROJECT_ID"
gcloud services enable run.googleapis.com artifactregistry.googleapis.com secretmanager.googleapis.com logging.googleapis.com
gcloud artifacts repositories create "$REPOSITORY" \
--repository-format=docker \
--location="$REGION" \
--description="Docker images for myapp"
gcloud auth configure-docker "$REGION-docker.pkg.dev"
docker build -t "$IMAGE" .
docker push "$IMAGE"
部署前创建专用运行服务账号,避免默认账号权限过大。
gcloud iam service-accounts create myapp-run \
--display-name="Cloud Run runtime for myapp"
SERVICE_ACCOUNT="myapp-run@$PROJECT_ID.iam.gserviceaccount.com"
gcloud run deploy "$SERVICE" \
--image "$IMAGE" \
--region "$REGION" \
--platform managed \
--service-account "$SERVICE_ACCOUNT" \
--memory 512Mi \
--cpu 1 \
--concurrency 80 \
--min-instances 0 \
--max-instances 20 \
--allow-unauthenticated \
--set-env-vars NODE_ENV=production \
--port 8080
内部 API 不应公开访问,去掉 --allow-unauthenticated,只给调用方 Cloud Run Invoker 权限。
Secret Manager、IAM 和安全
不要把密码写进 --set-env-vars。用 Secret Manager 保存,再让 Cloud Run 注入环境变量。
echo -n "postgresql://user:password@host:5432/app" | \
gcloud secrets create DATABASE_URL --data-file=-
echo -n "replace-with-long-random-value" | \
gcloud secrets create JWT_SECRET --data-file=-
gcloud secrets add-iam-policy-binding DATABASE_URL \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding JWT_SECRET \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/secretmanager.secretAccessor"
gcloud run services update "$SERVICE" \
--region "$REGION" \
--set-secrets "DATABASE_URL=DATABASE_URL:latest,JWT_SECRET=JWT_SECRET:latest"
权限尽量加在单个 secret 上,而不是给整个项目 roles/editor。这能显著缩小事故影响范围。
并发、最小实例和成本陷阱
Concurrency 表示一个容器实例最多同时处理多少请求。值越高,实例数可能越少,但数据库连接池、外部 API 限流和 CPU 都可能先成为瓶颈。
gcloud run services update "$SERVICE" \
--region "$REGION" \
--concurrency 40 \
--min-instances 1 \
--max-instances 20 \
--cpu-throttling
开发环境和低流量个人项目可以用 min-instances 0。Webhook 或生产 API 如果不能接受冷启动延迟,可以设为 1。Webhook 常从 20-40 开始,BFF/API 从 40-80 开始,再根据 p95 延迟、DB 连接数和错误率调整。
Cloud Logging 和回滚
Cloud Run 的请求日志、容器日志和系统日志会进入 Cloud Logging。Node.js 服务通常把日志写到 stdout/stderr 就足够。
gcloud run services logs read "$SERVICE" \
--region "$REGION" \
--limit 20
gcloud logging read \
"resource.type=cloud_run_revision AND resource.labels.service_name=$SERVICE" \
--limit 20 \
--format=json
每次部署或配置变更都会创建不可变 revision。出现问题时,把流量切回上一版。
gcloud run revisions list \
--service "$SERVICE" \
--region "$REGION"
gcloud run services update-traffic "$SERVICE" \
--region "$REGION" \
--to-revisions myapp-api-00012-abc=100
上线前让 Claude Code 做部署审查:
claude -p "
Act as a Cloud Run deployment reviewer.
Review package.json, Dockerfile, src/index.ts, and the gcloud commands below.
Find blockers before production:
- Cloud Run PORT handling
- SIGTERM graceful shutdown
- non-root container
- Secret Manager usage
- service account and IAM least privilege
- concurrency, min instances, max instances, and cost risks
- Cloud Logging observability
- rollback command for the previous revision
Return: critical issues, recommended fixes, and commands to verify after deploy.
"
常见失败点
镜像太大会拖慢构建、推送和冷启动。把 secret 写进普通环境变量,会留下命令历史或 CI 日志。min-instances 1 可以降延迟,但空闲也会计费。Concurrency 过高会把下游数据库或外部 SaaS 打满。回滚命令必须在平时演练,而不是事故发生后再搜索。
参考和下一步
- Cloud Run 文档
- 部署容器镜像到 Cloud Run
- Artifact Registry Docker 认证
- Cloud Run 配置 Secret
- Cloud Run 日志
- Cloud Run 回滚和流量迁移
- Claude Code Docker 集成
- Claude Code AWS ECS/Fargate 指南
- Claude Code 安全最佳实践
Cloud Run 是一个实用的中间选择:比函数平台更灵活,比 ECS 或 Kubernetes 更轻。需要把 Claude Code 提示、审查清单和部署护栏落到团队流程中,可以查看 Claude Code 培训与咨询。
实测记录
本文示例已按本地 npm run dev、Docker /health、PORT 处理和必填环境变量校验进行验证。上线前还应在真实项目里检查 Artifact Registry 权限、Secret Manager 单 secret IAM、Cloud Logging 查询,以及 update-traffic 回滚演练。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
从Obsidian到CLAUDE.md的Claude Code流程:不再反复解释上下文
把 Obsidian 工作笔记整理成 CLAUDE.md 运行说明,让 Claude Code 每次都带着正确上下文开始。
Claude Code 收入 CTA 路由:从文章分流到 PDF、Gumroad 与咨询
用 Claude Code 按读者意图把文章流量分到免费 PDF、Gumroad 教材或咨询入口。
Claude Code 团队交接规则: 把审查证据、权限、回滚和收入路径一起交付
面向团队的 Claude Code 交接格式: 证据、权限、回滚、免费 PDF、Gumroad 与咨询路径都要可审查。