Use Cases (Actualizado: 2/6/2026)

Desplegar en GCP Cloud Run con Claude Code: guía práctica

Publica una API Node.js segura en Cloud Run con Docker, IAM, secretos, logs y rollback.

Desplegar en GCP Cloud Run con Claude Code: guía práctica

Cloud Run encaja muy bien cuando quieres publicar un servicio HTTP en contenedor sin operar Kubernetes, ECS ni una flota de máquinas virtuales. Frente a Cloud Functions o Lambda, no te obliga a convertir toda la aplicación en funciones pequeñas. Puedes llevar una API Express normal, empaquetarla como imagen Docker y dejar que Google Cloud gestione HTTPS, revisiones, escalado y logs.

Esta guía muestra cómo usar Claude Code para llevar una API TypeScript/Express desde local hasta Cloud Run. Incluye código ejecutable, Dockerfile, prueba local, Artifact Registry, gcloud run deploy, cuenta de servicio, IAM, Secret Manager, concurrencia, instancias mínimas, Cloud Logging, rollback de revisiones, errores de coste y una prompt de revisión de despliegue.

En términos simples: Cloud Run es una plataforma serverless para ejecutar contenedores que responden a HTTP. Artifact Registry es el almacén de imágenes Docker. Secret Manager es la caja fuerte de contraseñas y claves API. IAM es el sistema de permisos que decide qué identidad puede acceder a qué recurso.

Cuándo Cloud Run gana a Functions o Lambda

Cloud Run no siempre es mejor que Cloud Functions o Lambda. Para un manejador de eventos mínimo, una función puede ser más simple. Cloud Run gana cuando el servicio ya es una aplicación HTTP o cuando necesitas más control del runtime.

Caso de usoPor qué Cloud Run encaja
Receptor de webhooksStripe, GitHub o LINE se modelan de forma natural como rutas Express
BFF o API pequeñaAutenticación, middleware, rutas y validación quedan en una app Node.js normal
Endpoint HTTP para tareas programadasCloud Scheduler puede llamarlo sin crear otra infraestructura de jobs
API ligera de IA o datosDependencias nativas y binarios personalizados quedan dentro del contenedor

Para workers de larga duración, revisa CPU y coste antes. Cloud Run es excelente para servicios orientados a petición, no una respuesta automática para bucles en segundo plano.

Servicio Express ejecutable

Cloud Run pasa el puerto mediante la variable PORT. El servicio debe leerla, exponer /health y cerrar correctamente cuando reciba SIGTERM.

{
  "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();
});

Compruébalo en local:

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 y revisión con Claude Code

Pide a Claude Code una revisión de producción, no solo generación de archivos. Debe comprobar imagen pequeña, dependencias de producción, usuario no root, .dockerignore, soporte de PORT y riesgos de seguridad o coste.

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 y primer despliegue

Artifact Registry guarda la imagen Docker. Configura autenticación para el host regional, crea el repositorio y sube la imagen.

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"

Crea una cuenta de servicio de runtime antes de desplegar.

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

Si la API es interna, elimina --allow-unauthenticated y concede Cloud Run Invoker solo a los llamadores necesarios.

Secret Manager, IAM y seguridad

No escribas secretos en --set-env-vars. Guárdalos en Secret Manager e inyéctalos en 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"

Prefiere IAM por secreto en lugar de permisos amplios de proyecto. Reduce el impacto si una identidad se usa mal.

Concurrencia, instancias mínimas y coste

La concurrencia define cuántas peticiones simultáneas procesa una instancia. Subirla reduce instancias, pero puede saturar la base de datos o una API externa.

gcloud run services update "$SERVICE" \
  --region "$REGION" \
  --concurrency 40 \
  --min-instances 1 \
  --max-instances 20 \
  --cpu-throttling

Usa min-instances 0 en desarrollo o proyectos con poco tráfico. Usa 1 o más si un webhook o API de producción no tolera arranques en frío. Para webhooks empieza con 20-40; para BFF/API, 40-80, y ajusta con latencia p95, conexiones de base de datos y errores.

Logs y rollback

Cloud Run envía logs de petición, contenedor y sistema a Cloud Logging. Para Node.js suele bastar con escribir en 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

Cada despliegue o cambio de configuración crea una revisión inmutable. Revierte moviendo tráfico a una revisión estable.

gcloud run revisions list \
  --service "$SERVICE" \
  --region "$REGION"

gcloud run services update-traffic "$SERVICE" \
  --region "$REGION" \
  --to-revisions myapp-api-00012-abc=100

Prompt de revisión antes de producción:

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.
"

Errores habituales

Las imágenes grandes empeoran build, push y arranque en frío. Los secretos en variables normales pueden quedar en historial o logs de CI. min-instances 1 baja la latencia, pero cobra incluso sin tráfico. Una concurrencia demasiado alta puede romper la base de datos o APIs externas. El rollback debe ensayarse antes del incidente.

Referencias y siguiente paso

Cloud Run es un punto medio útil: más flexible que una plataforma solo de funciones y más ligero que ECS o Kubernetes. Para convertir prompts, revisiones y reglas de despliegue en un proceso de equipo, revisa formación y consultoría de Claude Code.

Nota de verificación práctica

El ejemplo se comprobó con npm run dev, acceso Docker a /health, manejo de PORT y validación de variables obligatorias. Antes de producción, repite la prueba con permisos reales de Artifact Registry, IAM de Secret Manager, consultas de Cloud Logging y un ensayo de rollback con update-traffic.

#claude-code #gcp #cloud-run #docker #typescript #serverless
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.