13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] S3 호환 API

  • [Cloud] Cloudflare R2 vs AWS S3/GCS: 객체 스토리지 선택 기준 비교 분석

    [Cloud] Cloudflare R2 vs AWS S3/GCS: 객체 스토리지 선택 기준 비교 분석

    Cloudflare R2 vs AWS S3/GCS: 객체 스토리지 선택 기준 비교

    Cloudflare R2를 검토할 때 많은 분이 먼저 보는 건 저장 단가인데, 실제 운영에서는 그보다 데이터가 어디로 흘러가느냐가 더 크게 작용하더라고요. 같은 파일 하나를 올려도 사용자 다운로드가 많은지, 같은 클라우드 내부 서비스가 읽는지, 브라우저가 직접 접근하는지에 따라 비용 구조와 운영 난이도가 확 달라집니다. 저도 백업 산출물, 정적 자산, 로그 아카이브를 R2, S3, GCS에 각각 붙여보면서 결국 같은 결론으로 돌아왔습니다. 객체 스토리지는 GB당 저장 단가보다 네트워크 경로와 권한 모델이 더 비싸게 굴 때가 많다는 점입니다.

    이번 글은 Cloudflare R2, AWS S3, Google Cloud Storage(GCS)를 제품 소개가 아니라 선택 기준으로 비교합니다. 어느 서비스가 더 좋다고 단정하기보다, 어떤 워크로드에 붙이면 덜 후회하는지, 반대로 어떤 경우엔 일부러 피하는 게 맞는지까지 적어보겠습니다. 가격은 수시로 바뀌니 숫자 나열은 줄이고, 대신 공식 문서로 확인 가능한 동작과 실무에서 바로 부딪히는 파라미터, CLI 문법, 실패 모드를 중심으로 봤습니다.

    특히 이미 S3를 쓰고 있는데 egress 비용이 거슬리거나, GCP 분석 파이프라인과 스토리지를 더 단순하게 묶고 싶거나, S3 호환이라는 말만 믿고 R2로 옮기려는 분이라면 이 글이 판단 시간을 꽤 줄여줄 겁니다. 비슷한 인프라 비교 글이 더 필요하다면 블로그 안의 스토리지·CDN 관련 글도 함께 보시면 흐름이 더 잘 잡힙니다.

    Cloudflare R2, AWS S3, GCS의 연결 구조와 비용 관점을 한눈에 보는 개요 이미지입니다.

    Cloudflare R2 비교에서 먼저 봐야 하는 것

    비교 순서를 잘못 잡으면 스토리지 가격표만 오래 보게 됩니다. 저는 실제로 아래 순서로 먼저 봅니다.

    • 데이터가 누구에게 나가느냐: 사용자 인터넷 다운로드인지, 같은 클라우드 내부 서비스 호출인지
    • 누가 쓰느냐: 백엔드 서버, 배치 작업, 브라우저, 데이터 파이프라인 중 어디가 주체인지
    • 권한을 어디서 통제하느냐: AWS IAM, GCP IAM, 별도 키 관리, 임시 서명 URL 중 무엇이 주력인지
    • 현재 도구를 얼마나 재사용하느냐: AWS CLI/SDK를 그대로 쓸지, gcloud 중심으로 갈지, 운영 문서를 새로 써야 하는지

    저장 단가, 요청 비용, 전송 비용이라는 세 축은 여전히 중요합니다. 다만 실무에서는 이 세 축이 따로 움직이지 않더라고요. 예를 들어 다운로드 서비스는 전송 정책이 핵심이고, 배치·분석 워크로드는 같은 클라우드 안에서 붙는 서비스들과의 연동 비용이 더 중요합니다. 반대로 브라우저 직접 업로드는 CORS와 presigned URL 설계가 더 중요하고요. 결국 객체 스토리지는 저장 상품이 아니라 애플리케이션 경로의 일부로 봐야 비교가 맞습니다.

    Cloudflare R2 vs AWS S3/GCS: 한 번에 보는 선택 기준

    항목 Cloudflare R2 AWS S3 GCS
    핵심 포인트 S3 호환 API와 인터넷 egress 무료 정책이 강점 가장 넓은 생태계, IAM·이벤트·주변 서비스 연동이 매우 촘촘함 GCP 애플리케이션·분석 워크로드와의 결합이 자연스럽고 운영 경험이 일관적
    언제 유리한가 외부 다운로드가 많고 S3 도구 체인을 버리고 싶지 않을 때 이미 AWS 중심 아키텍처이고 저장소를 다른 서비스와 깊게 묶어야 할 때 Cloud Run, GKE, BigQuery, 데이터 적재 파이프라인을 GCP 안에서 굴릴 때
    언제 불리한가 S3와 완전 동일한 부가 기능, 세부 API 동작, 특정 AWS 연동을 기대할 때 인터넷 방향 전송량이 커서 egress가 월 비용을 흔들 때 AWS 도구 체인에 이미 깊게 묶였고 팀이 gcloud·IAM 모델에 익숙하지 않을 때
    운영 난이도 포인트 endpoint 고정, 호환성 문서 확인, 서명·버킷 동작 차이 점검이 핵심 리전, 버킷 정책, 소유권 제어, 서비스별 권한 위임 설계가 핵심 uniform bucket-level access, 서비스 계정 권한, CORS·공개 접근 정책 정리가 핵심
    비용 판단 포인트 인터넷 방향 다운로드가 많을수록 매력적 AWS 내부 서비스와 같은 리전에 묶일수록 자연스럽고 예측 가능 GCP 내부 데이터 처리와 함께 갈 때 전체 운영비 계산이 쉬움
    먼저 권하는 상황 정적 파일 배포, 다운로드 아카이브, 사용자 파일 제공 서비스 AWS 기반 SaaS, 이벤트 파이프라인, 권한 통합이 중요한 시스템 로그 적재, 분석용 원본 보관, GCP 중심 애플리케이션 백엔드

    공식 문서 기준으로 보면 R2는 인터넷 방향 egress에 과금하지 않고, S3와 GCS는 저장, 요청, 전송을 분리해서 봐야 합니다. R2는 현재 S3 호환 API를 제공하지만 구현 범위가 AWS S3와 완전히 같지는 않습니다. 그래서 핵심은 단순히 “R2가 싸다”가 아니라, 트래픽이 인터넷으로 빠지는 구조면 R2가 비용 변동성을 줄이기 쉽다는 점입니다. 반대로 애플리케이션, 배치, 분석, 권한 체계가 이미 AWS/GCP에 깊게 묶여 있으면 저장소만 떼어내는 순간 운영 복잡성이 생깁니다.

    Cloudflare R2를 포함해 제가 실제로 쓰는 결정 프레임

    1. 다운로드 트래픽이 핵심이면 Cloudflare R2

    R2의 가장 눈에 띄는 장점은 저장 기능 자체보다 인터넷 방향 전송 비용을 계산하기 쉬운 구조입니다. 사용자에게 원본 파일, 이미지, 백업 산출물, 미디어 자산을 자주 내려줘야 한다면 이 장점이 꽤 직접적으로 보입니다. 특히 기존 스크립트가 aws s3 cp, aws s3 sync, SDK 기반 업로드 로직으로 이미 짜여 있다면 endpoint만 바꿔서 마이그레이션 테스트를 시작할 수 있다는 점도 큽니다. 이거 진짜 편하더라고요.

    다만 여기서 많이 착각하는 부분이 있습니다. S3-compatible는 S3와 동일가 아닙니다. 호환 API라는 건 마이그레이션 진입장벽을 낮춰준다는 뜻이지, 모든 기능과 부가 동작이 완전히 같다는 뜻은 아니거든요. 그래서 저는 R2를 검토할 때 기능 비교보다 먼저 S3 API compatibility 문서를 열어놓고 봅니다. 이 단계 없이 들어가면 나중에 ACL, 이벤트, 특정 헤더 처리, SDK 기본값에서 시간을 꽤 씁니다.

    2. AWS 서비스와 촘촘히 묶여 있으면 AWS S3

    S3는 여전히 기준점입니다. 이유는 단순합니다. 저장소 혼자 강한 게 아니라 AWS 내부 연결성이 압도적으로 넓기 때문입니다. EC2, Lambda, CloudFront, IAM, 이벤트 기반 처리, 백업 정책, 수명주기 관리까지 이미 AWS 안에서 굴러가고 있다면 S3는 기술적으로도, 조직적으로도 마찰이 적습니다.

    실무에서는 저장 단가 몇 퍼센트보다 운영 문서와 권한 체계를 다시 쓰는 비용이 더 큽니다. 누가 어느 버킷을 읽고 쓰는지, 어떤 배치가 어떤 role을 assume 하는지, 특정 배포 파이프라인이 어떤 리전에 올리는지 다 이미 굴러가고 있다면, 스토리지만 따로 빼서 최적화하는 작업이 생각보다 깔끔하지 않습니다. AWS 중심 서비스라면 S3를 기본값으로 두고, 정말로 인터넷 방향 전송비가 반복적으로 부담이 되는 워크로드만 별도로 떼어내는 접근이 더 현실적이었습니다.

    3. GCP 앱과 데이터 파이프라인이 중심이면 GCS

    GCS는 기능 설명보다 운영 흐름의 일관성으로 평가하는 게 맞습니다. Cloud Run, GKE, 데이터 적재 파이프라인, 서비스 계정, GCP IAM 모델에 이미 익숙한 팀이라면 GCS가 훨씬 덜 거슬립니다. 저장소 하나 때문에 별도의 계정 체계나 SDK 관용구를 늘리지 않아도 되니까요.

    특히 저는 로그 보관, 분석용 원본 적재, 주기적 배치 산출물 보관 같은 용도는 GCP 안에서 끝내는 편이 실수가 적었습니다. 브라우저 접근, 서비스 계정, 권한 상속, 배치 계정 권한 분리가 한 체계 안에 있으니 운영 문서가 짧아집니다. 사소해 보여도 팀이 커질수록 체감 차이가 꽤 큽니다.

    실전 구현: 같은 파일을 R2, S3, GCS에 올려보며 보는 차이

    말로만 비교하면 결국 감이 흐려집니다. 아래는 backup.tar.gz 파일 하나를 각각 올리는 최소 흐름입니다. 저는 이런 테스트를 할 때 세 가지만 같이 봅니다. 인증이 어디서 결정되는지, 리전 또는 endpoint를 누가 결정하는지, 업로드 직후 메타데이터를 어떻게 검증하는지입니다. 여기까지 확인해야 나중에 자동화 스크립트로 확장할 때 덜 꼬입니다.

    1. 버킷을 생성합니다.
    2. 샘플 파일을 업로드합니다.
    3. head-object 또는 상세 조회로 메타데이터를 확인합니다.
    4. 브라우저 접근이 있으면 CORS와 공개·비공개 경계를 분리합니다.

    Cloudflare R2: AWS CLI를 재활용하되 endpoint를 고정해야 합니다

    R2는 공식 문서 기준으로 https://<ACCOUNT_ID>.r2.cloudflarestorage.com 엔드포인트를 사용하고, S3 API에서 bucket region은 auto를 씁니다. 이 조합이 중요합니다. 인증 정보만 바꾸고 endpoint를 빼먹으면 AWS CLI는 자연스럽게 AWS S3 쪽으로 요청을 보냅니다. 여기서 생기는 실패는 얼핏 보면 권한 문제처럼 보여서 더 헷갈립니다. 원인은 단순한데 증상은 복잡하게 보여요. 초반에 한 번쯤은 꼭 삽질하게 되는 포인트입니다.

    aws configure --profile r2
    # AWS Access Key ID: <R2_ACCESS_KEY_ID>
    # AWS Secret Access Key: <R2_SECRET_ACCESS_KEY>
    # Default region name: auto
    # Default output format: json
    
    export R2_ENDPOINT="https://<ACCOUNT_ID>.r2.cloudflarestorage.com"
    
    aws s3api create-bucket \
      --bucket my-r2-bucket \
      --endpoint-url "$R2_ENDPOINT" \
      --profile r2
    
    aws s3 cp ./backup.tar.gz s3://my-r2-bucket/backup.tar.gz \
      --endpoint-url "$R2_ENDPOINT" \
      --profile r2
    
    aws s3api head-object \
      --bucket my-r2-bucket \
      --key backup.tar.gz \
      --endpoint-url "$R2_ENDPOINT" \
      --profile r2

    실무 팁은 간단합니다. R2용 profile과 endpoint 환경변수를 아예 분리해두세요. 매 명령마다 직접 치는 습관은 결국 한 번 빠뜨리게 됩니다. 그리고 테스트 초반에는 aws s3 ls보다 aws s3api head-object를 먼저 보시는 걸 권합니다. 존재 여부뿐 아니라 객체 키, 크기, 수정 시각, ETag를 바로 확인할 수 있어서 자동화 검증에 더 잘 맞습니다.

    Cloudflare R2 버킷 생성과 업로드 설정 흐름을 보여주는 이미지

    R2를 AWS CLI로 다루는 실제 흐름을 보여주는 이미지입니다. endpoint 설정 위치가 핵심입니다.

    AWS S3: 리전과 버킷 소유권 모델을 같이 정리하는 게 낫습니다

    S3는 익숙해서 오히려 대충 넘어가기 쉽습니다. 그런데 버킷 생성 단계에서 리전과 소유권 제어를 같이 잡아두면 뒤가 편합니다. 특히 us-east-1 이외 리전에서는 LocationConstraint를 명시해야 하고, ACL 기반 접근을 굳이 유지할 이유가 없다면 BucketOwnerEnforced로 가는 편이 팀 운영상 깔끔합니다.

    aws s3api create-bucket \
      --bucket my-s3-bucket-example \
      --region ap-northeast-2 \
      --create-bucket-configuration LocationConstraint=ap-northeast-2 \
      --object-ownership BucketOwnerEnforced
    
    aws s3 cp ./backup.tar.gz s3://my-s3-bucket-example/backup.tar.gz
    
    aws s3api head-object \
      --bucket my-s3-bucket-example \
      --key backup.tar.gz

    여기서 핵심은 단순 업로드 성공이 아닙니다. head-object 결과를 보고 올바른 버킷·키에 올라갔는지, 메타데이터가 비어 있거나 잘못 덮이지 않았는지, 자동화가 예상한 리전에 들어갔는지를 확인해야 합니다. S3에서 흔한 문제는 인증 실패보다도 잘못된 기본값으로도 성공해 버리는 문제입니다. 예를 들어 잘못된 키 경로, 다른 계정, 다른 버킷 접두사로 업로드해도 명령 자체는 끝나기 때문에 검증 단계를 생략하면 나중에 배포 파이프라인에서 터집니다.

    GCS: 권한 모델을 먼저 단순화하면 뒤가 덜 꼬입니다

    GCS는 최근 gcloud storage 계열 명령이 잘 정리돼 있어서 CLI 사용감이 괜찮은 편입니다. 제가 권하는 시작점은 버킷을 만들 때부터 --uniform-bucket-level-access를 켜는 것입니다. 객체마다 ACL을 따로 만지는 모델은 초기엔 유연해 보여도, 운영자가 늘어나고 서비스 계정이 늘어나면 사고 지점이 늘어나더라고요.

    gcloud storage buckets create gs://my-gcs-bucket-example \
      --location=ASIA-NORTHEAST3 \
      --uniform-bucket-level-access
    
    gcloud storage cp ./backup.tar.gz gs://my-gcs-bucket-example/backup.tar.gz
    
    gcloud storage ls -L gs://my-gcs-bucket-example/backup.tar.gz

    이 흐름에서는 ls보다 ls -L 쪽을 선호합니다. 단순 존재 여부만 보지 말고 저장 클래스, 메타데이터, 업데이트 시각까지 같이 보는 게 좋거든요. GCS는 특히 브라우저 직접 접근과 서비스 계정 접근이 섞일 때 권한 구조가 복잡해지기 쉬워서, 시작부터 버킷 단위 접근을 기본값으로 잡는 편이 훨씬 관리가 쉽습니다.

    브라우저 접근이 있으면 CORS를 뒤로 미루지 마세요

    이 부분은 세 서비스 모두에서 자주 놓칩니다. 백엔드 업로드만 테스트하면 멀쩡한데, 프론트엔드에서 이미지 fetch나 파일 다운로드를 붙이는 순간 막히는 경우가 많습니다. 특히 GCS는 콘솔이나 JSON API 예시와 gcloud storage buckets update --cors-file가 기대하는 파일 구조가 달라서 한 번씩 틀리더라고요.

    [
      {
        "origin": ["https://app.example.com"],
        "method": ["GET", "HEAD"],
        "responseHeader": ["Content-Type", "ETag"],
        "maxAgeSeconds": 3600
      }
    ]
    gcloud storage buckets update gs://my-gcs-bucket-example \
      --cors-file=./cors.json

    근본 원인은 단순합니다. 문서 예시를 섞어 읽으면 JSON API용 구조와 gcloud CLI 입력 구조를 같은 것으로 착각하기 쉽습니다. 실제로 CLI는 최상위 {"cors": [...]}가 아니라 규칙 배열만 있는 파일을 기대합니다. 브라우저에서만 깨지는 문제는 로그가 빈약해서 더 오래 잡히니, CORS는 마지막에 보는 항목이 아니라 초기에 붙여보는 편이 시간을 아낍니다.

    어디서 삽질이 나는지: 흔한 실패 모드와 근본 원인

    여기부터가 제품 소개 글과 실무 글이 갈리는 지점입니다. 표면 증상보다 원인을 알아야 다음에도 덜 틀립니다.

    • R2에서 endpoint 누락: 증상은 인증 실패, 버킷 없음, 예상 밖 계정 리소스 조회처럼 보입니다. 근본 원인은 CLI가 R2가 아니라 AWS S3 기본 엔드포인트로 서명 요청을 보내기 때문입니다. 해결은 --endpoint-url를 강제하거나 R2 전용 profile·환경변수 래퍼 스크립트를 두는 것입니다.
    • S3에서 리전 생성 옵션 누락: 증상은 버킷 생성 실패 또는 리다이렉트성 오류입니다. 근본 원인은 us-east-1 외 리전에서 LocationConstraint가 필요하기 때문입니다. 해결은 리전 값을 단일 변수로 관리하고 생성 시점에 함께 주는 것입니다.
    • GCS에서 CORS 파일 형식 오류: 증상은 명령은 실행됐는데 브라우저에서 preflight나 응답 헤더가 기대와 다르게 보입니다. 근본 원인은 콘솔·JSON API 구조와 gcloud CLI 입력 구조를 혼동한 것입니다.
    • S3 호환이면 기능도 동일하겠지라는 가정: 증상은 특정 SDK 옵션, 부가 API, 권한 동작에서 예상과 다른 결과가 납니다. 근본 원인은 호환 API와 원본 구현을 동일시한 설계 가정입니다. 해결은 사전에 호환성 문서를 대조하고, 사용하는 API 집합을 실제 호출 기준으로 목록화하는 것입니다.
    • 메타데이터 검증 생략: 증상은 업로드는 성공했는데 캐시, 콘텐츠 타입, 브라우저 다운로드 동작이 뒤늦게 꼬입니다. 근본 원인은 존재 확인만 하고 Content-Type, 캐시 헤더, 키 경로, ETag를 안 본 것입니다.

    재현 가능한 시나리오 하나를 적어보겠습니다. 기존 백업 스크립트가 매일 aws s3 cp ./dist/report.tar.gz s3://archive-bucket/daily/만 실행하던 환경이라고 해보죠. 이걸 R2로 옮기면서 액세스 키만 바꾸고 endpoint를 안 넣으면, 스크립트는 여전히 AWS S3 문법으로 실행됩니다. 여기서 운영자는 흔히 IAM 키 문제부터 의심합니다. 그런데 실제 원인은 권한이 아니라 목적지 자체가 바뀌지 않은 것입니다. 이 차이는 로그를 자세히 보기 전까지 잘 안 보입니다. 그래서 저는 마이그레이션 첫 주엔 업로드 직후 head-object를 붙여 결과를 강제로 검증합니다.

    검증과 결과 해석: 무엇을 보면 배포 가능한 상태인지 알 수 있나

    업로드가 한 번 성공했다고 운영 준비가 끝난 건 아닙니다. 최소한 아래 검증은 해야 합니다.

    aws s3api head-object \
      --bucket my-r2-bucket \
      --key backup.tar.gz \
      --endpoint-url "$R2_ENDPOINT" \
      --profile r2
    
    gcloud storage ls -L gs://my-gcs-bucket-example/backup.tar.gz
    • 객체 존재 확인: 키 경로가 정확한지 봅니다. 특히 자동화에서 날짜 접두사나 디렉터리 흉내 키를 많이 틀립니다.
    • 크기 확인: 로컬 파일과 원격 객체 크기가 다르면 중간 실패, 잘못된 파일 참조, 압축 단계 혼선을 의심해야 합니다.
    • 수정 시각 확인: 배포 직후인데 예전 객체를 보고 있으면 잘못된 경로에 올렸을 가능성이 큽니다.
    • 메타데이터 확인: Content-Type, 캐시 관련 헤더, 커스텀 메타데이터가 의도대로 들어갔는지 봅니다.
    • 브라우저 응답 확인: CORS가 필요한 구조라면 Access-Control-Allow-Origin와 preflight 응답을 실제 브라우저에서 확인합니다.

    제가 보는 해석 기준은 단순합니다. GET이 된다와 서비스에 올릴 수 있다는 다른 이야기입니다. 후자는 권한, 메타데이터, 캐시 정책, CORS, 자동화 재실행 시 동작까지 포함합니다. 다운로드 서비스나 이미지 서빙은 특히 브라우저에서만 드러나는 문제가 많아서, curl 테스트만 통과했다고 안심하면 꼭 한 번 더 일하게 됩니다.

    Cloudflare R2와 GCS 업로드 검증 포인트를 보여주는 대시보드 이미지

    업로드 이후 무엇을 확인해야 하는지, 메타데이터와 권한 검증 포인트를 시각화한 이미지입니다.

    비용은 단가보다 경로가 갈라놓습니다

    비용 비교에서 제일 흔한 실수는 저장 단가만 비교하는 것입니다. 실제로는 아래처럼 워크로드를 나눠 봐야 판단이 빨라집니다.

    워크로드 유형 주요 비용 민감도 우선 검토 피해야 할 실수
    백업 보관 위주 저장 기간, 요청 수, 복구 빈도 S3 또는 GCS 기본 구조, R2는 외부 복구 빈도 높을 때 검토 복구 때만 발생하는 전송·검색 패턴을 무시하고 저장 단가만 보는 것
    정적 자산·다운로드 배포 인터넷 방향 전송량, 캐시 전략 Cloudflare R2 SDK 호환만 보고 브라우저·CORS·캐시 정책 검증을 뒤로 미루는 것
    AWS 내부 서비스 연동 권한 통합, 이벤트 처리, 같은 리전 데이터 이동 AWS S3 end-to-end 운영 비용 대신 저장 단가만 보고 외부 스토리지를 섞는 것
    GCP 분석·앱 파이프라인 서비스 계정 권한, GCP 도구 일관성, 데이터 적재 흐름 GCS 팀이 이미 익숙한 IAM·CLI 체계를 버리고 저장소만 따로 최적화하는 것

    여기서 제가 특히 중요하게 보는 건 비용의 예측 가능성입니다. 월말에 갑자기 튀는 비용은 대부분 저장이 아니라 전송 경로에서 나옵니다. 다운로드 트래픽이 핵심인 서비스라면 R2가 눈에 띄고, 내부 연동이 핵심인 서비스라면 S3나 GCS가 더 자연스럽습니다. 이 차이는 가격표의 절대값보다도 장애 대응과 예산 관리에서 훨씬 크게 체감됩니다.

    반대로 “무조건 R2가 낫다”는 식으로 보면 안 됩니다. 예를 들어 데이터가 대부분 AWS 내부 서비스 사이에서 움직이고, 사용자가 직접 다운로드하는 비율이 낮다면 egress 무료라는 장점이 실제 청구서에서 크게 드러나지 않을 수 있습니다. 이럴 때는 새 키 관리, 새로운 엔드포인트, 마이그레이션 검증 비용이 더 큽니다. 저는 이런 경우 굳이 스토리지를 분리하지 않는 편입니다.

    Cloudflare R2와 AWS S3 GCS의 선택 기준을 정리한 비교 인포그래픽

    비용 구조와 사용 패턴에 따라 어떤 스토리지가 유리한지 요약한 비교 인포그래픽입니다.

    그래서 어떤 경우에 뭘 고르면 되나

    여기서는 애매하게 끝내지 않겠습니다. 선택 기준을 조금 더 분명하게 적어보겠습니다.

    • 외부 다운로드가 많고, 기존 AWS CLI·SDK 도구를 최대한 재사용하고 싶다: Cloudflare R2를 먼저 보시면 됩니다. 다만 S3와 완전 동일하다고 가정하지 말고, 사용하는 API 범위를 실제로 대조해보세요.
    • AWS 중심 아키텍처이고 IAM, 이벤트, 주변 서비스 연동이 중요하다: AWS S3가 가장 무난합니다. 저장소를 따로 분리해 얻는 이익보다 운영 복잡성이 더 커질 가능성이 높습니다.
    • GCP 기반 앱과 데이터 파이프라인을 굴리고 있고 운영 단순성이 중요하다: GCS가 맞습니다. 특히 서비스 계정과 버킷 권한을 한 체계로 가져가려면 더 그렇습니다.
    • 브라우저 직접 업로드·다운로드가 많다: 제품 선택만큼 CORS, presigned URL, 메타데이터 검증 설계가 중요합니다. 이 항목을 소홀히 하면 어느 스토리지를 골라도 비슷하게 고생합니다.

    현업에서 최종 선택할 때 저는 한 줄 기준으로 정리합니다. 트래픽이 인터넷으로 많이 나가면 R2 쪽으로 기울고, 애플리케이션과 권한 체계가 특정 클라우드에 깊게 묶여 있으면 그 클라우드의 기본 스토리지로 남습니다. 이 기준이 제일 실수를 덜 만들었습니다.

    FAQ와 공식 문서 체크 포인트

    • R2는 S3와 완전히 같나요? 아닙니다. S3 호환 API입니다. 세부 구현 상태는 Cloudflare의 S3 API compatibility 문서를 확인하셔야 합니다.
    • R2의 가장 큰 차별점은? 공식 가격 문서 기준으로 인터넷 방향 egress 요금이 없다는 점입니다. 다운로드 중심 워크로드일수록 이 차이가 직접적으로 보입니다.
    • S3는 언제 가장 강한가요? 저장소 자체보다 AWS 생태계와의 결합력이 중요할 때입니다. IAM, 이벤트, 주변 서비스 통합을 같이 봐야 합니다.
    • GCS는 언제 선택이 쉬워지나요? Cloud Run, GKE, 데이터 적재, 서비스 계정 운영이 이미 GCP 중심일 때입니다. 팀이 gcloud와 GCP IAM에 익숙하면 마찰이 적습니다.
    • 가격은 어디서 다시 봐야 하나요? 시점에 따라 바뀔 수 있으니 R2, S3, GCS 공식 페이지를 마지막에 다시 확인하는 게 정확합니다.

    마지막 판단만 남기면 이렇습니다. 다운로드 트래픽이 핵심이면 Cloudflare R2, 클라우드 내부 생태계 결합이 핵심이면 AWS S3 또는 GCS입니다. 세 서비스 모두 좋은 저장소지만, 강점이 드러나는 경로가 다릅니다. 그 경로만 먼저 잡아도 선택이 훨씬 쉬워집니다.

    실제 운영 시나리오별로 어떤 선택이 어울리는지 정리한 마무리 가이드 이미지입니다.