Deploy ke GCP Cloud Run dengan Claude Code: panduan praktis
Deploy API Node.js yang aman di Cloud Run dengan Docker, IAM, secrets, logs, dan rollback.
Cloud Run cocok ketika Anda ingin memublikasikan layanan HTTP berbasis kontainer tanpa mengoperasikan Kubernetes, ECS, atau banyak VM. Dibanding Cloud Functions atau Lambda, Anda tidak perlu memecah seluruh aplikasi menjadi fungsi kecil. API Express biasa bisa dikemas sebagai image Docker, lalu Google Cloud menangani HTTPS, revision, scaling, dan logs.
Panduan ini menunjukkan cara memakai Claude Code untuk membawa API TypeScript/Express dari lokal ke Cloud Run. Isinya mencakup kode yang bisa dijalankan, Dockerfile, tes lokal, Artifact Registry, gcloud run deploy, service account, IAM, Secret Manager, concurrency, min instances, Cloud Logging, rollback revision, jebakan biaya, dan prompt review deployment.
Secara sederhana: Cloud Run adalah platform serverless untuk menjalankan kontainer yang merespons HTTP. Artifact Registry adalah tempat menyimpan image Docker. Secret Manager adalah brankas untuk password dan API key. IAM adalah sistem permission yang menentukan identity mana boleh mengakses resource apa.
Kapan Cloud Run lebih cocok dari Functions atau Lambda
Cloud Run tidak selalu lebih baik dari Cloud Functions atau Lambda. Untuk event handler yang sangat kecil, function bisa lebih sederhana. Cloud Run unggul ketika layanan sudah berupa aplikasi HTTP atau ketika runtime dan dependency perlu lebih banyak kontrol.
| Use case | Mengapa Cloud Run cocok |
|---|---|
| Penerima webhook | Stripe, GitHub, dan LINE bisa dipetakan alami ke route Express |
| BFF atau API kecil | Auth, middleware, routing, dan validasi tetap berada di satu app Node.js |
| Endpoint HTTP untuk batch terjadwal | Cloud Scheduler bisa memanggil via HTTP tanpa framework job terpisah |
| API AI/data ringan | Dependency native dan binary custom bisa dimasukkan ke kontainer |
Untuk worker yang berjalan lama, review CPU allocation dan biaya terlebih dahulu. Cloud Run kuat untuk layanan berbasis request, tetapi bukan jawaban default untuk background loop.
Service Express yang bisa dijalankan
Cloud Run memberikan port melalui environment variable PORT. Service harus membaca nilai ini, menyediakan /health, dan shutdown dengan rapi saat menerima SIGTERM.
{
"name": "cloud-run-claude-code-api",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "tsx src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"test": "node --test"
},
"dependencies": {
"express": "^4.19.2"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^22.10.0",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
}
}
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}
import express from "express";
const app = express();
app.use(express.json());
const requiredEnv = ["DATABASE_URL", "JWT_SECRET"];
for (const key of requiredEnv) {
if (!process.env[key]) {
console.error(`Missing required environment variable: ${key}`);
process.exit(1);
}
}
app.get("/health", (_req, res) => {
res.status(200).json({ ok: true, service: "myapp-api" });
});
app.post("/webhooks/example", (req, res) => {
console.log("webhook_received", {
eventType: req.body?.type ?? "unknown",
receivedAt: new Date().toISOString()
});
res.status(202).json({ accepted: true });
});
app.get("/config-check", (_req, res) => {
res.json({
nodeEnv: process.env.NODE_ENV ?? "development",
hasDatabaseUrl: Boolean(process.env.DATABASE_URL),
hasJwtSecret: Boolean(process.env.JWT_SECRET)
});
});
const port = Number(process.env.PORT ?? 8080);
const server = app.listen(port, () => {
console.log(`listening on ${port}`);
});
process.on("SIGTERM", () => {
console.log("SIGTERM received, closing HTTP server");
server.close(() => process.exit(0));
setTimeout(() => process.exit(1), 30000).unref();
});
Tes lokal dulu:
npm install
DATABASE_URL="postgresql://local" JWT_SECRET="local-secret" npm run dev
curl http://localhost:8080/health
curl -X POST http://localhost:8080/webhooks/example \
-H "Content-Type: application/json" \
-d '{"type":"demo.created"}'
Dockerfile dan review Claude Code
Minta Claude Code melakukan review produksi, bukan hanya membuat file. Periksa image runtime kecil, dependency production saja, user non-root, .dockerignore, dukungan PORT, serta risiko keamanan dan biaya.
claude -p "
Review and improve this Cloud Run Docker setup.
Requirements:
- Node.js 22 LTS, TypeScript, Express
- production dependencies only in runtime image
- run as a non-root user
- listen on the PORT environment variable
- include .dockerignore
- explain any Cloud Run security or cost risks
Return the final Dockerfile and a short review checklist.
"
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=8080
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=builder /app/dist ./dist
USER appuser
EXPOSE 8080
CMD ["node", "--max-old-space-size=384", "dist/index.js"]
node_modules
dist
.env
.env.*
*.log
.git
.gitignore
Dockerfile
README.md
docker build -t myapp-api:local .
docker run --rm -p 8080:8080 \
-e PORT=8080 \
-e DATABASE_URL="postgresql://local" \
-e JWT_SECRET="local-secret" \
myapp-api:local
curl http://localhost:8080/health
Artifact Registry dan deploy pertama
Artifact Registry menyimpan image Docker. Konfigurasikan autentikasi Docker untuk host regional, buat repository, lalu push image.
PROJECT_ID="my-project-123"
REGION="asia-northeast1"
REPOSITORY="myapp"
SERVICE="myapp-api"
IMAGE="$REGION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/api:v1.0.0"
gcloud config set project "$PROJECT_ID"
gcloud services enable run.googleapis.com artifactregistry.googleapis.com secretmanager.googleapis.com logging.googleapis.com
gcloud artifacts repositories create "$REPOSITORY" \
--repository-format=docker \
--location="$REGION" \
--description="Docker images for myapp"
gcloud auth configure-docker "$REGION-docker.pkg.dev"
docker build -t "$IMAGE" .
docker push "$IMAGE"
Buat service account runtime khusus sebelum deploy.
gcloud iam service-accounts create myapp-run \
--display-name="Cloud Run runtime for myapp"
SERVICE_ACCOUNT="myapp-run@$PROJECT_ID.iam.gserviceaccount.com"
gcloud run deploy "$SERVICE" \
--image "$IMAGE" \
--region "$REGION" \
--platform managed \
--service-account "$SERVICE_ACCOUNT" \
--memory 512Mi \
--cpu 1 \
--concurrency 80 \
--min-instances 0 \
--max-instances 20 \
--allow-unauthenticated \
--set-env-vars NODE_ENV=production \
--port 8080
Untuk API internal, hapus --allow-unauthenticated dan berikan Cloud Run Invoker hanya kepada caller yang perlu.
Secret Manager, IAM, dan keamanan
Jangan menulis secret di --set-env-vars. Simpan di Secret Manager dan inject ke Cloud Run.
echo -n "postgresql://user:password@host:5432/app" | \
gcloud secrets create DATABASE_URL --data-file=-
echo -n "replace-with-long-random-value" | \
gcloud secrets create JWT_SECRET --data-file=-
gcloud secrets add-iam-policy-binding DATABASE_URL \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding JWT_SECRET \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/secretmanager.secretAccessor"
gcloud run services update "$SERVICE" \
--region "$REGION" \
--set-secrets "DATABASE_URL=DATABASE_URL:latest,JWT_SECRET=JWT_SECRET:latest"
IAM per secret lebih aman daripada role project yang terlalu luas. Dampak kesalahan konfigurasi menjadi lebih kecil.
Concurrency, min instances, dan biaya
Concurrency adalah jumlah request simultan maksimum yang diproses satu instance. Nilai tinggi bisa mengurangi instance, tetapi database pool atau API eksternal bisa lebih dulu penuh.
gcloud run services update "$SERVICE" \
--region "$REGION" \
--concurrency 40 \
--min-instances 1 \
--max-instances 20 \
--cpu-throttling
Gunakan min-instances 0 untuk development dan traffic rendah. Gunakan 1 atau lebih jika webhook atau API production tidak boleh terkena cold start. Mulai webhook di 20-40, BFF/API di 40-80, lalu sesuaikan dengan p95 latency, koneksi database, dan error rate.
Cloud Logging dan rollback
Cloud Run mengirim request logs, container logs, dan system logs ke Cloud Logging. Untuk Node.js, stdout/stderr biasanya cukup.
gcloud run services logs read "$SERVICE" \
--region "$REGION" \
--limit 20
gcloud logging read \
"resource.type=cloud_run_revision AND resource.labels.service_name=$SERVICE" \
--limit 20 \
--format=json
Setiap deploy atau perubahan konfigurasi membuat revision immutable. Jika bermasalah, pindahkan traffic ke revision yang stabil.
gcloud run revisions list \
--service "$SERVICE" \
--region "$REGION"
gcloud run services update-traffic "$SERVICE" \
--region "$REGION" \
--to-revisions myapp-api-00012-abc=100
Prompt review sebelum production:
claude -p "
Act as a Cloud Run deployment reviewer.
Review package.json, Dockerfile, src/index.ts, and the gcloud commands below.
Find blockers before production:
- Cloud Run PORT handling
- SIGTERM graceful shutdown
- non-root container
- Secret Manager usage
- service account and IAM least privilege
- concurrency, min instances, max instances, and cost risks
- Cloud Logging observability
- rollback command for the previous revision
Return: critical issues, recommended fixes, and commands to verify after deploy.
"
Jebakan umum
Image besar memperlambat build, push, dan cold start. Secret di environment variable biasa bisa bocor ke history atau log CI. min-instances 1 menurunkan latency, tetapi tetap menambah biaya saat idle. Concurrency terlalu tinggi bisa menekan database dan SaaS eksternal. Perintah rollback sebaiknya dilatih sebelum insiden terjadi.
Referensi dan langkah berikutnya
- Dokumentasi Cloud Run
- Deploy container image ke Cloud Run
- Autentikasi Docker Artifact Registry
- Konfigurasi secrets Cloud Run
- Logging Cloud Run
- Rollback dan migrasi traffic Cloud Run
- Integrasi Docker Claude Code
- Panduan Claude Code AWS ECS/Fargate
- Praktik keamanan Claude Code
Cloud Run adalah jalan tengah yang praktis: lebih fleksibel dari platform function-only dan lebih ringan daripada ECS atau Kubernetes. Untuk menerapkan prompt, checklist review, dan guardrail deployment di tim, lihat training dan konsultasi Claude Code.
Catatan verifikasi langsung
Contoh ini dicek dengan npm run dev, akses Docker ke /health, handling PORT, dan validasi environment wajib. Sebelum production, cek permission Artifact Registry nyata, IAM Secret Manager, query Cloud Logging, dan latihan rollback dengan update-traffic.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.
Artikel terkait
Workflow Obsidian ke CLAUDE.md untuk Claude Code
Ubah catatan kerja Obsidian menjadi operating note CLAUDE.md agar konteks tidak dijelaskan ulang.
Claude Code Revenue CTA Routing: dari artikel ke PDF, Gumroad, dan konsultasi
Workflow Claude Code untuk mengarahkan pembaca ke PDF gratis, Gumroad, atau konsultasi sesuai intent.
Aturan handoff tim Claude Code: bukti review, permission, rollback, dan jalur revenue
Format handoff Claude Code untuk tim: bukti, permission rule, rollback, PDF gratis, Gumroad, dan konsultasi.