🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

S3 버킷 생성과 관리 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 19. · 7 Views

S3 버킷 생성과 관리 완벽 가이드

AWS S3의 핵심 개념인 버킷과 객체를 이해하고, 실무에서 자주 사용하는 파일 업로드/다운로드, 폴더 구조, 스토리지 클래스 관리까지 완벽하게 마스터하는 실전 가이드입니다.


목차

  1. S3란_무엇인가
  2. 버킷과_객체_개념
  3. 버킷_생성하기
  4. 파일_업로드_다운로드
  5. 폴더_구조_활용
  6. 스토리지_클래스

1. S3란 무엇인가

김개발 씨는 입사 첫 주에 팀장님께 이런 요청을 받았습니다. "사용자가 업로드한 프로필 사진들을 어딘가에 저장해야 하는데, 서버 디스크 용량이 부족해요.

AWS S3를 알아보고 구축해볼래요?" 클라우드 스토리지라는 말은 들어봤지만 정확히 뭔지 몰라서 막막했습니다.

AWS S3(Simple Storage Service)는 한마디로 클라우드 상에 파일을 저장하는 무제한 저장소입니다. 마치 구글 드라이브나 네이버 클라우드처럼 파일을 업로드하고 다운로드할 수 있지만, 프로그래밍 방식으로 제어할 수 있다는 점이 다릅니다.

이것을 제대로 이해하면 서버 용량 걱정 없이 수백만 개의 파일도 안전하게 관리할 수 있습니다.

다음 코드를 살펴봅시다.

import boto3

# AWS S3 클라이언트 생성
s3_client = boto3.client('s3',
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY',
    region_name='ap-northeast-2'
)

# S3 버킷 목록 조회
response = s3_client.list_buckets()

# 현재 계정의 모든 버킷 출력
for bucket in response['Buckets']:
    print(f"버킷 이름: {bucket['Name']}")
    print(f"생성 날짜: {bucket['CreationDate']}")

김개발 씨는 검색을 시작했습니다. AWS 공식 문서를 읽어보니 S3가 뭔지 대충 감이 잡혔습니다.

하지만 왜 이걸 써야 하는지, 어떤 장점이 있는지는 아직 명확하지 않았습니다. 마침 옆자리 선배 개발자 박시니어 씨가 점심시간에 친절하게 설명해주었습니다.

"S3는 AWS에서 제공하는 객체 스토리지 서비스예요. 쉽게 말해서 인터넷에 연결된 거대한 하드디스크라고 생각하면 돼요." S3가 뭔가요? 박시니어 씨의 비유가 이해하기 쉬웠습니다.

S3는 마치 무제한 용량의 외장 하드디스크와 같습니다. 일반 하드디스크처럼 파일을 저장하고 꺼낼 수 있지만, 물리적인 공간이 아니라 클라우드 상에 존재합니다.

언제 어디서든 인터넷만 연결되어 있으면 파일에 접근할 수 있습니다. 더 중요한 점은 프로그래밍 코드로 제어할 수 있다는 것입니다.

웹 브라우저로 파일을 업로드하는 것이 아니라, Python이나 JavaScript 코드로 자동화할 수 있습니다. 왜 S3가 필요한가요? 예전에는 서버에 파일을 직접 저장했습니다.

사용자가 프로필 사진을 업로드하면 웹 서버의 디스크에 저장하는 방식이었습니다. 처음에는 문제가 없어 보였습니다.

하지만 사용자가 늘어나면서 문제가 생기기 시작했습니다. 서버 디스크 용량이 금방 가득 찼습니다.

용량을 늘리려면 서버를 업그레이드해야 했고, 비용이 계속 증가했습니다. 더 큰 문제는 백업과 복구였습니다.

서버에 문제가 생기면 모든 파일이 날아갈 위험이 있었습니다. 직접 백업 시스템을 구축하려면 또 다른 서버와 개발 비용이 필요했습니다.

서버가 여러 대로 늘어나면 더욱 복잡해졌습니다. A 서버에 업로드된 파일을 B 서버에서 조회할 수 없는 문제가 발생했습니다.

파일 동기화 시스템을 따로 만들어야 했습니다. S3의 등장 바로 이런 문제를 해결하기 위해 AWS S3가 등장했습니다.

S3를 사용하면 무제한 용량을 사용할 수 있습니다. 파일이 아무리 많아져도 용량 걱정을 할 필요가 없습니다.

사용한 만큼만 비용을 지불하면 됩니다. 또한 자동 백업과 복구 기능이 내장되어 있습니다.

AWS가 알아서 여러 곳에 파일을 복제해두기 때문에 데이터 손실 걱정이 없습니다. 99.999999999%(일레븐 나인)의 내구성을 보장합니다.

무엇보다 어디서든 접근 가능하다는 큰 이점이 있습니다. 서버가 10대든 100대든 상관없이 모든 서버에서 동일한 파일에 접근할 수 있습니다.

파일 동기화 걱정이 사라집니다. 코드로 S3 접근하기 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 boto3라는 AWS의 공식 Python 라이브러리를 사용합니다. 이것이 S3와 통신하는 도구입니다.

boto3.client('s3')로 S3 클라이언트를 생성하면서 인증 정보를 전달합니다. aws_access_key_idaws_secret_access_key는 AWS 계정의 인증 키입니다.

마치 아이디와 비밀번호 같은 역할을 합니다. region_name은 서울 리전(ap-northeast-2)을 지정했습니다.

list_buckets() 메서드를 호출하면 현재 계정에 있는 모든 버킷 목록을 가져옵니다. 버킷이 뭔지는 다음 섹션에서 자세히 다루겠지만, 일단 최상위 폴더라고 생각하면 됩니다.

실무 활용 사례 실제 현업에서는 어떻게 활용할까요? 예를 들어 인스타그램 같은 SNS 서비스를 개발한다고 가정해봅시다.

사용자들이 매일 수천 장의 사진을 업로드합니다. 이 모든 사진을 S3에 저장하면 서버는 가벼운 웹 애플리케이션 실행에만 집중할 수 있습니다.

Netflix, Airbnb, Spotify 같은 글로벌 기업들도 S3를 핵심 인프라로 사용하고 있습니다. 수십억 개의 파일을 안정적으로 관리하는 검증된 서비스입니다.

주의사항 하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 인증 키를 코드에 직접 작성하는 것입니다.

위 예제처럼 코드에 키를 넣으면 GitHub에 올렸을 때 유출될 위험이 있습니다. 환경 변수나 AWS IAM Role을 사용하는 것이 안전합니다.

또한 S3는 네트워크를 통해 접근하기 때문에 로컬 디스크보다 느립니다. 매우 빈번하게 읽고 쓰는 작은 파일들은 서버 메모리나 Redis 같은 캐시를 사용하는 것이 더 효율적입니다.

정리 다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.

"아, S3는 클라우드 하드디스크 같은 거군요!" AWS S3를 제대로 이해하면 파일 저장 걱정 없이 서비스를 확장할 수 있습니다. 여러분도 오늘 배운 내용으로 S3의 기본 개념을 완전히 이해했을 것입니다.

실전 팁

💡 - AWS 프리티어를 사용하면 매월 5GB까지 무료로 S3를 사용할 수 있습니다

  • boto3 설치는 pip install boto3로 간단하게 할 수 있습니다
  • 인증 키는 절대 코드에 직접 작성하지 말고 환경 변수나 IAM Role을 사용하세요

2. 버킷과 객체 개념

S3의 기본 개념을 이해한 김개발 씨가 실제로 파일을 업로드하려고 하자 또 다른 용어가 등장했습니다. "버킷?

객체? 이게 뭐지?" 박시니어 씨가 웃으며 말했습니다.

"S3의 구조를 이해하려면 먼저 이 두 개념부터 알아야 해요."

**버킷(Bucket)**은 S3에서 파일을 담는 최상위 컨테이너이고, **객체(Object)**는 버킷 안에 저장되는 실제 파일입니다. 마치 하드디스크의 파티션이 버킷이고, 그 안의 파일들이 객체라고 생각하면 됩니다.

버킷 이름은 전 세계에서 유일해야 하며, 하나의 버킷에는 무제한 개수의 객체를 저장할 수 있습니다.

다음 코드를 살펴봅시다.

import boto3

s3_client = boto3.client('s3', region_name='ap-northeast-2')

# 버킷 이름은 전 세계에서 유일해야 함
bucket_name = 'my-company-profile-images-2024'

# 버킷 생성 - 최상위 컨테이너
s3_client.create_bucket(
    Bucket=bucket_name,
    CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-2'}
)

# 객체(파일) 정보 조회
response = s3_client.list_objects_v2(Bucket=bucket_name)

# 버킷 안의 모든 객체 출력
for obj in response.get('Contents', []):
    print(f"객체 키: {obj['Key']}, 크기: {obj['Size']} bytes")

박시니어 씨가 화이트보드에 그림을 그리기 시작했습니다. "S3의 구조는 생각보다 단순해요.

두 가지만 기억하면 됩니다." 버킷이란 무엇인가? 버킷은 S3에서 가장 상위 단계의 저장 공간입니다. 쉽게 비유하자면, 버킷은 마치 아파트 동수와 같습니다.

101동, 102동처럼 큰 구역을 나누는 것처럼, 버킷도 파일들을 큰 단위로 구분합니다. 예를 들어 회사에서 여러 프로젝트를 진행한다면, 프로젝트마다 버킷을 하나씩 만들 수 있습니다.

company-project-a, company-project-b 이런 식으로요. 또는 용도별로 나눌 수도 있습니다.

company-user-profiles, company-product-images 같은 방식입니다. 중요한 점은 버킷 이름이 전 세계에서 유일해야 한다는 것입니다.

다른 누군가가 my-bucket이라는 이름을 이미 사용 중이라면, 여러분은 그 이름을 사용할 수 없습니다. 따라서 회사 이름이나 도메인을 포함시키는 것이 좋습니다.

객체란 무엇인가? 객체는 버킷 안에 저장되는 실제 데이터입니다. 일반적으로 파일이라고 생각하면 됩니다.

사진, 동영상, 문서, 로그 파일 등 모든 종류의 파일이 객체가 될 수 있습니다. 각 객체는 **키(Key)**라는 고유한 이름을 가집니다.

이 키가 파일의 경로와 이름을 나타냅니다. 예를 들어 users/1234/profile.jpg라는 키는 마치 폴더 구조처럼 보이지만, 실제로는 하나의 긴 이름일 뿐입니다.

객체에는 실제 데이터 외에도 메타데이터가 함께 저장됩니다. 파일 크기, 생성 날짜, 콘텐츠 타입 등의 정보가 자동으로 기록됩니다.

왜 이렇게 구조화했을까? 초창기 파일 시스템에서는 모든 파일을 한 곳에 저장했습니다. 파일이 적을 때는 문제가 없었지만, 수백만 개로 늘어나자 관리가 어려워졌습니다.

S3는 버킷이라는 논리적인 경계를 만들어서 이 문제를 해결했습니다. 버킷마다 다른 권한 설정, 다른 암호화 정책, 다른 백업 규칙을 적용할 수 있습니다.

예를 들어 사용자 프로필 이미지는 누구나 볼 수 있게 공개하고, 회사 기밀 문서는 특정 직원만 접근하도록 설정할 수 있습니다. 버킷 단위로 이런 정책을 관리하면 훨씬 편리합니다.

코드 분석 위의 코드를 살펴보겠습니다. create_bucket() 메서드로 새 버킷을 생성합니다.

Bucket 파라미터에 원하는 이름을 지정하는데, 소문자와 하이픈만 사용할 수 있습니다. 대문자나 언더스코어는 사용할 수 없습니다.

CreateBucketConfiguration에서 LocationConstraint를 지정합니다. 이것은 버킷을 어느 지역에 만들지 정하는 것입니다.

서울 리전은 ap-northeast-2입니다. list_objects_v2() 메서드는 버킷 안의 모든 객체 목록을 가져옵니다.

반환된 딕셔너리에서 Contents 키로 객체 리스트에 접근합니다. 각 객체는 키 이름과 크기 등의 정보를 담고 있습니다.

실무 활용 실제 프로젝트에서는 어떻게 구성할까요? 쇼핑몰 서비스를 예로 들어봅시다.

버킷을 용도별로 나눕니다. myshop-product-images 버킷에는 상품 사진들을 저장하고, myshop-user-uploads 버킷에는 사용자가 올린 리뷰 사진들을 저장합니다.

myshop-order-receipts 버킷에는 주문 영수증 PDF 파일들을 보관합니다. 각 버킷마다 다른 수명 주기 정책을 적용할 수 있습니다.

상품 사진은 계속 보관하지만, 오래된 로그 파일은 90일 후 자동 삭제하도록 설정하는 식입니다. 주의사항 초보자들이 자주 하는 실수가 있습니다.

첫째, 버킷을 너무 많이 만드는 것입니다. AWS 계정당 기본 100개까지만 버킷을 만들 수 있습니다.

파일 종류마다 버킷을 만들 필요는 없습니다. 객체의 키(경로)로 구분하는 것이 더 효율적입니다.

둘째, 버킷 이름을 나중에 변경할 수 없다는 점을 모르는 경우입니다. 한 번 만든 버킷의 이름은 바꿀 수 없습니다.

처음부터 신중하게 이름을 정해야 합니다. 정리 김개발 씨가 이해한 표정으로 말했습니다.

"아, 버킷은 큰 상자고 객체는 그 안의 물건이라고 생각하면 되겠네요!" 박시니어 씨가 고개를 끄덕였습니다. "정확해요.

그리고 버킷 이름은 전 세계에서 유일해야 한다는 것, 잊지 마세요." 버킷과 객체의 개념을 이해하면 S3의 나머지 기능들도 쉽게 이해할 수 있습니다.

실전 팁

💡 - 버킷 이름은 DNS 규칙을 따라야 하므로 소문자, 숫자, 하이픈(-)만 사용 가능합니다

  • 하나의 AWS 계정에서 기본 100개의 버킷까지 생성할 수 있습니다
  • 버킷은 리전별로 생성되지만, 버킷 이름은 전체 AWS에서 유일해야 합니다

3. 버킷 생성하기

개념을 이해한 김개발 씨가 드디어 실전에 돌입했습니다. "이제 진짜 버킷을 만들어볼까요?" 하지만 AWS 콘솔을 열어보니 설정 옵션이 너무 많아서 어떤 걸 선택해야 할지 막막했습니다.

박시니어 씨가 옆에서 하나씩 설명해주기 시작했습니다.

버킷 생성은 이름과 리전을 정하는 것이 핵심입니다. 퍼블릭 액세스 차단 설정으로 보안을 강화하고, 버전 관리로 파일의 이전 버전을 보관할 수 있습니다.

코드로 버킷을 생성하면 자동화와 반복 작업이 가능해집니다. 한 번 설정해두면 동일한 구성의 버킷을 몇 초 만에 여러 개 만들 수 있습니다.

다음 코드를 살펴봅시다.

import boto3
from botocore.exceptions import ClientError

s3_client = boto3.client('s3', region_name='ap-northeast-2')

bucket_name = 'mycompany-storage-2024'

try:
    # 버킷 생성
    s3_client.create_bucket(
        Bucket=bucket_name,
        CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-2'}
    )

    # 퍼블릭 액세스 차단 (보안 강화)
    s3_client.put_public_access_block(
        Bucket=bucket_name,
        PublicAccessBlockConfiguration={
            'BlockPublicAcls': True,
            'IgnorePublicAcls': True,
            'BlockPublicPolicy': True,
            'RestrictPublicBuckets': True
        }
    )

    # 버전 관리 활성화
    s3_client.put_bucket_versioning(
        Bucket=bucket_name,
        VersioningConfiguration={'Status': 'Enabled'}
    )

    print(f"버킷 '{bucket_name}' 생성 완료!")

except ClientError as e:
    print(f"오류 발생: {e}")

박시니어 씨가 화면을 가리키며 설명을 시작했습니다. "버킷 만드는 건 어렵지 않아요.

하지만 보안 설정을 제대로 안 하면 나중에 큰일 나요." 버킷 이름 정하기 버킷 이름을 정하는 것부터 신중해야 합니다. 이름은 전 세계에서 유일해야 하기 때문에, 너무 흔한 이름은 이미 다른 사람이 사용 중일 가능성이 높습니다.

좋은 명명 규칙은 회사명이나 프로젝트명을 앞에 붙이는 것입니다. mycompany-storage-2024처럼 연도를 붙이면 더 유일하게 만들 수 있습니다.

또는 도메인을 뒤집어서 사용하는 방법도 있습니다. com-mycompany-storage 같은 식입니다.

절대 피해야 할 실수는 이름에 민감한 정보를 넣는 것입니다. mycompany-secret-files 같은 이름은 해커들에게 "여기 중요한 파일 있어요"라고 광고하는 것과 같습니다.

리전 선택하기 리전은 버킷이 물리적으로 위치할 데이터 센터를 의미합니다. 한국에서 서비스한다면 서울 리전(ap-northeast-2)을 선택하는 것이 가장 빠릅니다.

리전이 중요한 이유는 속도 때문입니다. 서울에 있는 사용자가 미국 버지니아 리전의 파일에 접근하면 물리적 거리 때문에 느려집니다.

반대로 서울 리전을 사용하면 응답 속도가 월등히 빨라집니다. 또한 법적 규제도 고려해야 합니다.

금융 데이터나 개인정보는 특정 국가 밖으로 반출하면 안 되는 경우가 있습니다. 이런 경우 반드시 국내 리전을 사용해야 합니다.

퍼블릭 액세스 차단 이 부분이 가장 중요합니다. 몇 년 전 대형 보안 사고들의 원인 중 하나가 바로 S3 버킷의 잘못된 공개 설정이었습니다.

기본적으로 모든 퍼블릭 액세스를 차단해야 합니다. 위 코드의 put_public_access_block() 메서드가 바로 이 역할을 합니다.

네 가지 옵션을 모두 True로 설정하면 외부에서 절대 접근할 수 없습니다. "그럼 웹사이트에서 이미지를 보여줄 수는 없나요?"라고 물을 수 있습니다.

좋은 질문입니다. 이 경우 CloudFront라는 CDN 서비스를 함께 사용하거나, 미리 서명된 URL(Presigned URL)을 생성해서 제공하면 됩니다.

버전 관리 설정 버전 관리를 활성화하면 파일을 덮어써도 이전 버전이 보관됩니다. 마치 구글 문서의 버전 기록처럼 말이죠.

예를 들어 profile.jpg를 업로드하고, 나중에 같은 이름으로 다시 업로드해도 이전 파일이 삭제되지 않습니다. 필요하면 언제든 이전 버전으로 복원할 수 있습니다.

이 기능은 실수로 중요한 파일을 덮어쓰거나 삭제했을 때 생명줄이 됩니다. 특히 여러 명이 작업하는 프로젝트에서는 필수입니다.

코드 분석 위 코드를 단계별로 살펴보겠습니다. 먼저 try-except 블록으로 감싸서 오류를 처리합니다.

이미 존재하는 버킷 이름을 사용하면 오류가 발생하기 때문입니다. create_bucket() 메서드로 버킷을 생성합니다.

CreateBucketConfiguration은 서울 리전 이외의 리전에서 버킷을 만들 때 필수입니다. us-east-1 리전만 이 설정이 불필요합니다.

그 다음 put_public_access_block()으로 보안을 강화합니다. 이 설정은 나중에도 변경할 수 있지만, 처음부터 차단해두는 것이 안전합니다.

마지막으로 put_bucket_versioning()으로 버전 관리를 켭니다. StatusEnabled로 설정하면 활성화됩니다.

실무 팁 실제 현업에서는 버킷을 수동으로 만들지 않습니다. 인프라를 코드로 관리하는 IaC(Infrastructure as Code) 도구를 사용합니다.

Terraform이나 CloudFormation 같은 도구로 버킷 설정을 코드로 작성해두면, 개발/스테이징/프로덕션 환경에 동일한 구성의 버킷을 자동으로 배포할 수 있습니다. 실수도 줄어들고 관리도 편해집니다.

주의사항 버킷을 만들 때 흔히 하는 실수가 있습니다. 첫째, 리전을 잘못 선택하는 경우입니다.

실수로 미국 리전에 버킷을 만들면 한국 사용자에게 느린 서비스를 제공하게 됩니다. 한 번 만든 버킷의 리전은 변경할 수 없으므로 삭제하고 다시 만들어야 합니다.

둘째, 보안 설정을 나중으로 미루는 것입니다. "일단 만들고 나중에 설정하지 뭐"라고 생각하면 안 됩니다.

그 "나중"에 해킹 사고가 일어날 수 있습니다. 버킷 생성과 동시에 보안 설정을 완료해야 합니다.

정리 김개발 씨가 코드를 실행했고, 버킷이 성공적으로 생성되었습니다. "생각보다 간단하네요!" 박시니어 씨가 웃으며 답했습니다.

"간단하지만 보안 설정만큼은 절대 소홀히 하면 안 돼요. 한 번의 실수가 회사 전체를 위험에 빠뜨릴 수 있으니까요." 버킷 생성의 핵심은 올바른 보안 설정입니다.

오늘 배운 내용을 토대로 안전한 버킷을 만들어보세요.

실전 팁

💡 - 버킷 이름에 회사명이나 프로젝트명을 포함시켜 충돌을 방지하세요

  • 모든 퍼블릭 액세스는 기본적으로 차단하고, 필요할 때만 제한적으로 허용하세요
  • 버전 관리는 약간의 비용이 추가되지만 데이터 손실을 막는 보험입니다

4. 파일 업로드 다운로드

버킷을 만든 김개발 씨가 이제 실제로 파일을 올려보려 합니다. "사용자 프로필 이미지를 업로드하고, 필요할 때 다운로드해야 하는데 어떻게 하죠?" 박시니어 씨가 노트북을 열며 말했습니다.

"boto3의 upload_file()download_file() 메서드를 사용하면 간단해요."

파일 업로드는 로컬 파일 경로와 S3 객체 키를 지정하면 됩니다. 다운로드는 그 반대로 S3 객체 키와 저장할 로컬 경로를 지정합니다.

대용량 파일은 자동으로 멀티파트 업로드되어 효율적으로 처리됩니다. 메타데이터를 함께 저장하면 파일 타입, 캐시 설정 등을 관리할 수 있습니다.

다음 코드를 살펴봅시다.

import boto3
import os

s3_client = boto3.client('s3', region_name='ap-northeast-2')
bucket_name = 'mycompany-storage-2024'

# 파일 업로드
local_file = '/path/to/profile.jpg'
s3_key = 'users/1234/profile.jpg'

# ExtraArgs로 메타데이터와 설정 추가
s3_client.upload_file(
    local_file,
    bucket_name,
    s3_key,
    ExtraArgs={
        'ContentType': 'image/jpeg',
        'Metadata': {'user-id': '1234'},
        'CacheControl': 'max-age=86400'
    }
)
print(f"업로드 완료: {s3_key}")

# 파일 다운로드
download_path = '/path/to/downloaded_profile.jpg'
s3_client.download_file(bucket_name, s3_key, download_path)
print(f"다운로드 완료: {download_path}")

# 파일이 존재하는지 확인
if os.path.exists(download_path):
    print("파일 다운로드 성공!")

박시니어 씨가 화면을 보여주며 설명했습니다. "파일 업로드와 다운로드는 S3의 가장 기본적인 작업이에요.

하지만 제대로 하려면 몇 가지 알아둬야 할 게 있어요." 업로드의 기본 원리 파일을 S3에 업로드한다는 것은 로컬 컴퓨터의 파일을 인터넷을 통해 AWS 데이터 센터로 전송하는 것입니다. 마치 이메일에 첨부파일을 보내는 것과 비슷합니다.

upload_file() 메서드는 세 가지 필수 인자가 필요합니다. 첫째, 업로드할 로컬 파일의 경로입니다.

둘째, 저장할 버킷 이름입니다. 셋째, S3에서 사용할 객체 키(파일 이름)입니다.

객체 키는 슬래시(/)를 사용해서 마치 폴더 구조처럼 만들 수 있습니다. users/1234/profile.jpg라고 하면 실제로 폴더가 생기는 것은 아니지만, AWS 콘솔에서는 폴더처럼 보입니다.

메타데이터 활용하기 ExtraArgs 파라미터를 통해 파일과 함께 추가 정보를 저장할 수 있습니다. 이것이 바로 메타데이터입니다.

ContentType은 파일의 MIME 타입을 지정합니다. 이미지라면 image/jpeg, PDF라면 application/pdf를 설정합니다.

이것을 설정하지 않으면 브라우저에서 파일을 다운로드할 때 올바르게 표시되지 않을 수 있습니다. Metadata에는 커스텀 정보를 담을 수 있습니다.

예를 들어 어떤 사용자가 업로드했는지, 언제 업로드했는지 등의 정보를 저장할 수 있습니다. 나중에 파일을 조회할 때 이 정보를 확인할 수 있습니다.

CacheControl은 브라우저나 CDN이 파일을 얼마나 오래 캐시할지 결정합니다. max-age=86400은 24시간(86400초) 동안 캐시하라는 의미입니다.

자주 바뀌지 않는 파일은 긴 캐시 시간을 설정하면 성능이 향상됩니다. 다운로드의 원리 다운로드는 업로드의 반대입니다.

S3에 있는 파일을 로컬 컴퓨터로 가져오는 것입니다. download_file() 메서드도 세 가지 인자가 필요합니다.

버킷 이름, 다운로드할 객체 키, 저장할 로컬 파일 경로입니다. 주의할 점은 로컬 경로에 이미 같은 이름의 파일이 있으면 덮어쓴다는 것입니다.

따라서 중요한 파일이 있는 경로는 피해야 합니다. 대용량 파일 처리 boto3는 똑똑합니다.

파일이 크면 자동으로 멀티파트 업로드를 사용합니다. 멀티파트 업로드는 큰 파일을 여러 조각으로 나눠서 병렬로 전송하는 기술입니다.

마치 큰 짐을 여러 사람이 나눠서 옮기는 것처럼, 전송 속도가 빨라지고 중간에 실패해도 전체를 다시 보낼 필요가 없습니다. 기본적으로 파일이 8MB보다 크면 자동으로 멀티파트 업로드가 활성화됩니다.

개발자가 특별히 신경 쓸 필요가 없습니다. 진행 상황 추적하기 대용량 파일을 업로드하면 시간이 오래 걸립니다.

사용자에게 진행 상황을 보여주고 싶다면 콜백 함수를 사용할 수 있습니다. 이것은 좀 더 고급 주제이지만, Callback 파라미터에 함수를 전달하면 업로드 중간중간 호출됩니다.

이것으로 프로그레스 바를 구현할 수 있습니다. 코드 분석 위 코드를 자세히 살펴보겠습니다.

업로드 부분에서 ExtraArgs는 딕셔너리 형태로 여러 설정을 담습니다. ContentType을 명시적으로 지정하면 나중에 브라우저에서 파일을 열 때 올바르게 표시됩니다.

다운로드 후 os.path.exists()로 파일이 실제로 저장되었는지 확인합니다. 네트워크 오류 등으로 다운로드가 실패할 수도 있기 때문입니다.

실무 활용 실제 웹 애플리케이션에서는 어떻게 사용할까요? 사용자가 웹 폼에서 파일을 업로드하면, 서버가 그 파일을 임시로 받아서 S3에 전송합니다.

그리고 S3의 객체 키를 데이터베이스에 저장합니다. 나중에 파일이 필요하면 데이터베이스에서 키를 조회해서 S3에서 다운로드하거나 URL을 생성합니다.

예를 들어 사용자 ID가 1234인 사람의 프로필 사진은 users/1234/profile.jpg로 저장합니다. 일관된 명명 규칙을 사용하면 파일 관리가 훨씬 쉬워집니다.

주의사항 초보자들이 자주 하는 실수가 있습니다. 첫째, 로컬 파일 경로를 잘못 지정하는 경우입니다.

상대 경로를 사용하면 현재 작업 디렉토리에 따라 다른 결과가 나올 수 있습니다. 절대 경로를 사용하는 것이 안전합니다.

둘째, ContentType을 설정하지 않는 것입니다. 설정하지 않으면 기본값인 binary/octet-stream이 사용됩니다.

이 경우 브라우저에서 파일을 다운로드하지 않고 보려고 하면 제대로 표시되지 않습니다. 셋째, 오류 처리를 하지 않는 것입니다.

네트워크 문제, 권한 문제 등으로 업로드나 다운로드가 실패할 수 있습니다. 반드시 try-except로 감싸서 오류를 처리해야 합니다.

정리 김개발 씨가 코드를 실행해보니 파일이 순식간에 업로드되었습니다. "와, 생각보다 빠르네요!" 박시니어 씨가 고개를 끄덕였습니다.

"AWS의 네트워크는 정말 빠르죠. 하지만 ContentType 같은 세부 설정도 꼭 챙겨야 나중에 문제가 없어요." 파일 업로드와 다운로드는 간단하지만, 메타데이터와 오류 처리까지 신경 쓰면 훨씬 견고한 시스템을 만들 수 있습니다.

실전 팁

💡 - 파일 업로드 시 ContentType을 명시하면 브라우저에서 올바르게 표시됩니다

  • 5GB 이상의 대용량 파일은 멀티파트 업로드를 사용해야 합니다 (boto3가 자동 처리)
  • 업로드/다운로드는 반드시 try-except로 감싸서 네트워크 오류를 처리하세요

5. 폴더 구조 활용

파일을 몇 개 업로드한 김개발 씨가 문득 궁금해졌습니다. "파일이 수천 개가 되면 어떻게 정리하죠?

폴더를 만들 수 있나요?" 박시니어 씨가 흥미로운 사실을 알려주었습니다. "사실 S3에는 폴더가 없어요.

하지만 폴더처럼 보이게 만들 수 있죠."

S3는 플랫 스토리지 구조로 실제 폴더가 존재하지 않지만, 객체 키에 슬래시(/)를 사용하면 폴더처럼 보입니다. **접두사(Prefix)**를 사용해서 특정 "폴더" 안의 파일들만 조회할 수 있습니다.

이런 논리적 계층 구조는 파일 관리를 쉽게 하고, 권한 설정도 세밀하게 할 수 있게 해줍니다.

다음 코드를 살펴봅시다.

import boto3

s3_client = boto3.client('s3', region_name='ap-northeast-2')
bucket_name = 'mycompany-storage-2024'

# 폴더 구조처럼 파일 업로드
files = [
    ('profile1.jpg', 'users/1234/profile.jpg'),
    ('profile2.jpg', 'users/5678/profile.jpg'),
    ('doc1.pdf', 'documents/2024/report.pdf'),
    ('doc2.pdf', 'documents/2024/invoice.pdf')
]

for local_file, s3_key in files:
    s3_client.upload_file(local_file, bucket_name, s3_key)
    print(f"업로드: {s3_key}")

# 특정 "폴더"의 파일만 조회 (Prefix 사용)
response = s3_client.list_objects_v2(
    Bucket=bucket_name,
    Prefix='users/',  # users/ 로 시작하는 객체만
    Delimiter='/'     # 폴더 구분자
)

print("\nusers/ 안의 내용:")
for obj in response.get('Contents', []):
    print(f"  파일: {obj['Key']}")

# 하위 "폴더" 목록
for prefix in response.get('CommonPrefixes', []):
    print(f"  폴더: {prefix['Prefix']}")

박시니어 씨가 재미있는 비유를 들기 시작했습니다. "S3의 폴더는 마치 도서관의 책 분류 시스템과 비슷해요." 폴더가 없다는 것의 의미 전통적인 파일 시스템에는 실제 폴더(디렉토리)가 존재합니다.

윈도우 탐색기나 맥 파인더에서 보는 그 폴더들은 하드디스크 상에 실제로 존재하는 구조입니다. 하지만 S3는 다릅니다.

S3는 플랫 네임스페이스를 사용합니다. 모든 객체는 같은 평면 상에 놓여 있고, 단지 이름이 다를 뿐입니다.

users/1234/profile.jpg는 폴더 안의 파일이 아니라, 그냥 그런 이름을 가진 하나의 객체입니다. 그렇다면 AWS 콘솔에서 보이는 폴더들은 뭘까요?

그것은 AWS가 슬래시를 기준으로 객체를 그룹화해서 보여주는 것일 뿐입니다. 실제로는 폴더가 없습니다.

왜 이렇게 설계했을까? 플랫 구조의 장점은 확장성입니다. 실제 폴더 구조를 유지하려면 폴더별로 메타데이터를 관리해야 하고, 폴더 안의 파일 개수를 세는 등의 작업이 복잡해집니다.

반면 플랫 구조에서는 모든 객체가 독립적입니다. 한 버킷에 수십억 개의 객체를 넣어도 성능 저하가 거의 없습니다.

폴더 깊이나 파일 개수 제한도 없습니다. 또한 분산 저장도 쉬워집니다.

각 객체는 독립적이므로 AWS는 자유롭게 여러 서버에 분산해서 저장할 수 있습니다. 슬래시로 계층 만들기 그렇다고 파일을 아무렇게나 저장하면 관리가 불가능합니다.

여기서 명명 규칙이 중요해집니다. 슬래시(/)를 사용해서 논리적인 계층을 만들 수 있습니다.

users/1234/profile.jpg라고 이름을 지으면, AWS 콘솔과 대부분의 도구들이 이것을 폴더 구조로 표시해줍니다. 실무에서는 일관된 명명 규칙을 정하는 것이 중요합니다.

예를 들어 <타입>/<연도>/<월>/<파일명> 같은 패턴을 사용하면 시간 순으로 정리하기 쉽습니다. logs/2024/12/app.log 이런 식입니다.

Prefix로 필터링하기 list_objects_v2() 메서드의 Prefix 파라미터가 핵심입니다. 이것은 특정 문자열로 시작하는 객체만 조회합니다.

Prefix='users/'라고 하면 users/로 시작하는 모든 객체를 가져옵니다. users/1234/profile.jpg, users/5678/profile.jpg 모두 포함됩니다.

더 구체적으로 Prefix='users/1234/'라고 하면 특정 사용자의 파일만 조회할 수 있습니다. 이것은 마치 특정 폴더의 내용만 보는 것과 같은 효과입니다.

Delimiter로 폴더처럼 보기 Delimiter='/'를 함께 사용하면 더 재미있어집니다. 이것은 슬래시를 구분자로 사용해서 하위 레벨을 그룹화합니다.

예를 들어 users/ 아래에 users/1234/, users/5678/ 같은 "폴더"가 있다면, CommonPrefixes에 이것들이 리스트로 반환됩니다. 마치 폴더 목록을 보는 것처럼요.

이 기능을 활용하면 파일 브라우저처럼 단계별로 탐색하는 UI를 만들 수 있습니다. 코드 분석 위 코드를 살펴보겠습니다.

첫 번째 부분에서는 여러 파일을 서로 다른 "경로"에 업로드합니다. 실제로는 모두 같은 버킷의 평면에 저장되지만, 이름 덕분에 논리적으로 분류됩니다.

두 번째 부분에서 Prefix='users/'로 users로 시작하는 객체만 조회합니다. Delimiter='/'를 추가하면 CommonPrefixesusers/1234/, users/5678/ 같은 "하위 폴더" 목록이 반환됩니다.

실무 활용 실제 서비스에서는 어떻게 구성할까요? 사용자별로 파일을 분리하려면 users/<사용자ID>/<파일명> 패턴을 사용합니다.

이렇게 하면 특정 사용자의 모든 파일을 쉽게 찾을 수 있고, 사용자를 삭제할 때도 해당 Prefix로 시작하는 모든 객체를 삭제하면 됩니다. 날짜별로 로그를 저장한다면 logs/YYYY/MM/DD/app.log 패턴을 사용합니다.

오래된 로그를 삭제하거나 아카이브할 때 Prefix 기반으로 처리하면 효율적입니다. 주의사항 폴더처럼 보이지만 실제로는 아니라는 점을 잊으면 혼란스러울 수 있습니다.

예를 들어 빈 폴더를 만들 수 없습니다. 폴더는 객체가 있을 때만 보입니다.

users/1234/ 아래에 파일이 하나도 없으면 그 "폴더"는 보이지 않습니다. 또한 폴더 이름을 바꾸는 것도 불가능합니다.

users/members/로 바꾸려면 모든 객체를 하나씩 복사하고 이름을 변경해야 합니다. 수천 개의 파일이 있다면 시간이 오래 걸립니다.

정리 김개발 씨가 놀란 표정으로 말했습니다. "폴더가 없는데 폴더처럼 보이다니, 신기하네요!" 박시니어 씨가 웃으며 답했습니다.

"클라우드 스토리지의 독특한 특징이죠. 하지만 이 방식이 대규모 확장에는 훨씬 유리해요." 슬래시와 Prefix를 잘 활용하면 수백만 개의 파일도 체계적으로 관리할 수 있습니다.

처음부터 좋은 명명 규칙을 정하는 것이 중요합니다.

실전 팁

💡 - 일관된 명명 규칙을 프로젝트 초기에 정하고 문서화하세요

  • Prefix를 활용하면 특정 "폴더"의 파일만 빠르게 조회하거나 삭제할 수 있습니다
  • 빈 폴더는 존재하지 않으므로, 폴더 구조를 유지하려면 최소 하나의 파일이 필요합니다

6. 스토리지 클래스

몇 달 후, 김개발 씨가 청구서를 보고 깜짝 놀랐습니다. "S3 비용이 생각보다 많이 나왔네요!" 박시니어 씨가 청구서를 보더니 말했습니다.

"오래된 파일들을 여전히 Standard 클래스에 저장하고 있네요. 스토리지 클래스를 최적화하면 비용을 70% 이상 줄일 수 있어요."

S3는 여러 스토리지 클래스를 제공하며, 파일의 접근 빈도에 따라 선택할 수 있습니다. Standard는 자주 접근하는 파일용이고, Glacier는 거의 접근하지 않는 아카이브용입니다.

수명 주기 정책을 설정하면 오래된 파일을 자동으로 저렴한 클래스로 이동시킬 수 있습니다. 올바른 클래스 선택으로 성능은 유지하면서 비용을 대폭 절감할 수 있습니다.

다음 코드를 살펴봅시다.

import boto3

s3_client = boto3.client('s3', region_name='ap-northeast-2')
bucket_name = 'mycompany-storage-2024'

# 파일을 특정 스토리지 클래스로 업로드
s3_client.upload_file(
    'archive.zip',
    bucket_name,
    'backups/2024/archive.zip',
    ExtraArgs={'StorageClass': 'GLACIER'}  # 저렴한 아카이브 클래스
)

# 수명 주기 정책 설정 - 자동으로 클래스 변경
lifecycle_policy = {
    'Rules': [
        {
            'Id': 'MoveOldFilesToGlacier',
            'Status': 'Enabled',
            'Filter': {'Prefix': 'logs/'},  # logs/ 폴더만 적용
            'Transitions': [
                {
                    'Days': 30,  # 30일 후
                    'StorageClass': 'STANDARD_IA'  # Infrequent Access로 이동
                },
                {
                    'Days': 90,  # 90일 후
                    'StorageClass': 'GLACIER'  # Glacier로 이동
                }
            ],
            'Expiration': {'Days': 365}  # 365일 후 삭제
        }
    ]
}

s3_client.put_bucket_lifecycle_configuration(
    Bucket=bucket_name,
    LifecycleConfiguration=lifecycle_policy
)
print("수명 주기 정책 설정 완료!")

박시니어 씨가 스토리지 클래스 비교표를 보여주었습니다. "S3의 가장 강력한 기능 중 하나예요.

제대로 활용하면 비용을 엄청나게 절감할 수 있죠." 스토리지 클래스란? 스토리지 클래스는 파일을 저장하는 방식의 종류입니다. 마치 택배 서비스처럼, 빠른 배송(비싼 요금)과 느린 배송(저렴한 요금) 중에서 선택하는 것과 비슷합니다.

AWS는 여러 스토리지 클래스를 제공하며, 각각 가격과 성능이 다릅니다. 핵심은 파일의 특성에 맞는 클래스를 선택하는 것입니다.

주요 스토리지 클래스 S3 Standard는 가장 기본이 되는 클래스입니다. 즉시 접근 가능하고, 가장 빠르지만 가장 비쌉니다.

자주 읽고 쓰는 파일에 적합합니다. 웹사이트 이미지, 활성 데이터베이스 백업 등에 사용합니다.

S3 Standard-IA(Infrequent Access)는 자주 접근하지 않는 파일용입니다. 저장 비용은 Standard의 절반 수준이지만, 파일을 읽을 때마다 추가 요금이 발생합니다.

한 달에 몇 번 정도만 접근하는 파일에 적합합니다. S3 Glacier는 아카이브용 클래스입니다.

저장 비용이 매우 저렴하지만(Standard의 약 1/5), 파일을 꺼내는 데 몇 시간이 걸립니다. 법적으로 보관해야 하지만 거의 보지 않는 문서, 오래된 백업 등에 사용합니다.

S3 Glacier Deep Archive는 가장 저렴한 클래스입니다. 저장 비용이 극도로 낮지만, 파일을 꺼내는 데 12시간 이상 걸립니다.

7년 이상 장기 보관하는 데이터에 적합합니다. 언제 어떤 클래스를 쓸까? 선택 기준은 간단합니다.

얼마나 자주 접근하느냐입니다. 매일 또는 매주 접근하는 파일은 Standard를 사용합니다.

웹사이트 이미지, 현재 진행 중인 프로젝트 파일, 최근 로그 등이 해당됩니다. 한 달에 몇 번 정도만 보는 파일은 Standard-IA가 적합합니다.

지난 분기 보고서, 1-2개월 된 로그 파일 등입니다. 1년에 한두 번 정도만 접근하거나 거의 보지 않는 파일은 Glacier를 사용합니다.

세무 신고용 증빙 서류, 오래된 프로젝트 아카이브 등입니다. 수명 주기 정책의 힘 매일 수동으로 파일을 옮기는 것은 불가능합니다.

여기서 수명 주기 정책이 빛을 발합니다. 수명 주기 정책은 규칙을 한 번 설정해두면 자동으로 실행됩니다.

예를 들어 "logs/ 폴더의 파일은 30일이 지나면 Standard-IA로 옮기고, 90일이 지나면 Glacier로 옮기고, 1년이 지나면 삭제해"라는 규칙을 만들 수 있습니다. 이렇게 설정하면 AWS가 알아서 관리해줍니다.

개발자는 신경 쓸 필요가 없습니다. 새로운 로그 파일이 업로드되면 자동으로 이 규칙이 적용됩니다.

코드 분석 위 코드를 살펴보겠습니다. 첫 번째 부분에서 파일을 업로드할 때 StorageClass를 지정할 수 있습니다.

GLACIER로 설정하면 처음부터 Glacier 클래스로 저장됩니다. 두 번째 부분이 핵심입니다.

put_bucket_lifecycle_configuration()으로 수명 주기 정책을 설정합니다. Rules 배열에 여러 규칙을 정의할 수 있습니다.

각 규칙은 Filter로 어떤 파일에 적용할지 정하고, Transitions로 언제 어떤 클래스로 옮길지 정합니다. Expiration은 최종적으로 파일을 삭제할 시점을 정합니다.

실무 활용 실제 서비스에서는 파일 종류마다 다른 정책을 적용합니다. 사용자 프로필 사진은 계속 Standard로 유지합니다.

자주 보기 때문입니다. 하지만 삭제된 사용자의 사진은 30일 후 자동 삭제되도록 설정합니다.

애플리케이션 로그는 최근 30일은 Standard, 30-90일은 Standard-IA, 90일 이후는 Glacier, 1년 후 삭제로 설정합니다. 대부분의 로그 분석은 최근 데이터로만 하기 때문입니다.

데이터베이스 백업은 최근 7일은 Standard, 7-30일은 Standard-IA, 30일 이후는 Glacier로 설정하고 1년간 보관합니다. 복구가 필요한 경우는 주로 최근 백업이기 때문입니다.

비용 절감 효과 실제로 얼마나 절약할 수 있을까요? 예를 들어 1TB의 데이터를 모두 Standard에 저장하면 월 $23 정도입니다.

하지만 이 중 절반을 Standard-IA로, 나머지 절반을 Glacier로 옮기면 월 $7 정도로 줄어듭니다. 70% 이상 절감됩니다.

대규모 서비스에서는 이 차이가 매우 큽니다. 100TB를 저장한다면 매월 $1,600을 절약할 수 있습니다.

연간으로는 거의 $20,000입니다. 주의사항 하지만 주의할 점도 있습니다.

Glacier에 있는 파일을 읽으려면 먼저 복원 요청을 해야 합니다. 몇 시간 기다려야 파일을 다운로드할 수 있습니다.

따라서 즉시 접근해야 하는 파일은 Glacier에 넣으면 안 됩니다. 또한 Standard-IA와 Glacier는 최소 저장 기간이 있습니다.

30일 미만으로 저장하고 삭제해도 30일치 요금이 청구됩니다. 짧은 기간만 보관하는 파일에는 적합하지 않습니다.

정리 김개발 씨가 수명 주기 정책을 설정하고 며칠 후 확인해보니, 많은 로그 파일들이 자동으로 IA 클래스로 이동했습니다. "다음 달 청구서가 기대되네요!" 박시니어 씨가 웃으며 말했습니다.

"스토리지 클래스 최적화는 한 번 설정해두면 계속 혜택을 받아요. 초기에 제대로 설정하는 것이 중요하죠." 파일의 생명 주기를 이해하고 적절한 스토리지 클래스를 선택하면, 성능은 유지하면서도 비용을 크게 줄일 수 있습니다.

실전 팁

💡 - 로그나 백업처럼 시간이 지날수록 접근 빈도가 낮아지는 파일은 수명 주기 정책을 반드시 설정하세요

  • Glacier에서 파일을 복원할 때는 Expedited(1-5분, 비쌈), Standard(3-5시간, 보통), Bulk(5-12시간, 저렴) 중 선택할 수 있습니다
  • S3 Intelligent-Tiering 클래스를 사용하면 AWS가 자동으로 최적의 클래스를 선택해줍니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#AWS#S3#Boto3#Storage#CloudStorage

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.