Django 어플리케이션을 AWS EC2 인스턴스에 배포했는데, 어플리케이션이 정적 파일들을 사용하지 못하고 있다. 조사해보니 배포시에는 다른 디렉토리를 사용한다고 한다. (실제 사용 환경을 가정하면) 얼마나 많은 용량이 필요할지 몰라 S3를 사용하기로 한다. Media 파일도 같이 저장해서 사용할 수 있다는 장점도 있다.
EC2 인스턴스를 통해 CRUD가 가능해야한다. EC2에 직접 설정해주는 방법도 있지만, AmazonS3FullAccess 권한을 가진 IAM 역할을 만들고 EC2에 그 역할을 부여하는 방법으로 진행한다. EC2가 삭제되어도 IAM 역할은 유지되기 때문에 이 방법이 개발할 때 더 실용적인것 같다.
Amazon IAM으로 이동 및 왼쪽 탭에 있는 '역할' 클릭
역할 만들기
신뢰할 수 있는 엔터티 유형 → AWS 서비스, 사용 사례 → EC2 선택 후 다음
S3 검색 후 AmazonS3FullAccess 체크 및 다음
이름을 지정하고 역할을 생성한다. 다시 역할 섹션으로 돌아와보면 방금 만든 역할이 생성되어있다. EC2로 이동한다.
IAM 역할을 부여할 인스턴스 선택 → 작업 → 보안 → IAM 역할 수정
해당 IAM 역할 선택 후 IAM 역할 업데이트 클릭
역할이 부여되었다.
Amazon S3로 이동 → 버킷 만들기 클릭
버킷 이름은 고유해야 한다. 어떤 사람도 같은 이름을 가진 버킷이 없어야 한다. AWS 리전은 EC2 인스턴스가 있는 리전과 같게 선택한다.
모든 퍼블릭 액세스 차단을 해제(체크해제) 한 채로 버킷 만들기를 클릭한다.
권한 탭 → 버킷 정책 → 편집 선택
버킷 ARN을 복사하고 정책 생성기 클릭.
Select Type of Policy → S3 Bucket Policy
진행에 앞서 버킷 정책에 대해 생각해보자[8]. IAM 유저/역할이 S3에 접근할 때, 아래의 정책들이 적용된다:
버킷 정책은 아래와 같이 동작한다:
즉 아무 정책도 없으면 모든 접근이 거부된다. 같은 Principal, Action에 허용과 거부가 같이 있다면 거부가 적용된다.
현재 이 프로젝트는
'*'
)에 대해 GetObject를 허용한다.*
/*
을 붙여서 해당 서비스에 있는 모든 오브젝트를 가리킴을 명시한다.Add Statement 클릭
Generate Policy 클릭 후 뜨는 JSON 문서를 복사한다.
버킷 정책 편집창으로 돌아와 기존 내용 삭제 후 붙여넣고 저장.
완성된 정책은 다음과 같다:
{
"Version": "2012-10-17",
"Id": "Policy1683291350206",
"Statement": [
{
"Sid": "Stmt1683291324706",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::{S3 버킷 이름}/*"
}
]
}
django-storages와 boto3를 설치한다. django-storage는 django가 커스텀 백엔드 저장소를 사용할 수 있게 해주는 패키지이고, boto3은 파이썬으로 Amazon SDK를 제공해주는 패키지이다.
이전 글에 이어서 작업하고 있다면 pipenv를 사용하고 있을 것이다. 그렇지 않다면 pip 명령으로 설치해도 무방하다.
# django-storages
# pip install django-storages
pipenv install django-storages
# Amazon SDK for python development
# pip install boto3
pipenv install boot3
settings.py
INSTALLED_APPS += ['storages',] # django-storages
이 부분은 Django 4.2부터는 달라지니 django-storages 공식 문서를 참고하라.
settings.py
# AWS_ACCESS_KEY_ID = ""
# AWS_SECRET_ACCESS_KEY = ""
AWS_STORAGE_BUCKET_NAME = "버킷 이름"
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
STATICFILES_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
AWS_S3_CUSTOM_DOMAIN = AWS_STORAGE_BUCKET_NAME + ".s3.{S3 리전}.amazonaws.com"
AWS_S3_FILE_OVERWRITE = False
AWS_QUERYSTRING_AUTH = False
AWS_STORAGE_BUCKET_NAME
: S3 저장소 이름DEFAULT_FILE_STORAGE
와 STATICFILES_STORAGE
는 위와 같이 지정한다.AWS_S3_CUSTOM_DOMAIN
: 커스텀 도메인 경로. 위와 같이 하면 된다.AWS_S3_FILE_OVERWRITE
: 같은 이름을 가진 파일이 업로드되었을 때 덮어쓸 것인가?AWS_QUERYSTRING_AUTH
: URL로 액세스 키가 넘어가지 않도록 False
할당.EC2에 배포하는 어플리케이션에 대해서 액세스 키는 발급받지 않아도 된다. IAM 역할을 EC2 인스턴스에 부여했기 때문이다. 다만 IAM 역할이 없는 개인 컴퓨터에서 runserver를 실행해 잘 동작하는지 확인하기 위해서라면 발급받아야 한다. 발급받는 방법에 대해선 이 글 참고.
AWS_ACCESS_KEY_ID
와 AWS_SECRET_ACCESS_KEY
를 제공하지 않으면 boto3은 내부적으로 IAM 정보를 통해 접근한다고 한다. 즉, IAM 권한을 가진 EC2 인스턴스 내에서는 액세스 키를 따로 제공하지 않아도 된다[10].
설정이 완료되었으면 EC2 인스턴스에서 해당 내용일 받아 sudo systemctl restart supervisor
, sudo service restart nginx
로 supervisor와 nginx를 재시작한다.
python manage.py collectstatic
위 명령을 실행해 현재 어플리케이션이 사용하는 정적 파일들을 모아 S3에 업로드하고 배포 환경에서 사용하도록 한다. collectstatic
을 여러번 실행하면, 변경된 파일만 적용되고 변경되지 않은 파일들은 그대로 유지되도록 작동한다.
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
정적 파일 경로가 위와 같이 설정되어 있음에도 collectstatic
실행시 설정된 S3 저장소로 정적 파일이 저장되고 사용된다.