Use Cases

Claude Code × GCP Cloud Run Komplettanleitung | Serverlose Container automatisch deployen

GCP Cloud Run-Deployments mit Claude Code beschleunigen. Vollständige Anleitung mit echten Code-Beispielen: Dockerfile-Generierung, Auto-Scaling, CI/CD-Pipelines und Secret Manager-Integration.

„Ich möchte Container auf GCP betreiben, aber es gibt zu viele Einstellungen — ich weiß nicht, wo ich anfangen soll” — so habe ich mich früher auch gefühlt. Als ich dann aber Cloud Run tatsächlich ausprobiert habe, war ich ehrlich gesagt überrascht, wie viel einfacher die Konfiguration im Vergleich zu ECS war. Kein VPC-Setup, kein Task-Role-Design, kein Cluster-Management. Einfach ein Container-Image vorbereiten und schon steht ein HTTPS-Endpunkt bereit.

In Kombination mit Claude Code lässt sich alles — von der Dockerfile-Generierung bis zum Cloud Build CI/CD-Pipeline-Aufbau — in erstaunlich kurzer Zeit erledigen. Dieser Artikel erklärt die Schritte, die ich tatsächlich ausprobiert habe, in 6 klaren Phasen.


Warum Cloud Run einfacher ist als ECS

Cloud Run ist GCPs vollständig verwalteter Container-Ausführungsdienst. Er nutzt ein „anforderungsgesteuertes serverloses” Modell, bei dem Container nur gestartet werden, wenn HTTP-Anfragen eintreffen.

Vergleich mit ECS:

Cloud Run:
- Cluster-Verwaltung: Nicht erforderlich
- Netzwerk-Setup:    Externes HTTPS standardmäßig veröffentlicht
- Skalierung:        Vollautomatisch von 0 bis N
- Abrechnung:        Basierend auf Anfragelaufzeit (fast kostenlos bei Leerlauf)

AWS ECS/Fargate:
- Cluster-Verwaltung: Erforderlich (3 Ebenen: Cluster / Service / TaskDef)
- Netzwerk-Setup:    VPC- und Security-Group-Design erforderlich
- Skalierung:        Abrechnung für Mindestanzahl an Instanzen
- Abrechnung:        Basierend auf laufender Task-Zeit

Für APIs, Webhook-Empfänger, Batch-Jobs und interne Microservices — alles, was „per HTTP aufgerufen wird” — ist Cloud Run fast immer die beste Wahl.


Schritt 1: Dockerfile automatisch generieren

Beginnen wir mit der Generierung eines produktionsreifen Dockerfiles für einen TypeScript Node.js API-Server. Multi-Stage-Builds und Nicht-Root-Benutzer-Konfiguration sind Sicherheitsanforderungen.

claude -p "
Generiere ein produktionsreifes Dockerfile mit folgenden Anforderungen:

- App: TypeScript + Express API (Port 8080)
- Node.js-Version: 22 LTS
- Multi-Stage-Build (builder → runner)
- Als Nicht-Root-Benutzer (node-Benutzer) ausführen
- Auch .dockerignore generieren
- PORT-Umgebungsvariable wie von Cloud Run empfohlen unterstützen
- Health-Check: /health-Endpunkt
"

Generiertes Dockerfile:

# ---- builder-Stage ----
FROM node:22-alpine AS builder
WORKDIR /app

# Abhängigkeiten zuerst kopieren, um Build-Cache zu nutzen
COPY package*.json ./
RUN npm ci --only=production=false

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

# ---- runner-Stage ----
FROM node:22-alpine AS runner
WORKDIR /app

# Sicherheit: Als Nicht-Root-Benutzer ausführen
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# Nur Produktionsabhängigkeiten installieren
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Build-Artefakte kopieren
COPY --from=builder /app/dist ./dist

# Cloud Run übergibt den Port über die PORT-Umgebungsvariable
ENV PORT=8080
ENV NODE_ENV=production

# Zu Nicht-Root-Benutzer wechseln
USER appuser

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

Schritt 2: Erster Cloud Run-Deployment

Sobald das Dockerfile fertig ist, werden die Befehle zum Deployen in Cloud Run generiert.

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

Schritt 3: Auto-Scaling konfigurieren

gcloud run services update myapp-api \
  --region asia-northeast1 \
  --min-instances 1 \
  --max-instances 20 \
  --concurrency 80 \
  --cpu-throttling \
  --execution-environment gen2
# service.yaml - Cloud Run-Dienstkonfiguration
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: myapp-api
spec:
  template:
    metadata:
      annotations:
        # Mindestanzahl an Instanzen (Cold-Start-Minderung)
        autoscaling.knative.dev/minScale: "1"
        # Höchstanzahl an Instanzen (Kostenlimit)
        autoscaling.knative.dev/maxScale: "20"
        # Skalierung bei 70% CPU-Auslastung
        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"

Schritt 4: Secret Manager-Integration

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

# Leserechte für Service-Account gewähren
gcloud projects add-iam-policy-binding my-project-123 \
  --member="serviceAccount:[email protected]" \
  --role="roles/secretmanager.secretAccessor"

# Secrets in Cloud Run einbinden
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",
};

// Beim Start prüfen, ob alle erforderlichen Secrets vorhanden sind
const requiredEnvVars = ["DATABASE_URL", "SENDGRID_API_KEY", "JWT_SECRET"];
for (const envVar of requiredEnvVars) {
  if (!process.env[envVar]) {
    console.error(`Fehlende Umgebungsvariable: ${envVar}`);
    process.exit(1);
  }
}

Schritt 5: CI/CD-Pipeline mit Cloud Build

# cloudbuild.yaml
steps:
  # Schritt 1: Abhängigkeiten installieren und Tests ausführen
  - name: "node:22-alpine"
    id: "test"
    entrypoint: "sh"
    args:
      - "-c"
      - |
        npm ci
        npm run test
        npm run lint

  # Schritt 2: Docker-Image bauen
  - 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"
      - "."

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

  # Schritt 4: In Cloud Run deployen
  - 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"

  # Schritt 5: Slack-Benachrichtigung bei Erfolg
  - name: "curlimages/curl"
    id: "notify-success"
    entrypoint: "curl"
    args:
      - "-X"
      - "POST"
      - "-H"
      - "Content-type: application/json"
      - "--data"
      - '{"text":"✅ Cloud Run-Deployment abgeschlossen: $COMMIT_SHA"}'
      - "$_SLACK_WEBHOOK_URL"

options:
  logging: CLOUD_LOGGING_ONLY
  machineType: E2_HIGHCPU_8

timeout: "1200s"

Schritt 6: Custom Domain und 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 = "SQL-Injection-Schutz"
  }
  rule {
    action   = "allow"
    priority = "2147483647"
    match {
      versioned_expr = "SRC_IPS_V1"
      config { src_ip_ranges = ["*"] }
    }
    description = "Standard-Zulassen"
  }
}

Die 5 häufigsten Fallstricke

1. Timeouts durch Cold Starts

Wenn längere Zeit kein Traffic vorhanden ist, skaliert Cloud Run auf null Instanzen. Die nächste Anfrage muss auf den Container-Start warten, was zu 1–2 Sekunden Verzögerung führt. Setzen Sie min-instances auf mindestens 1 in der Produktion.

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

2. SIGTERM nicht behandeln

Cloud Run sendet SIGTERM bei Scale-in oder Deployment. Ohne ordnungsgemäße Behandlung werden laufende Anfragen zwangsweise beendet.

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

3. Sensible Daten als Klartext in Umgebungsvariablen

# ❌ Niemals: Secrets im Klartext
gcloud run services update myapp-api --set-env-vars DATABASE_PASSWORD=mypassword123

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

4. Unzureichende Speicherkonfiguration

# Speicherproblem beheben: Node.js Heap-Größe explizit setzen
CMD ["node", "--max-old-space-size=384", "dist/index.js"]

5. Hintergrundverarbeitung außerhalb von Anfragen

Cloud Run-CPUs sind beim Nichtverarbeiten von Anfragen praktisch nicht verfügbar. Für periodische Hintergrundverarbeitung Cloud Scheduler verwenden oder immer-aktiven CPU-Modus nutzen.

gcloud run services update myapp-api --no-cpu-throttling --region asia-northeast1

Zusammenfassung

AufgabeClaude Codes Beitrag
Dockerfile-GenerierungMulti-Stage-Build und Nicht-Root-Setup automatisiert
Erster DeploymentVollständige gcloud-Befehle aus Anforderungen generiert
SkalierungskonfigurationMin/Max-Instanzen und CPU-Schwellenwerte optimiert
Secret Manager-IntegrationSecret-Erstellung, Berechtigungen und Mount-Konfiguration generiert
CI/CD-Pipelinecloudbuild.yaml mit Tests generiert
Custom DomainLoad Balancer Terraform-Konfiguration automatisch generiert

Verwandte Artikel

Referenzen

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

Kostenloses PDF: Claude-Code-Spickzettel in 5 Minuten

Trag einfach deine E-Mail-Adresse ein – wir senden dir den A4-Spickzettel als PDF sofort zu.

Wir behandeln deine Daten sorgfältig und senden niemals Spam.

Bring deinen Claude-Code-Workflow aufs nächste Level

50 in der Praxis erprobte Prompt-Vorlagen zum direkten Copy-and-paste in Claude Code.

Masa

Über den Autor

Masa

Ingenieur, der Claude Code intensiv nutzt. Betreibt claudecode-lab.com, ein Tech-Medium in 10 Sprachen mit über 2.000 Seiten.