핵심 요약
- GCS는 객체 스토리지로, 버킷 단위로 리전 / 멀티리전 / 듀얼리전 / 스토리지 클래스 / 라이프사이클을 결정하면 비용과 가용성이 함께 결정된다.
- 스토리지 클래스는 Standard / Nearline / Coldline / Archive 4종이며, 접근 빈도가 아닌 검색(retrieval) 비용까지 고려해 선택해야 한다.
- 한국 사용자 대상 서비스라면 asia-northeast3 메인이 합리적. Always Free 영구 무료(US 3개 리전)는 학습 sandbox용으로만 별도 분리한다.
- Signed URL과 Object Versioning은 보안/복구의 핵심 기능. Uniform Bucket-level Access를 기본으로 ACL은 사용하지 않는다.
- 본 글은 콘솔 클릭 가이드가 아닌 gsutil / gcloud storage / Terraform 기반 운영 패턴을 다룬다.
사전 지식: 시리즈 #1, #2, REST API 기본, HTTP 헤더 개념
작성 시점: 2026년 5월 기준 (gcloud storage 명령 GA, gsutil deprecation 진행 중)
1. 객체 스토리지 모델 복습
Cloud Storage(GCS)는 AWS S3, Azure Blob Storage와 같은 객체 스토리지(Object Storage) 다. 파일 시스템과의 차이를 짧게 짚고 가자.
| 계층 구조 | 디렉토리 트리 | Flat namespace (prefix로 모방) |
| 부분 수정 | 가능 (랜덤 액세스) | 불가 (객체 단위 교체) |
| 메타데이터 | inode 기반, 제한적 | Custom metadata 자유롭게 부여 가능 |
| 접근 방식 | POSIX | HTTP REST API |
| 일관성 | 동기식 | Strong consistency (S3와 동일하게 2021년부터) |
GCS의 gs://my-bucket/photos/2026/img.jpg 같은 경로는 실제로는 단일 객체 이름이다. 콘솔이나 gsutil이 슬래시를 디렉토리처럼 시각화할 뿐, 내부적으로 photos/ 디렉토리는 존재하지 않는다. 이 점은 prefix listing 성능 특성에 직접적인 영향을 준다.
2. 버킷 구성의 4가지 결정 축
버킷 생성 시 결정하는 4가지가 비용과 가용성을 좌우한다:
- Location Type: Region / Dual-region / Multi-region
- Storage Class: Standard / Nearline / Coldline / Archive
- Access Control: Uniform / Fine-grained
- Public Access Prevention: enforced / inherited
이 중 (1), (2), (3)은 생성 후 변경이 까다롭거나 비용이 발생하므로 처음부터 신중하게 결정한다.
2.1 Location Type 비교
| Region | asia-northeast3 | 99.9% | $0.023/GB/월 | 단일 리전 서비스 |
| Dual-region | asia1 | 99.95% | $0.046/GB/월 | 재해 복구 필요한 운영 |
| Multi-region | asia, us | 99.95% | $0.026/GB/월 | 글로벌 CDN 원본 |
요금은 2026년 5월 기준, Standard 클래스 기준 대략치다. 정확한 수치는 GCS Pricing에서 확인한다.
한국 사용자 대상 서비스의 기본 선택: asia-northeast3 단일 리전. 비용 효율과 레이턴시가 모두 우수하다.
재해 복구가 필요한 경우: asia1 Dual-region (도쿄 + 오사카) 또는 asia-northeast3 + asia-northeast1 양쪽에 별도 버킷 + Storage Transfer Service로 복제.
2.2 Storage Class 선택 기준
스토리지 클래스 비교 (asia-northeast3 기준, 2026년 5월):
| Standard | $0.023 | $0 | 없음 | 자주 접근, 웹 콘텐츠 |
| Nearline | $0.016 | $0.01 | 30일 | 월 1회 미만 접근 |
| Coldline | $0.006 | $0.02 | 90일 | 분기 1회 미만 접근 |
| Archive | $0.0025 | $0.05 | 365일 | 연 1회 미만, 규제 보관 |
핵심 함정: 저장 비용만 보고 Archive를 선택하면 검색 시 비용 폭탄이 난다. 1TB를 한 번 전체 다운로드하면 검색 비용만 $50, 여기에 외부 egress 추가($0.12/GB × 1024 = $122)다.
선택 결정 트리:
├─ 매일 또는 매주 → Standard
├─ 월 1회 미만 → Nearline
├─ 분기 1회 미만 → Coldline
└─ 연 1회 미만 또는 규제 보관 → Archive
단, 객체 수명이 최소 보관 기간보다 짧으면
한 단계 위 클래스 선택 (조기 삭제 페널티 회피)
조기 삭제 페널티 예시: Nearline에 저장한 객체를 10일 후 삭제하면, 남은 20일치 저장 비용이 청구된다. 객체 수명이 가변적이라면 라이프사이클 정책으로 자동 전환하는 게 안전하다.
2.3 Uniform Bucket-level Access (UBLA)
신규 버킷은 무조건 Uniform으로 생성한다. Fine-grained(객체별 ACL)는 다음 문제로 사실상 deprecated 상태다:
- 객체마다 다른 권한 → 권한 감사 불가능
- IAM 정책과 ACL이 동시 적용되면서 권한 충돌
- 대량 객체에 일괄 권한 적용 시 성능 저하
Uniform 모드에서는 버킷 단위 IAM만 사용하며, 객체별 권한 분리가 필요하면 버킷을 분리하거나 Signed URL(7절)로 임시 권한을 부여한다.
3. 버킷 생성 — gcloud storage 기준
3.1 gcloud storage vs gsutil
기존 gsutil은 deprecation 진행 중이며, 신규 명령은 gcloud storage 사용을 권장한다. 두 명령의 동일 작업 매핑:
| 버킷 생성 | gsutil mb | gcloud storage buckets create |
| 객체 업로드 | gsutil cp | gcloud storage cp |
| 객체 동기화 | gsutil rsync | gcloud storage rsync |
| 메타데이터 조회 | gsutil stat | gcloud storage objects describe |
본 글은 모두 gcloud storage 기준으로 작성한다.
3.2 운영 권장 설정으로 버킷 생성
서울 리전, Standard 클래스, UBLA, Public Access Prevention 적용 버킷 생성:
--location=asia-northeast3 \
--default-storage-class=STANDARD \
--uniform-bucket-level-access \
--public-access-prevention \
--enable-autoclass=false
각 옵션의 의미:
- --location: 리전 또는 멀티리전 지정
- --default-storage-class: 신규 객체의 기본 클래스
- --uniform-bucket-level-access: UBLA 강제 (객체별 ACL 차단)
- --public-access-prevention: 실수로 allUsers 부여해도 차단
- --enable-autoclass: 자동 클래스 전환 활성화 옵션 (워크로드에 따라 선택)
3.3 Terraform으로 동일 구성
운영 환경은 IaC로 관리한다. Terraform 코드 예시:
name = "my-app-uploads-prod"
location = "ASIA-NORTHEAST3"
storage_class = "STANDARD"
uniform_bucket_level_access = true
public_access_prevention = "enforced"
versioning {
enabled = true
}
lifecycle_rule {
condition {
age = 30
}
action {
type = "SetStorageClass"
storage_class = "NEARLINE"
}
}
lifecycle_rule {
condition {
age = 365
}
action {
type = "Delete"
}
}
labels = {
env = "prod"
team = "platform"
}
}
4. 라이프사이클 정책
라이프사이클 정책은 객체의 나이, 버전, 클래스 등 조건에 따라 자동으로 클래스 전환 또는 삭제를 실행한다. 비용 최적화의 핵심 도구다.
4.1 권장 패턴 - 핫/콜드 분리
웹 서비스의 업로드 파일 같은 워크로드는 초기 7일 핫 + 이후 콜드 패턴이 일반적이다. 라이프사이클 JSON 예시:
"lifecycle": {
"rule": [
{
"action": {
"type": "SetStorageClass",
"storageClass": "NEARLINE"
},
"condition": {
"age": 30,
"matchesStorageClass": ["STANDARD"]
}
},
{
"action": {
"type": "SetStorageClass",
"storageClass": "COLDLINE"
},
"condition": {
"age": 90,
"matchesStorageClass": ["NEARLINE"]
}
},
{
"action": {
"type": "Delete"
},
"condition": {
"age": 730
}
}
]
}
}
이 정책을 적용하면:
- 0~30일: Standard
- 30~90일: Nearline (저장비 30% 절감)
- 90~730일: Coldline (저장비 73% 절감)
- 730일 이후: 자동 삭제
4.2 적용 명령
라이프사이클 JSON 파일을 작성한 뒤 적용:
--lifecycle-file=lifecycle.json
4.3 Autoclass 옵션
수동 라이프사이클 대신 GCS가 객체 접근 패턴을 학습해서 자동 전환하는 Autoclass도 있다.
Autoclass의 트레이드오프:
- 장점: 라이프사이클 정책 작성 불필요, 접근 패턴 변화에 자동 적응
- 단점: 객체당 월 $0.0025 관리 비용 추가, 1MiB 미만 객체에 비효율적
- 권장: 객체 수명/접근 패턴이 예측 불가능한 경우 사용. 정형 워크로드는 명시적 라이프사이클이 더 경제적
5. Object Versioning
5.1 동작 원리
Versioning이 활성화된 버킷에서는 객체 덮어쓰기/삭제 시 이전 버전이 noncurrent로 보존된다. 사실상 휴지통 + 시점 복구(point-in-time recovery)다.
활성화 명령:
객체 버전 조회:
각 버전은 generation 번호로 구분되며, 특정 버전 복구는 다음과 같이 한다:
5.2 비용 관리
Versioning 없이 자주 덮어쓰는 워크로드는 의도치 않게 저장 비용이 폭증할 수 있다. noncurrent 버전 자동 정리 라이프사이클이 필수다:
"lifecycle": {
"rule": [
{
"action": {
"type": "Delete"
},
"condition": {
"numNewerVersions": 3,
"isLive": false
}
},
{
"action": {
"type": "Delete"
},
"condition": {
"daysSinceNoncurrentTime": 30,
"isLive": false
}
}
]
}
}
이 정책의 의미: 최신 3개 버전 외에는 30일 후 자동 삭제. isLive: false는 현재 버전이 아닌 noncurrent 버전만 대상으로 한다는 표시다.
6. Signed URL — 임시 권한 부여
6.1 활용 시나리오
다음과 같은 케이스에서 Signed URL이 필수다:
- 모바일 앱에서 직접 GCS에 업로드 (백엔드 경유 시 트래픽 2배)
- 일회성 다운로드 링크 (만료 시간 설정)
- 비공개 객체를 임시로 외부 공유
Signed URL의 원리: 백엔드가 SA 키 또는 IAM 자격증명으로 URL에 서명을 부여하고, 클라이언트는 그 URL로 직접 GCS에 접근한다. 권한은 서명된 URL 자체에 내장되어 있다.
6.2 백엔드 구현 예시 (Python)
업로드용 Signed URL 발급:
from datetime import timedelta
def generate_upload_signed_url(bucket_name: str, blob_name: str) -> str:
client = storage.Client()
bucket = client.bucket(bucket_name)
blob = bucket.blob(blob_name)
url = blob.generate_signed_url(
version="v4",
expiration=timedelta(minutes=15),
method="PUT",
content_type="application/octet-stream",
)
return url
다운로드용 Signed URL은 method="GET"으로 동일하게 발급한다.
6.3 인증 자격증명
위 코드가 동작하려면 백엔드가 서명 권한을 가져야 한다. 운영 환경 권장 패턴:
- Cloud Run / GCE에 SA 첨부 (ADC 자동 사용)
- 해당 SA에 roles/iam.serviceAccountTokenCreator 부여
- IAM Service Account Credentials API를 통해 서명 (SA Key 파일 불필요)
SA Key를 디스크에 두지 않고 서명하려면 다음 추가 설정:
url = blob.generate_signed_url(
version="v4",
expiration=timedelta(minutes=15),
method="PUT",
service_account_email="signer-sa@my-project.iahttp://m.gserviceaccount.com",
access_token=auth_request_token,
)
#2편의 Workload Identity Federation과 결합하면, GitHub Actions에서도 키 없이 Signed URL을 발급할 수 있다.
6.4 보안 체크리스트
- 만료 시간은 짧게 (업로드 15분, 다운로드 1시간 권장)
- content_type / content_md5 명시로 URL 변조 방지
- 발급 로그를 Cloud Logging에 기록 (감사 트레일)
- 클라이언트 IP 제한 필요 시 VPC Service Controls 또는 별도 게이트웨이 검토
7. 한국 사용자 대상 서비스의 리전 결정
7.1 결정 흐름
운영 환경 리전 선택 결정 트리:
한국 사용자 대상 서비스인가?
├─ Yes
│ ├─ 재해 복구 RTO < 1h 필요?
│ │ ├─ Yes → Dual-region (asia1)
│ │ └─ No → asia-northeast3 단일 리전
│ └─ 비용 민감 + 레이턴시 일부 양보 가능?
│ └─ asia-northeast1 (도쿄) 검토
├─ No (글로벌 / 미국 중심)
│ └─ us-central1
└─ 학습 / sandbox / 영구 무료 필요
└─ us-west1 (Always Free 가능)
7.2 리전별 가격 차이
asia-northeast3 vs us-central1 비교 (Standard, 2026년 5월):
| 저장 ($/GB/월) | $0.023 | $0.020 | +15% |
| Class A 작업 (write) | $0.05/10K | $0.05/10K | 동일 |
| Class B 작업 (read) | $0.004/10K | $0.004/10K | 동일 |
| 외부 egress (아시아) | $0.12/GB | $0.12/GB | 동일 |
대량 저장(수십 TB) 서비스가 아니면 리전 가격 차이의 절대 금액은 작다. 레이턴시 차이(서울 발 한국 사용자 ~10ms vs 미국 발 ~150ms)가 훨씬 큰 의사결정 요인이다.
7.3 Always Free 한도 (영구 무료)
paid 계정 전환 후에도 매월 자동 적용:
- Cloud Storage 5GB Regional (us-west1, us-central1, us-east1 중 한 곳)
- Class A 5,000회/월
- Class B 50,000회/월
- 네트워크 egress 100GB/월 (북미 발신)
운영 환경과 분리된 학습/sandbox 프로젝트를 us-west1에 별도로 두면 영구 무료 한도 안에서 실험 가능하다. 운영 버킷을 굳이 미국 리전으로 옮기는 비용 최적화는 권장하지 않는다.
8. 운영 모니터링 패턴
8.1 비용 분리 - 라벨
대규모 운영에서 가장 흔한 문제: "어느 서비스가 GCS 비용을 얼마나 쓰는지 모름". 버킷에 라벨을 부여하고 Billing Export로 분석한다.
라벨 부여:
--update-labels=team=platform,env=prod,service=upload
이후 BigQuery로 Billing Export한 데이터에서 라벨 기준 집계가 가능하다.
8.2 객체 수 / 용량 추적
버킷 객체 통계 조회:
대용량 버킷은 위 명령이 느리므로, Cloud Monitoring의 storage.googleapis.com/storage/total_bytes 메트릭을 활용하는 것이 표준이다.
8.3 Access Log 활성화
Bucket Access Logs는 모든 객체 접근을 별도 버킷에 기록한다. 보안 사고 분석과 비정상 접근 패턴 탐지에 필수다.
활성화:
--log-bucket=gs://my-audit-logs \
--log-object-prefix=my-app-uploads-prod
로그는 다음 날 새벽에 1시간 단위 batch로 생성된다. 실시간 분석이 필요하면 Cloud Audit Logs (Data Access) 를 활성화해야 한다(별도 과금).
9. 흔한 함정과 디버깅
함정 1: Multi-region 버킷의 listing 일관성
Multi-region 버킷도 strong consistency를 보장하지만, listing 작업은 eventual consistency 구간이 있을 수 있다. 업로드 직후 listing에 안 나타나면 단순 재시도로 해결되는 경우가 많다.
함정 2: gsutil cp -r vs gcloud storage cp --recursive
대량 파일 복사 시 gcloud storage cp --recursive가 gsutil cp -r 대비 평균 2~3배 빠르다. 내부 병렬 처리 구현이 다르다. 대량 작업은 무조건 gcloud storage 사용.
함정 3: Signed URL 시계 불일치
서명한 백엔드의 시계가 GCS 서버와 5분 이상 차이 나면 401 에러가 발생한다. 컨테이너 환경에서 NTP 동기화 누락이 원인인 경우가 많다. 디버깅 시 date -u 출력과 GCS API 응답의 Date 헤더를 비교한다.
함정 4: Composite object의 CRC32C 불일치
gcloud storage compose로 합친 객체는 CRC32C가 부모 객체와 다르게 계산된다. 무결성 검증이 필요한 워크로드는 별도로 MD5/SHA-256을 metadata에 저장한다.
함정 5: Public Access Prevention의 enforced vs inherited
enforced는 버킷 레벨에서 강제이며, 누구도 allUsers 권한을 부여할 수 없다. inherited는 Organization Policy를 따른다. 운영 버킷은 무조건 enforced 로 설정한다.
10. 마무리 및 다음 글
핵심 정리
- 버킷 생성 시 결정하는 4가지(Location / Class / Access Control / PAP)가 비용과 보안의 90%를 좌우한다.
- 한국 사용자 대상 서비스는 asia-northeast3 메인. 영구 무료 한도는 별도 sandbox 프로젝트에서 us-west1로 분리.
- Storage Class 선택은 저장 비용이 아닌 검색 비용까지 고려한다. 라이프사이클 또는 Autoclass로 자동화.
- Versioning + noncurrent 정리 라이프사이클은 세트로 구성. 버전 무제한 보관은 비용 폭탄의 흔한 원인.
- Signed URL은 SA Key 없이 발급하는 것이 표준 (IAM Credentials API + 워크로드 첨부 SA).
- 신규 작업은 gcloud storage(legacy gsutil 대신), 운영 환경은 Terraform으로 IaC 관리.
다음 글(#4 예정): Cloud Run 배포 실전 — 컨테이너 빌드 전략, 콜드 스타트 최적화, min/max instances 튜닝, Cloud Run + GCS + Cloud SQL 통합 패턴.
참고 자료
- Cloud Storage 공식 문서
- Storage Pricing 상세
- gcloud storage CLI 가이드
- Storage Class별 비교
- Lifecycle Management 공식 가이드
- Signed URL 가이드
- Terraform google_storage_bucket 리소스
카테고리: Cloud / GCP
태그: gcp google-cloud cloud-storage gcs object-storage terraform signed-url lifecycle cloud-architecture devops
'개발 프로젝트 > GCP 실습 일지' 카테고리의 다른 글
| GCP 시작 가이드 #5 — 비용 최적화 패턴 (0) | 2026.06.05 |
|---|---|
| GCP 시작 가이드 #4 — Cloud Run 배포 실전 (0) | 2026.06.03 |
| GCP 시작 가이드 #2 — IAM과 Service Account 깊이 있게 (0) | 2026.05.27 |
| GCP 시작 가이드 #1 — 계정 구조, 빌링, Free Tier의 함정 (0) | 2026.05.22 |