Claude Code × GCP Cloud Run 완전 가이드 | 서버리스 컨테이너 자동 배포
Claude Code로 GCP Cloud Run 배포를 빠르게. Dockerfile 생성, 자동 스케일링, CI/CD 파이프라인, Secret Manager 연동까지 실제 코드로 완전 해설.
“GCP에서 컨테이너를 실행하고 싶은데 설정이 너무 많아서 어디서 시작해야 할지 모르겠다” — 저도 예전에 그렇게 느꼈습니다. 그런데 Cloud Run을 실제로 사용해보니 ECS에 비해 설정이 훨씬 간단해서 놀랐습니다. VPC 설정 없이, 태스크 롤 설계 없이, 클러스터 관리 없이. 컨테이너 이미지만 준비하면 거의 즉시 HTTPS 엔드포인트가 생성됩니다.
Claude Code와 조합하면 Dockerfile 생성부터 Cloud Build CI/CD 파이프라인 구축까지 놀랍도록 짧은 시간에 완료됩니다. 이 글에서는 제가 실제로 시도한 단계를 6단계로 설명합니다.
Cloud Run이 ECS보다 간단한 이유
Cloud Run은 GCP의 완전 관리형 컨테이너 실행 서비스입니다. HTTP 요청이 들어올 때만 컨테이너가 시작되는 “요청 기반 서버리스” 모델을 사용합니다.
ECS와의 비교:
Cloud Run:
- 클러스터 관리: 불필요
- 네트워크 설정: 기본적으로 외부 HTTPS 공개
- 스케일링: 0대~N대 완전 자동
- 요금: 요청 처리 시간 기반 (유휴 시 거의 무료)
AWS ECS/Fargate:
- 클러스터 관리: 필요 (Cluster / Service / TaskDef 3계층)
- 네트워크 설정: VPC 및 보안 그룹 설계 필요
- 스케일링: 최소 인스턴스 수 요금 발생
- 요금: 실행 중인 태스크 시간 기반
Step 1: Dockerfile 자동 생성
claude -p "
다음 조건으로 프로덕션 수준의 Dockerfile을 생성해줘.
- 앱: TypeScript + Express API (포트 8080)
- Node.js 버전: 22 LTS
- 멀티스테이지 빌드 (builder → runner)
- 비루트 사용자 (node 사용자)로 실행
- .dockerignore도 함께 생성
- Cloud Run 권장 PORT 환경변수 대응
- 헬스체크: /health 엔드포인트
"
생성된 Dockerfile:
# ---- builder 스테이지 ----
FROM node:22-alpine AS builder
WORKDIR /app
# 빌드 캐시 활용을 위해 먼저 의존성 복사
COPY package*.json ./
RUN npm ci --only=production=false
COPY tsconfig.json ./
COPY src ./src
RUN npm run build
# ---- runner 스테이지 ----
FROM node:22-alpine AS runner
WORKDIR /app
# 보안: 비루트 사용자로 실행
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 프로덕션 의존성만 설치
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# 빌드 결과물 복사
COPY /app/dist ./dist
# Cloud Run은 PORT 환경변수로 포트를 전달
ENV PORT=8080
ENV NODE_ENV=production
# 비루트 사용자로 전환
USER appuser
EXPOSE 8080
CMD ["node", "dist/index.js"]
Step 2: Cloud Run 최초 배포
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
Step 3: 자동 스케일링 설정
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 서비스 설정 파일
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: myapp-api
spec:
template:
metadata:
annotations:
# 최소 인스턴스 수 (콜드 스타트 대책)
autoscaling.knative.dev/minScale: "1"
# 최대 인스턴스 수 (비용 상한)
autoscaling.knative.dev/maxScale: "20"
# CPU 사용률 70%에서 스케일아웃
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"
Step 4: Secret Manager 연동
# 시크릿 등록
echo -n "postgresql://user:password@host:5432/db" | \
gcloud secrets create DATABASE_URL --data-file=-
# 서비스 계정에 읽기 권한 부여
gcloud projects add-iam-policy-binding my-project-123 \
--member="serviceAccount:[email protected]" \
--role="roles/secretmanager.secretAccessor"
# Cloud Run에 시크릿 마운트
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",
};
// 시작 시 필수 시크릿 검증
const requiredEnvVars = ["DATABASE_URL", "SENDGRID_API_KEY", "JWT_SECRET"];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
console.error(`Missing required environment variable: ${envVar}`);
process.exit(1);
}
}
Step 5: Cloud Build CI/CD 파이프라인 구축
# cloudbuild.yaml
steps:
# Step 1: 의존성 설치 및 테스트 실행
- name: "node:22-alpine"
id: "test"
entrypoint: "sh"
args:
- "-c"
- |
npm ci
npm run test
npm run lint
# Step 2: Docker 이미지 빌드
- 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"
- "."
# Step 3: Artifact Registry에 푸시
- name: "gcr.io/cloud-builders/docker"
id: "push"
args:
- "push"
- "--all-tags"
- "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api"
# Step 4: Cloud Run에 배포
- 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"
# Step 5: Slack 알림 (성공 시)
- name: "curlimages/curl"
id: "notify-success"
entrypoint: "curl"
args:
- "-X"
- "POST"
- "-H"
- "Content-type: application/json"
- "--data"
- '{"text":"✅ Cloud Run 배포 완료: $COMMIT_SHA"}'
- "$_SLACK_WEBHOOK_URL"
options:
logging: CLOUD_LOGGING_ONLY
machineType: E2_HIGHCPU_8
timeout: "1200s"
Step 6: 커스텀 도메인 설정과 로드 밸런서
# 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 인젝션 대책"
}
rule {
action = "allow"
priority = "2147483647"
match {
versioned_expr = "SRC_IPS_V1"
config { src_ip_ranges = ["*"] }
}
description = "기본 허용"
}
}
함정 5선
1. 콜드 스타트로 인한 타임아웃
프로덕션에서 min-instances를 1 이상으로 설정하세요.
gcloud run services update myapp-api --min-instances 1 --region asia-northeast1
2. SIGTERM 처리를 잊어버리는 경우
// src/index.ts - SIGTERM 적절히 처리
process.on("SIGTERM", () => {
server.close(() => process.exit(0));
setTimeout(() => process.exit(1), 30000);
});
3. 환경변수에 기밀 정보를 직접 작성하는 경우
# ❌ 절대 NG: 시크릿을 평문으로 작성
gcloud run services update myapp-api --set-env-vars DATABASE_PASSWORD=mypassword123
# ✅ 정답: Secret Manager 경유로 안전하게 전달
gcloud run services update myapp-api --set-secrets="DATABASE_PASSWORD=DATABASE_PASSWORD:latest"
4. 메모리 설정 부족
# 메모리 부족 대책: Node.js 힙 사이즈를 명시
CMD ["node", "--max-old-space-size=384", "dist/index.js"]
5. 요청 외 백그라운드 처리를 하는 경우
# 항상 CPU를 할당하는 모드 (백그라운드 처리가 필요한 경우)
gcloud run services update myapp-api --no-cpu-throttling --region asia-northeast1
정리
| 태스크 | Claude Code의 기여 |
|---|---|
| Dockerfile 생성 | 멀티스테이지 빌드·비루트 설정 자동화 |
| 최초 배포 | 요건에서 gcloud 커맨드 일식 생성 |
| 스케일링 설정 | min/max 인스턴스·CPU 임계값 최적화 |
| Secret Manager 연동 | 시크릿 등록·권한 부여·마운트 설정 생성 |
| CI/CD 파이프라인 | 테스트 포함 cloudbuild.yaml 생성 |
| 커스텀 도메인 | Terraform 로드 밸런서 구성 자동 생성 |
관련 글
- Claude Code × AWS ECS/Fargate 완전 가이드
- Claude Code × AWS CloudFormation/CDK 완전 가이드
- Claude Code 보안 베스트 프랙티스
참고 자료
무료 PDF: 5분 완성 Claude Code 치트시트
이메일 주소만 등록하시면 A4 한 장짜리 치트시트 PDF를 즉시 보내드립니다.
개인정보는 엄격하게 관리하며 스팸은 보내지 않습니다.
Claude Code 워크플로우를 한 단계 업그레이드하세요
지금 바로 Claude Code에 복사해 쓸 수 있는 검증된 프롬프트 템플릿 50선.
이 글을 작성한 사람
Masa
Claude Code를 적극 활용하는 엔지니어. 10개 언어, 2,000페이지 이상의 테크 미디어 claudecode-lab.com을 운영 중.
관련 글
Codex Automations란? 잠자는 동안 AI가 콘텐츠 운영을 처리하게 하는 방법
Codex Automations로 트래픽 분석, 주제 선정, 글 작성, CTA 개선, 배포까지 자동화하는 실전 가이드.
Claude Code × GCP Cloud Functions 완전 가이드 | 서버리스 함수 초고속 개발
Claude Code로 GCP Cloud Functions를 효율화. HTTP/Pub/Sub/Firestore 트리거 구현부터 로컬 테스트·배포 자동화까지, Masa의 실무 경험을 토대로 실제 코드로 해설.
Claude Code로 Firestore 설계를 실패하지 않는 방법: 컬렉션보다 쿼리부터
Claude Code로 Firestore 스키마를 쿼리, 인덱스, 비용, 보안 규칙 관점에서 설계하는 실전 워크플로우입니다.