Use Cases (Mis à jour: 03/06/2026)

GCP Cloud Functions avec Claude Code : HTTP, Secret Manager, Cloud Logging

Créez des Cloud Run functions avec Claude Code : HTTP, secrets, logs, vérification de déploiement et pièges.

GCP Cloud Functions avec Claude Code : HTTP, Secret Manager, Cloud Logging

La documentation Google Cloud présente désormais souvent Cloud Functions via Cloud Run functions. Le modèle à retenir est simple : vous déployez du code source, Google Cloud le construit sous forme de conteneur, puis le résultat s’exécute comme un service Cloud Run appelé par HTTP ou par des événements.

Ce guide montre comment créer des GCP Cloud Functions avec Claude Code : une fonction HTTP Node.js, une fonction déclenchée par Cloud Storage via Eventarc, Secret Manager, Cloud Logging et la vérification après déploiement. Eventarc est la couche de distribution d’événements de Google Cloud. Functions Framework est l’adaptateur qui permet d’exécuter la même forme de fonction localement et dans le cloud.

Chez ClaudeCodeLab, j’utilise Cloud Run functions pour des unités petites et nettes : réception de webhooks, notification légère, déclenchement d’import CSV ou point d’entrée d’un traitement planifié. Je choisis Cloud Run lorsqu’il faut plusieurs routes, une API complète, Next.js ou Express, des WebSockets, un Dockerfile personnalisé, un traitement long ou un contrôle fin du conteneur. Le guide interne GCP Cloud Run traite ce cas.

Claude Code est utile pour générer les éléments répétables : package.json, enregistrement Functions Framework, commandes curl, gcloud run deploy, notes IAM et prompt de revue. La revue humaine reste nécessaire pour l’authentification, Secret Manager, les retries, l’idempotence et les logs. L’idempotence signifie que recevoir deux fois la même requête ou le même événement ne doit pas casser le résultat.


Cas d’usage adaptés

Cas d’usagePoint d’entréeÀ vérifier
Webhooks Stripe, GitHub ou internesFonction HTTPSignature, Bearer token, protection contre les relectures, Secret Manager
Import CSV après upload Cloud StorageEventarc + fonction CloudEventÉvénements dupliqués, région du bucket, règles de nommage
Notification de formulaire de contactFonction HTTP ou relais Pub/SubRéponse 200 rapide, passage en file, rate limits
Synchronisation nocturne ou rapportCloud Scheduler + fonction HTTPAuthentification OIDC, fuseau horaire, timeout

Ces cas fonctionnent bien avec Claude Code, car les entrées, validations, logs et comportements d’échec se transforment facilement en checklist. Le design devient fragile si une seule fonction porte trop de responsabilités, exécute des boucles longues ou devient toute l’API publique.

Pour une démarche d’équipe, ajoutez les liens internes vers la revue de code Claude Code et la gestion des secrets avec Claude Code.


Projet minimal

L’exemple utilise Node.js CommonJS pour éviter toute étape de build. La documentation officielle enregistre les fonctions avec Functions Framework, qui fonctionne aussi localement.

functions-demo/
  index.js
  package.json
{
  "name": "claude-code-gcp-functions-demo",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "scripts": {
    "start:http": "functions-framework --target=handleAction --port=8080",
    "start:event": "functions-framework --target=handleStorageObject --signature-type=cloudevent --port=8081"
  },
  "dependencies": {
    "@google-cloud/firestore": "^7.11.0",
    "@google-cloud/functions-framework": "^3.4.6"
  }
}
npm install

Code de fonction

Enregistrez ce contenu dans index.js. La fonction HTTP vérifie Authorization: Bearer ... et utilise Idempotency-Key pour éviter les doublons. La fonction Storage stocke l’ID CloudEvent dans Firestore afin qu’un événement rejoué ne crée pas deux fois le même job.

const functions = require("@google-cloud/functions-framework");
const { Firestore } = require("@google-cloud/firestore");
const crypto = require("node:crypto");

const db = new Firestore();

function jsonLog(severity, message, extra = {}) {
  console.log(JSON.stringify({ severity, message, ...extra }));
}

function requireBearerToken(req) {
  const expected = process.env.API_TOKEN;
  const header = req.get("Authorization") || "";
  return Boolean(expected && header === `Bearer ${expected}`);
}

function stableHash(value) {
  return crypto.createHash("sha256").update(value).digest("hex");
}

functions.http("handleAction", async (req, res) => {
  if (req.method !== "POST") {
    res.status(405).json({ ok: false, error: "POST only" });
    return;
  }

  if (!requireBearerToken(req)) {
    res.status(401).json({ ok: false, error: "invalid token" });
    return;
  }

  const body = req.body || {};
  if (typeof body.userId !== "string" || typeof body.action !== "string") {
    res.status(400).json({ ok: false, error: "userId and action are required" });
    return;
  }

  const idempotencyKey =
    req.get("Idempotency-Key") ||
    stableHash(`${body.userId}:${body.action}:${body.requestedAt || ""}`);

  const requestRef = db.collection("function_requests").doc(idempotencyKey);
  const logRef = db.collection("action_logs").doc(idempotencyKey);

  try {
    let duplicate = false;
    await db.runTransaction(async (tx) => {
      const existing = await tx.get(requestRef);
      if (existing.exists) {
        duplicate = true;
        return;
      }

      tx.create(requestRef, {
        userId: body.userId,
        action: body.action,
        createdAt: new Date(),
        source: "handleAction"
      });
      tx.set(logRef, {
        userId: body.userId,
        action: body.action,
        createdAt: new Date()
      });
    });

    jsonLog("INFO", "action accepted", { userId: body.userId, duplicate });
    res.status(200).json({ ok: true, duplicate, idempotencyKey });
  } catch (error) {
    jsonLog("ERROR", "action failed", { error: String(error) });
    res.status(500).json({ ok: false, error: "internal error" });
  }
});

functions.cloudEvent("handleStorageObject", async (cloudEvent) => {
  const data = cloudEvent.data || {};
  const bucket = data.bucket;
  const name = data.name;

  if (!bucket || !name) {
    jsonLog("WARNING", "storage event missing bucket or name", { eventId: cloudEvent.id });
    return;
  }

  const eventRef = db.collection("processed_storage_events").doc(cloudEvent.id);
  const jobRef = db.collection("storage_import_jobs").doc(stableHash(`${bucket}/${name}`));

  await db.runTransaction(async (tx) => {
    const existing = await tx.get(eventRef);
    if (existing.exists) {
      jsonLog("INFO", "duplicate storage event ignored", { eventId: cloudEvent.id });
      return;
    }

    tx.create(eventRef, {
      bucket,
      name,
      eventType: cloudEvent.type,
      createdAt: new Date()
    });
    tx.set(jobRef, {
      bucket,
      name,
      status: "queued",
      updatedAt: new Date()
    }, { merge: true });
  });

  jsonLog("INFO", "storage import job queued", { bucket, name, eventId: cloudEvent.id });
});

Les logs structurés rendent Cloud Logging exploitable pendant un incident. Cloud Run envoie automatiquement stdout et stderr vers Cloud Logging ; des lignes JSON avec severity, message, eventId et userId se filtrent beaucoup mieux que du texte libre.


Tests locaux

Démarrez la fonction HTTP :

export API_TOKEN="local-token"
npm run start:http

Envoyez une requête depuis un autre terminal :

curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer local-token" \
  -H "Idempotency-Key: local-001" \
  -d '{"userId":"user-123","action":"login","requestedAt":"2026-06-03T00:00:00Z"}'

Démarrez la fonction CloudEvent :

npm run start:event
curl -X POST http://localhost:8081 \
  -H "Content-Type: application/json" \
  -H "ce-id: local-event-001" \
  -H "ce-specversion: 1.0" \
  -H "ce-type: google.cloud.storage.object.v1.finalized" \
  -H "ce-source: //storage.googleapis.com/projects/_/buckets/demo-bucket" \
  -d '{"bucket":"demo-bucket","name":"inbox/sample.csv","metageneration":"1"}'

Si le code local se connecte à Firestore, utilisez gcloud auth application-default login ou un projet de test dédié. Les tests rapides ne doivent pas viser les données de production.


Secrets et IAM

Ne stockez pas les jetons dans le code source ni dans des fichiers .env qui circulent en revue. Placez-les dans Secret Manager et donnez l’accès uniquement au compte de service d’exécution.

PROJECT_ID="$(gcloud config get-value project)"
REGION="asia-northeast1"
RUNTIME_SA="functions-runtime@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts create functions-runtime \
  --display-name="Functions runtime service account"

printf "replace-with-real-token" | gcloud secrets create api-token \
  --replication-policy="automatic" \
  --data-file=-

gcloud secrets add-iam-policy-binding api-token \
  --member="serviceAccount:${RUNTIME_SA}" \
  --role="roles/secretmanager.secretAccessor"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member="serviceAccount:${RUNTIME_SA}" \
  --role="roles/datastore.user"

Séparez bien deux identités : la personne qui déploie a besoin de créer la Cloud Run function et d’utiliser le compte de service ; le compte d’exécution ne reçoit que les droits minimaux nécessaires au code.


Déployer avec gcloud run

Le flux actuel passe par gcloud run deploy. Pour un endpoint HTTP privé, commencez authentifié :

gcloud run deploy handle-action \
  --source . \
  --function handleAction \
  --base-image nodejs24 \
  --region "${REGION}" \
  --service-account "${RUNTIME_SA}" \
  --no-allow-unauthenticated \
  --memory 512Mi \
  --timeout 60s \
  --max-instances 20

gcloud run services update handle-action \
  --region "${REGION}" \
  --update-secrets=API_TOKEN=api-token:latest

Pour les événements Storage, déployez d’abord le service puis créez le déclencheur Eventarc :

BUCKET="your-import-bucket"
EVENTARC_SA="eventarc-invoker@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts create eventarc-invoker \
  --display-name="Eventarc trigger invoker"

gcloud run deploy storage-import \
  --source . \
  --function handleStorageObject \
  --base-image nodejs24 \
  --region "${REGION}" \
  --service-account "${RUNTIME_SA}" \
  --no-allow-unauthenticated \
  --memory 512Mi \
  --timeout 120s \
  --max-instances 10

gcloud run services add-iam-policy-binding storage-import \
  --region "${REGION}" \
  --member="serviceAccount:${EVENTARC_SA}" \
  --role="roles/run.invoker"

gcloud eventarc triggers create storage-finalized-to-function \
  --location="${REGION}" \
  --destination-run-service=storage-import \
  --destination-run-region="${REGION}" \
  --event-filters="type=google.cloud.storage.object.v1.finalized" \
  --event-filters="bucket=${BUCKET}" \
  --service-account="${EVENTARC_SA}"

Un déclencheur Eventarc peut mettre quelques minutes à devenir actif. Planifiez ensemble la région du bucket, la location du trigger et la région Cloud Run, car cela influence la latence, la résidence des données et les coûts.


Logs et vérification

Après le déploiement, testez l’endpoint et inspectez les logs avant de considérer la fonction prête.

SERVICE_URL="$(gcloud run services describe handle-action \
  --region "${REGION}" \
  --format='value(status.url)')"

curl -X POST "${SERVICE_URL}" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer replace-with-real-token" \
  -H "Idempotency-Key: prod-smoke-001" \
  -d '{"userId":"smoke-user","action":"deploy-check","requestedAt":"2026-06-03T00:00:00Z"}'

gcloud run services logs read handle-action \
  --region "${REGION}" \
  --limit 20

gcloud logging read \
  'resource.type="cloud_run_revision" AND resource.labels.service_name="handle-action" AND jsonPayload.message="action accepted"' \
  --limit 20 \
  --format json

Loggez ce qui aide à diagnostiquer : ID d’événement, nom de fichier, indicateur de doublon, statut d’API externe et identifiants métier sûrs. Ne loggez pas les tokens, les corps complets de messages ni les données personnelles.


Pièges fréquents

Premier piège : activer les retries sans idempotence. Facturation, e-mails, stock et imports doivent utiliser un ID d’événement ou une clé métier persistée.

Deuxième piège : accorder Secret Manager au compte de déploiement seulement. Le déploiement peut réussir alors que les requêtes échouent en production avec Permission denied.

Troisième piège : exposer une fonction HTTP publique avec seulement --allow-unauthenticated. Pour les webhooks publics, ajoutez signature, rate limits et, si nécessaire, API Gateway ou Cloud Armor. Pour les jobs internes, préférez les appels authentifiés.

Quatrième piège : transformer Cloud Run functions en hébergeur d’application complet. Plusieurs routes, jobs longs, paquets système, GPU ou contrôle fin du conteneur conviennent mieux à Cloud Run, Cloud Run jobs ou Workflows.

Cinquième piège : oublier coûts et nettoyage. Même avec scale-to-zero, Artifact Registry, Cloud Build, Storage, Eventarc et Cloud Logging peuvent générer des coûts.


Prompt de revue

Review this Cloud Run functions implementation.
Check:
- Functions Framework registration, gcloud run deploy --function, and package.json target match
- HTTP authentication, input validation, and error responses are safe
- Eventarc retries cannot create duplicate side effects
- Secret Manager values are not logged or returned in exceptions
- The runtime service account has only the minimum IAM roles
- Cloud Logging entries are structured enough for incident review
- Any workload that should be Cloud Run is not forced into a function

If there are issues, return severity, reason, corrected code, and verification commands.

ClaudeCodeLab transforme ces checklists opérationnelles en produits et modèles ainsi qu’en formations d’équipe. C’est utile lorsque vous voulez des revues serverless répétables, plutôt que dépendantes de la mémoire d’une seule personne senior.


Documentation officielle


Résultat

La forme testée reste petite, mais proche de la production : Cloud Run functions Node.js 24, commandes locales Functions Framework, vérifications HTTP et CloudEvent avec curl, injection Secret Manager, idempotence avec Firestore et requêtes Cloud Logging. Le réflexe essentiel est de revoir identité, logs, retries, région et coûts avant d’envoyer du trafic réel vers la fonction.

#claude-code #gcp #cloud-functions #typescript #serverless #pubsub
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.