Claude Code × GCP Cloud Functions Komplettanleitung | Serverlose Funktionen blitzschnell entwickeln
GCP Cloud Functions mit Claude Code optimieren. HTTP/Pub/Sub/Firestore-Trigger implementieren, lokal testen und Deployments automatisieren — mit echten Codebeispielen aus Masas Praxiserfahrung.
Cloud Run war überdimensioniert — deshalb wechselte ich zu Cloud Functions
Ich bin Masa, Entwickler hinter claudecode-lab.com.
Als ich anfing, GCP Serverless zu nutzen, habe ich zunächst Cloud Run in Betracht gezogen. Flexibel, containerbasiert — aber für Aufgaben wie „nur einen einzelnen Webhook empfangen” oder „einmal nachts einen Batch-Job ausführen” war es eindeutig zu komplex. Dockerfile schreiben, Cloud Build konfigurieren, Service Accounts erstellen… zu viel Aufwand für so einfache Anforderungen.
Da wechselte ich zu Cloud Functions (2. Generation / Gen2). Eine einzelne Funktion deployen und sofort ist ein HTTPS-Endpunkt verfügbar — kostenlos, wenn sie nicht genutzt wird. Es fühlt sich genau wie AWS Lambda an, mit nahtloser Integration in das GCP-Ökosystem (Pub/Sub, Firestore, Cloud Scheduler).
Das Problem war, dass ich bei jedem Mal in der Dokumentation nachschauen musste: „Wie schreibt man die Trigger-Konfiguration nochmal?” „Was ist der lokale Startbefehl für das Functions Framework?” Claude Code hat das alles gelöst. Jetzt sind über 90 % meines Cloud-Functions-Codes von Claude Code generiert.
Schritt 1: HTTP-Trigger-Funktion
import { http, HttpFunction } from "@google-cloud/functions-framework";
import { Request, Response } from "express";
import { Firestore } from "@google-cloud/firestore";
const db = new Firestore();
const VALID_TOKEN = process.env.API_SECRET_TOKEN;
interface ActionRequest {
userId: string;
action: string;
}
const handleAction: HttpFunction = async (req: Request, res: Response) => {
// CORS-Header setzen
res.set("Access-Control-Allow-Origin", "*");
if (req.method === "OPTIONS") {
res.set("Access-Control-Allow-Methods", "POST");
res.set("Access-Control-Allow-Headers", "Authorization, Content-Type");
res.status(204).send("");
return;
}
// Nur POST erlauben
if (req.method !== "POST") {
res.status(405).json({ success: false, message: "Method Not Allowed" });
return;
}
// Bearer-Token validieren
const authHeader = req.headers.authorization ?? "";
if (!authHeader.startsWith("Bearer ") || authHeader.slice(7) !== VALID_TOKEN) {
res.status(401).json({ success: false, message: "Unauthorized" });
return;
}
const body = req.body as Partial<ActionRequest>;
if (!body.userId || !body.action) {
res.status(400).json({ success: false, message: "userId and action are required" });
return;
}
try {
const logRef = await db.collection("action_logs").add({
userId: body.userId,
action: body.action,
timestamp: new Date(),
ip: req.ip,
});
res.status(200).json({ success: true, message: "Action logged", logId: logRef.id });
} catch (err) {
console.error("Firestore write error:", err);
res.status(500).json({ success: false, message: "Internal Server Error" });
}
};
http("handleAction", handleAction);
Schritt 2: Pub/Sub-Trigger-Funktion
import { cloudEvent, CloudEvent } from "@google-cloud/functions-framework";
import { MessagePublishedData } from "@google/events/cloud/pubsub/v1/MessagePublishedData";
import { Storage } from "@google-cloud/storage";
const storage = new Storage();
interface ImageUploadedMessage {
bucketName: string;
filePath: string;
}
cloudEvent<MessagePublishedData>("handleImageUploaded", async (event: CloudEvent<MessagePublishedData>) => {
const base64Data = event.data?.message?.data;
if (!base64Data) {
console.warn("Keine Nachrichtendaten empfangen, wird übersprungen");
return;
}
const rawJson = Buffer.from(base64Data, "base64").toString("utf-8");
let payload: ImageUploadedMessage;
try {
payload = JSON.parse(rawJson) as ImageUploadedMessage;
} catch {
console.error("Ungültiges JSON in Pub/Sub-Nachricht:", rawJson);
return;
}
const { bucketName, filePath } = payload;
try {
const [metadata] = await storage.bucket(bucketName).file(filePath).getMetadata();
console.log("Datei-Metadaten:", { name: metadata.name, size: metadata.size });
} catch (err) {
// Ausnahme werfen, damit Pub/Sub die Nachricht erneut versucht
console.error(`Verarbeitung von ${filePath} fehlgeschlagen:`, err);
throw err;
}
});
Schritt 3: Firestore-Trigger-Funktion
import { onDocumentWritten, Change, FirestoreEvent } from "firebase-functions/v2/firestore";
import { QueryDocumentSnapshot } from "firebase-admin/firestore";
import * as admin from "firebase-admin";
admin.initializeApp();
const db = admin.firestore();
export const onUserWrite = onDocumentWritten(
"users/{userId}",
async (event: FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, { userId: string }>) => {
const userId = event.params.userId;
const before = event.data?.before;
const after = event.data?.after;
// Erstellungsereignis
if (!before?.exists && after?.exists) {
const userData = after.data();
await db.collection("email_queue").add({
to: userData?.email,
template: "welcome",
createdAt: admin.firestore.FieldValue.serverTimestamp(),
status: "pending",
});
return;
}
// Löschereignis — in Archiv-Sammlung kopieren
if (before?.exists && !after?.exists) {
await db.collection("deleted_users").doc(userId).set({
...before.data(),
deletedAt: admin.firestore.FieldValue.serverTimestamp(),
});
}
}
);
Schritt 4: Lokales Testen & Deployment
# Lokaler Start
npm run build
npx @google-cloud/functions-framework --target=handleAction --port=8080
# Test-Anfrage senden
curl -X POST http://localhost:8080 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer test-token" \
-d '{"userId": "user-123", "action": "login"}'
# Deployment
gcloud functions deploy handleAction \
--gen2 \
--runtime=nodejs22 \
--region=europe-west1 \
--source=. \
--entry-point=handleAction \
--trigger-http \
--allow-unauthenticated \
--memory=512Mi \
--timeout=60s \
--set-secrets="API_SECRET_TOKEN=api-secret-token:latest"
4 häufige Fallstricke
| Fallstrick | Problem | Lösung |
|---|---|---|
| Cold Start | Latenz von 2–5 s bei Inaktivität | --min-instances=1 für kritische Funktionen |
| Timeout-Limit | Max. 9 Minuten (540 s) | Große Aufgaben per Pub/Sub aufteilen |
| Secret Manager-Berechtigungen | Permission denied zur Laufzeit | IAM-Rolle secretmanager.secretAccessor vergeben |
| Speichermangel | OOM bei schwerer Verarbeitung | --memory=2Gi --cpu=2 setzen |
Zusammenfassung
| Trigger | Anwendungsfall | Hauptpunkt |
|---|---|---|
| HTTP | Webhooks, API-Endpunkte | Authentifizierung, CORS |
| Pub/Sub | Asynchrone Ereignisverarbeitung | base64-Dekodierung, Retry-Design |
| Firestore | Auf Datenänderungen reagieren | Endlosschleifen vermeiden |
| Cloud Scheduler | Geplante Batch-Jobs | OIDC-Validierung, Zeitzone |
Verwandte Artikel
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.
Ü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.
Ähnliche Artikel
Was sind Codex Automations? Content Ops mit KI planen und ausfuehren
Praktischer Leitfaden fuer Codex Automations: Analytics, Themenwahl, Artikel, CTA, Deployment und Monetarisierung.
Firestore-Schema mit Claude Code entwerfen: Erst Queries, dann Collections
Ein praxisnaher Workflow für Firestore: Query-first Design, Indexe, Kosten, Security Rules und TypeScript-Beispiele mit Claude Code.
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.