Use Cases

Claude Code × GCP Cloud Run Guia Completo | Deploy Automático de Contêineres Serverless

Acelere os deploys no GCP Cloud Run com Claude Code. Guia completo com exemplos de código reais: geração de Dockerfile, auto-scaling, pipelines CI/CD e integração com Secret Manager.

“Quero rodar contêineres no GCP, mas há muitas configurações — não sei por onde começar” — eu mesmo me sentia assim antes. Mas quando realmente coloquei as mãos no Cloud Run, fiquei genuinamente surpreso com o quão mais simples era a configuração comparada ao ECS. Sem configuração de VPC, sem design de roles de tarefa, sem gerenciamento de cluster. Basta preparar uma imagem de contêiner e você tem um endpoint HTTPS quase imediatamente.

Combine isso com Claude Code, e tudo — desde a geração do Dockerfile até a configuração do pipeline CI/CD do Cloud Build — pode ser feito em um tempo surpreendentemente curto. Este artigo explica os passos que realmente tentei, em 6 etapas claras.


Por Que o Cloud Run é Mais Simples que o ECS

O Cloud Run é o serviço de execução de contêineres totalmente gerenciado do GCP. Usa um modelo “serverless orientado a requisições” onde os contêineres só iniciam quando chegam requisições HTTP.

Cloud Run:
- Gerenciamento de cluster: Não necessário
- Configuração de rede:     HTTPS externo publicado por padrão
- Escalonamento:            Totalmente automático de 0 a N
- Cobrança:                 Baseada no tempo de processamento de requisições (quase gratuito em repouso)

AWS ECS/Fargate:
- Gerenciamento de cluster: Necessário (3 camadas: Cluster / Service / TaskDef)
- Configuração de rede:     Design de VPC e grupos de segurança necessário
- Escalonamento:            Cobrança pelo número mínimo de instâncias
- Cobrança:                 Baseada no tempo de tarefa em execução

Passo 1: Gerar Dockerfile Automaticamente

claude -p "
Gere um Dockerfile pronto para produção com os seguintes requisitos:

- App: TypeScript + Express API (porta 8080)
- Versão do Node.js: 22 LTS
- Build multi-estágio (builder → runner)
- Executar como usuário não-root (usuário node)
- Gerar também .dockerignore
- Suporte à variável de ambiente PORT como recomendado pelo Cloud Run
- Health check: endpoint /health
"

Dockerfile gerado:

# ---- estágio builder ----
FROM node:22-alpine AS builder
WORKDIR /app

# Copiar dependências primeiro para aproveitar o cache de build
COPY package*.json ./
RUN npm ci --only=production=false

COPY tsconfig.json ./
COPY src ./src
RUN npm run build

# ---- estágio runner ----
FROM node:22-alpine AS runner
WORKDIR /app

# Segurança: executar como usuário não-root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# Instalar apenas dependências de produção
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Copiar artefatos do build
COPY --from=builder /app/dist ./dist

# Cloud Run passa a porta via a variável de ambiente PORT
ENV PORT=8080
ENV NODE_ENV=production

# Mudar para usuário não-root
USER appuser

EXPOSE 8080
CMD ["node", "dist/index.js"]

Passo 2: Primeiro Deploy no Cloud Run

gcloud run deploy myapp-api \
  --image asia-northeast1-docker.pkg.dev/my-project-123/myapp/api:v1.0.0 \
  --region asia-northeast1 \
  --platform managed \
  --memory 512Mi \
  --cpu 1 \
  --concurrency 80 \
  --allow-unauthenticated \
  --set-env-vars NODE_ENV=production \
  --port 8080

Passo 3: Configurar Auto-Scaling

gcloud run services update myapp-api \
  --region asia-northeast1 \
  --min-instances 1 \
  --max-instances 20 \
  --concurrency 80 \
  --cpu-throttling \
  --execution-environment gen2
# service.yaml - Configuração do serviço Cloud Run
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: myapp-api
spec:
  template:
    metadata:
      annotations:
        # Número mínimo de instâncias (mitigação de cold start)
        autoscaling.knative.dev/minScale: "1"
        # Número máximo de instâncias (limite de custo)
        autoscaling.knative.dev/maxScale: "20"
        # Scale out a 70% de uso de CPU
        autoscaling.knative.dev/target-utilization-percentage: "70"
        run.googleapis.com/execution-environment: gen2
    spec:
      containerConcurrency: 80
      containers:
        - image: asia-northeast1-docker.pkg.dev/my-project-123/myapp/api:latest
          resources:
            limits:
              memory: 512Mi
              cpu: "1"

Passo 4: Integração com Secret Manager

# Registrar segredos
echo -n "postgresql://user:password@host:5432/db" | \
  gcloud secrets create DATABASE_URL --data-file=-

# Conceder permissão de leitura à conta de serviço
gcloud projects add-iam-policy-binding my-project-123 \
  --member="serviceAccount:[email protected]" \
  --role="roles/secretmanager.secretAccessor"

# Montar segredos no Cloud Run
gcloud run services update myapp-api \
  --region asia-northeast1 \
  --set-secrets="DATABASE_URL=DATABASE_URL:latest,SENDGRID_API_KEY=SENDGRID_API_KEY:latest,JWT_SECRET=JWT_SECRET:latest"
// src/config.ts
export const config = {
  databaseUrl: process.env.DATABASE_URL!,
  sendgridApiKey: process.env.SENDGRID_API_KEY!,
  jwtSecret: process.env.JWT_SECRET!,
  port: parseInt(process.env.PORT || "8080", 10),
  nodeEnv: process.env.NODE_ENV || "development",
};

// Validar segredos necessários na inicialização
const requiredEnvVars = ["DATABASE_URL", "SENDGRID_API_KEY", "JWT_SECRET"];
for (const envVar of requiredEnvVars) {
  if (!process.env[envVar]) {
    console.error(`Variável de ambiente obrigatória ausente: ${envVar}`);
    process.exit(1);
  }
}

Passo 5: Pipeline CI/CD com Cloud Build

# cloudbuild.yaml
steps:
  # Passo 1: Instalar dependências e executar testes
  - name: "node:22-alpine"
    id: "test"
    entrypoint: "sh"
    args:
      - "-c"
      - |
        npm ci
        npm run test
        npm run lint

  # Passo 2: Construir imagem Docker
  - name: "gcr.io/cloud-builders/docker"
    id: "build"
    args:
      - "build"
      - "-t"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:$COMMIT_SHA"
      - "-t"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:latest"
      - "."

  # Passo 3: Enviar para Artifact Registry
  - name: "gcr.io/cloud-builders/docker"
    id: "push"
    args:
      - "push"
      - "--all-tags"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api"

  # Passo 4: Deploy no Cloud Run
  - name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
    id: "deploy"
    entrypoint: "gcloud"
    args:
      - "run"
      - "deploy"
      - "myapp-api"
      - "--image"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:$COMMIT_SHA"
      - "--region"
      - "asia-northeast1"
      - "--platform"
      - "managed"
      - "--quiet"

  # Passo 5: Notificação Slack (em caso de sucesso)
  - name: "curlimages/curl"
    id: "notify-success"
    entrypoint: "curl"
    args:
      - "-X"
      - "POST"
      - "-H"
      - "Content-type: application/json"
      - "--data"
      - '{"text":"✅ Deploy Cloud Run concluído: $COMMIT_SHA"}'
      - "$_SLACK_WEBHOOK_URL"

options:
  logging: CLOUD_LOGGING_ONLY
  machineType: E2_HIGHCPU_8
timeout: "1200s"

Passo 6: Domínio Personalizado e Load Balancer

# main.tf - Cloud Run + Load Balancer + SSL
resource "google_compute_region_network_endpoint_group" "cloudrun_neg" {
  name                  = "myapp-neg"
  network_endpoint_type = "SERVERLESS"
  region                = "asia-northeast1"
  cloud_run {
    service = "myapp-api"
  }
}

resource "google_compute_managed_ssl_certificate" "default" {
  name = "myapp-ssl-cert"
  managed {
    domains = ["api.example.com"]
  }
}

resource "google_compute_security_policy" "policy" {
  name = "myapp-security-policy"
  rule {
    action   = "deny(403)"
    priority = "1000"
    match {
      expr {
        expression = "evaluatePreconfiguredExpr('sqli-stable')"
      }
    }
    description = "Proteção contra injeção SQL"
  }
  rule {
    action   = "allow"
    priority = "2147483647"
    match {
      versioned_expr = "SRC_IPS_V1"
      config { src_ip_ranges = ["*"] }
    }
    description = "Permitir por padrão"
  }
}

Os 5 Erros Mais Comuns

1. Timeouts causados por cold starts

Configure min-instances para pelo menos 1 em produção.

gcloud run services update myapp-api --min-instances 1 --region asia-northeast1

2. Não tratar SIGTERM

// src/index.ts - Tratar SIGTERM corretamente
process.on("SIGTERM", () => {
  server.close(() => process.exit(0));
  setTimeout(() => process.exit(1), 30000);
});

3. Dados sensíveis em texto puro em variáveis de ambiente

# ❌ Nunca: segredos em texto puro
gcloud run services update myapp-api --set-env-vars DATABASE_PASSWORD=mypassword123

# ✅ Correto: usar Secret Manager
gcloud run services update myapp-api --set-secrets="DATABASE_PASSWORD=DATABASE_PASSWORD:latest"

4. Configuração de memória insuficiente

# Solução: definir explicitamente o tamanho do heap do Node.js
CMD ["node", "--max-old-space-size=384", "dist/index.js"]

5. Processamento em segundo plano fora de requisições

# Modo CPU sempre ativo (para serviços que precisam de processamento em segundo plano)
gcloud run services update myapp-api --no-cpu-throttling --region asia-northeast1

Resumo

TarefaContribuição do Claude Code
Geração de DockerfileBuild multi-estágio e configuração não-root automatizados
Primeiro deployComandos gcloud completos gerados a partir de requisitos
Configuração de scalingInstâncias mín/máx e limites de CPU otimizados
Integração Secret ManagerCriação de segredos, permissões e configuração de montagem gerados
Pipeline CI/CDcloudbuild.yaml com testes gerado
Domínio personalizadoConfiguração Terraform do load balancer gerada automaticamente

Artigos Relacionados

Referências

#claude-code #gcp #cloud-run #docker #typescript #serverless
Grátis

PDF gratuito: Cheatsheet do Claude Code em 5 minutos

Basta informar seu e-mail e enviamos na hora o cheatsheet em uma página A4.

Cuidamos dos seus dados pessoais e nunca enviamos spam.

Leve seu fluxo no Claude Code a outro nível

50 modelos de prompt testados em campo, prontos para colar direto no Claude Code.

Masa

Sobre o autor

Masa

Engenheiro apaixonado por Claude Code. Mantém o claudecode-lab.com, uma mídia tech em 10 idiomas com mais de 2.000 páginas.