Claude Code से GCP Cloud Functions बनाना: HTTP, Secret Manager, Cloud Logging
Claude Code से Cloud Run functions बनाएं: HTTP, secrets, logging, deploy checks और आम pitfalls.
Google Cloud की मौजूदा documentation में Cloud Functions को अक्सर Cloud Run functions के रूप में समझाया जाता है। इसका व्यावहारिक मतलब यह है कि आप source code deploy करते हैं, Google Cloud उसे container में build करता है, और वह HTTP request या event से चलने वाली Cloud Run service के रूप में चलता है।
इस guide में Claude Code से GCP Cloud Functions बनाने का पूरा flow है: Node.js की एक HTTP function, Eventarc के जरिए Cloud Storage event लेने वाली function, Secret Manager, Cloud Logging, और deploy के बाद verification। Eventarc Google Cloud में events पहुँचाने वाली layer है। Functions Framework वह adapter है जिससे वही function shape local machine और cloud दोनों जगह चलती है।
ClaudeCodeLab में मैं Cloud Run functions को तब चुनता हूँ जब काम छोटा और साफ हो: webhook receive करना, हल्की notification भेजना, CSV import trigger करना, या scheduled job का entry point बनाना। अगर कई routes, full API, Next.js या Express, WebSocket, custom Dockerfile, लंबा processing time, या container पर ज्यादा control चाहिए, तो Cloud Run बेहतर है। इस पर GCP Cloud Run guide में अलग से बात की गई है।
Claude Code repeat होने वाली चीजें बनाने में अच्छा है: package.json, Functions Framework registration, curl commands, gcloud run deploy, IAM notes, और review prompt। फिर भी authentication, Secret Manager, retries, idempotency, और logs को इंसान से review कराना जरूरी है। Idempotency का मतलब है कि वही request या event दो बार आए, फिर भी result खराब या duplicate न हो।
अच्छे use cases
| Use case | Entry point | Review में क्या देखना है |
|---|---|---|
| Stripe, GitHub या internal tool webhooks | HTTP function | Signature check, Bearer token, replay handling, Secret Manager |
| Cloud Storage upload के बाद CSV import | Eventarc + CloudEvent function | Duplicate events, bucket region, file naming rules |
| Contact form notification | HTTP function या Pub/Sub handoff | तेज 200 response, queue handoff, rate limits |
| Nightly sync या report trigger | Cloud Scheduler + HTTP function | OIDC authentication, time zone, timeout |
ये cases Claude Code के लिए अच्छे हैं क्योंकि input, validation, logging, और failure behavior को checklist में बदला जा सकता है। Design तब कमजोर होता है जब एक function में बहुत सारे काम भर दिए जाएँ, लंबे loops चलें, या उसे पूरी public API बना दिया जाए।
Team process के लिए Claude Code code review और Claude Code secrets management को भी साथ पढ़ना उपयोगी है।
Minimal project
यह example CommonJS Node.js का है ताकि build step की जरूरत न पड़े। Official docs में Functions Framework से functions register की जाती हैं, और वही framework local में भी चलता है।
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
Function code
इसे index.js के रूप में save करें। HTTP function Authorization: Bearer ... check करती है और Idempotency-Key को duplicate रोकने वाली key की तरह इस्तेमाल करती है। Storage function CloudEvent ID को Firestore में save करती है ताकि retry हुआ event वही 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 });
});
Structured logs incident के समय Cloud Logging को उपयोगी बनाते हैं। Cloud Run stdout और stderr को अपने-आप Cloud Logging में भेजता है। severity, message, eventId, और userId वाली JSON lines plain text से कहीं बेहतर filter होती हैं।
Local tests
HTTP function start करें:
export API_TOKEN="local-token"
npm run start:http
दूसरे terminal से request भेजें:
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"}'
CloudEvent function start करें:
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"}'
अगर local code Firestore से connect करता है, तो gcloud auth application-default login चलाएँ या अलग test project इस्तेमाल करें। Smoke tests को production data पर न चलाएँ।
Secret Manager और IAM
Token को source code या review में जाने वाली .env file में न रखें। उसे Secret Manager में रखें और access सिर्फ runtime service account को दें।
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"
दो identities अलग रखें। Deploy करने वाले व्यक्ति को Cloud Run functions बनाने और service account इस्तेमाल करने की permission चाहिए। Runtime service account को सिर्फ वही minimum roles दें जो code सच में इस्तेमाल करता है।
gcloud run से deploy
मौजूदा flow gcloud run deploy का है। Private HTTP endpoint के लिए पहले authenticated service deploy करें:
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
Storage event function के लिए पहले service deploy करें, फिर Eventarc trigger बनाएँ:
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}"
Eventarc trigger active होने में कुछ मिनट लग सकते हैं। Bucket region, trigger location, और Cloud Run region को साथ में design करें, क्योंकि latency, data residency, और pricing पर असर पड़ता है।
Logs और verification
Deploy के बाद सिर्फ URL देखकर रुकें नहीं। Endpoint test करें और logs पढ़ें।
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
Investigation के लिए जरूरी values log करें: event ID, file name, duplicate flag, external API status, और सुरक्षित business IDs। Token, पूरा message body, या personal data log न करें।
आम pitfalls
पहला, idempotency के बिना retries duplicate side effects बनाते हैं। Billing, email, inventory, और imports में saved event ID या business key जरूरी है।
दूसरा, Secret Manager access runtime service account को मिलना चाहिए। Deploy सफल हो सकता है, लेकिन production request Permission denied से fail हो सकती है।
तीसरा, public HTTP function को सिर्फ --allow-unauthenticated पर न छोड़ें। Public webhook में signature check, rate limit, और जरूरत हो तो API Gateway या Cloud Armor जोड़ें। Internal jobs के लिए authenticated calls बेहतर हैं।
चौथा, Cloud Run functions को full application host न बनाएं। कई routes, लंबे jobs, system packages, GPU, या fine container control के लिए Cloud Run, Cloud Run jobs, या Workflows बेहतर हैं।
पाँचवां, cost और cleanup को prompt में शामिल करें। Cloud Run scale to zero कर सकता है, फिर भी Artifact Registry, Cloud Build, Storage, Eventarc, और Cloud Logging cost ला सकते हैं।
Review prompt
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 ऐसी operational checklists को products और templates तथा team training में बदलता है। इससे serverless reviews repeatable बनते हैं और वे किसी एक senior engineer की memory पर निर्भर नहीं रहते।
Official docs
- Cloud Run functions documentation
- Deploy a Cloud Run function
- Deploy a Cloud Run function using the gcloud CLI
- Write Cloud Run functions
- Local functions development
- Trigger functions from Cloud Storage using Eventarc
- Configure secrets for Cloud Run services
- Logging and viewing logs in Cloud Run
- Compare Cloud Run functions
- Cloud Run locations
परिणाम
Test किया गया आकार छोटा है, लेकिन production जैसा है: Node.js 24 Cloud Run functions, local Functions Framework commands, curl से HTTP और CloudEvent checks, Secret Manager injection, Firestore based idempotency, और Cloud Logging queries। Real traffic लेने से पहले identity, logs, retries, region, और cost review करना सबसे जरूरी आदत है।
मुफ़्त PDF: Claude Code cheatsheet
Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.
हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.
लेखक के बारे में
Masa
Claude Code workflow और team adoption पर काम करने वाला engineer.
संबंधित लेख
Claude Code Obsidian to CLAUDE.md workflow: context बार-बार न समझाएं
Obsidian notes को CLAUDE.md operating notes में बदलकर Claude Code sessions को resume करना आसान बनाएं.
Claude Code Revenue CTA Routing: article से PDF, Gumroad और consultation तक
Reader intent के आधार पर free PDF, Gumroad products और consultation तक CTA route करने वाला workflow.
Claude Code टीम हैंडऑफ नियम: review proof, permissions, rollback और revenue path
Claude Code टीम काम के लिए evidence, permission rules, rollback, free PDF, Gumroad और consultation path वाला handoff.