장고에서 AWS Lightsail 버킷에 static/media 저장하기

장고의 File storage API는 기본적으로 로컬 파일 시스템 만을 지원합니다. 클라우드에서는 AWS S3, Azure Storage, Google Cloud Storage 등을 스토리지 시스템을 많이 사용하는 데요. 장고에서는 django-storages 라이브러리를 통해 settings 설정 변경 만으로 손쉽게 스토리지 시스템을 활용할 수 있습니다.

아마존 Lightsail

AWS Lightsail은 AWS에서 제공하는 간편한 웹 어플리케이션 호스팅 서비스입니다. 기존 서비스들이 자유도/설정의 폭이 넓은 만큼 서비스가 많이 복잡했었는데요. Lightsail은 저렴하고 간결한 설정으로 이용할 수 있는 VM/컨테이너/데이터베이스/스토리지/도메인 종합선물세트 서비스입니다.

Lightsail에 대한 전반적인 내용은 (유튜브) Amazon Lightsail로 워드프레스 웹 사이트 이전하기 | AWS Builders 온라인 시리즈 7월, 2022 영상을 참고해주세요.

AWS Lightsail에서 지원하는 서비스 중에 스토리지와 장고를 연동하는 방법에 대해서 살펴보려 합니다.

bd07318011de41f291e6641821c22677.jpg

장고와 연동하게 된다면, 다음 2가지가 가능해집니다.

  1. python manage.py collectstatic 명령 만으로 스토리지 버킷 내 static으로 프로젝트 내 static 파일들이 자동으로 복사됩니다.
  2. 장고 모델에서 models.FileField, models.ImageField로 정의된 필드에 파일을 저장하면, 스토리지 버킷 내 media로 파일이 자동으로 저장됩니다.

이를 가능케하기 위해 뷰/모델/폼 코드를 수정할 필요는 없습니다. 장고의 파일 시스템 API는 완벽히 추상화되어있기에, 몇 개의 settings 설정 만으로 완벽히 동작합니다.

  1. 로컬 개발 시에는 로컬 파일 시스템을 활용하고
  2. AWS Lightsail 배포 시에는 Lightsail bucket에 저장하실 수 있으며, 언제든 환경변수 지정 만으로 다른 스토리지 서비스로 손쉽게 변경하실 수 있습니다.

가상머신에서 서비스를 운영하더라도 스토리지 서비스와 데이터베이스 서비스를 활용하게 되면, 가상머신은 컴퓨팅 계산 만을 담당하게 되고 가상머신 내에서는 저장/관리하는 파일들이 없으므로, 향후 Scale Out 처리에 유리합니다.

django-storages

django-storages 라이브러리는 다음의 스토리지 백엔드를 지원합니다.

  • 아마존 S3, 아마존 Lightsail bucket
  • 마이크로소프트 애저 Storage
  • 구글 Cloud Storage
  • FTP, SFTP 등 : 폐쇄망에서 유용

Amazon Lightsail bucket은 Amazon S3 기반의 서비스이므로 설정하는 방법은 동일합니다. 장고 settings에 다음 3가지 설정이 필요합니다.

  • AWS_S3_ACCESS_KEY_IDAWS_S3_SECRET_ACCESS_KEY
    • 장고에서 버킷 접근을 위해 액세스/시크릿 키가 필요합니다.
  • AWS_STORAGE_BUCKET_NAME : 생성한 버킷의 이름입니다. 버킷 생성 페이지에서는 "버킷 식별"로 안내되고 있습니다.
  • AWS_S3_REGION_NAME : 생성된 "버킷 위치" 리전을 지정합니다. 서울은 ap-northeast-2 입니다.

Lightsail 버킷 생성

"스토리지" > "버킷 생성" 메뉴를 통해 "새 버킷 생성" 페이지로 들어갑니다. 다음 3가지 옵션을 선택해줍니다.

  • 버킷 위치 (리전)
    • 관련설정 : AWS_S3_REGION_NAME
  • 스토리지 플랜 선택
    • 대개의 웹서비스는 가장 작은 5GB로도 충분합니다.
  • 버킷 식별자
    • 관련설정 : AWS_STORAGE_BUCKET_NAME

위 항목을 기입하시고, 버킷을 생성해주세요. 생성에 성공하시면 아래와 같은 화면을 만나시게 됩니다.

155d1da8ff404a269494cb4f00d1e615.jpg

Lightsail 버킷에 static, media 폴더 생성

객체 페이지에서 "새 폴더 생성" 메뉴를 통해 static, media 폴더를 생성해줍니다.

ddb4da12ed4a4e24b244c5f245aad45e.jpg

Lightsail 버킷 액세스 권한 변경

권한 페이지에서 버킷 액세스 권한을 "개별 객체를 퍼블릭 및 읽기 전용으로 설정 가능" 으로 변경해주세요. 버킷 자체의 액세스 권한이 private이라면, 버킷 내 파일들의 권한을 public-read로 설정하더라도 모두 private이 됩니다.

AWS에는 디폴트 액세스 정책이 있습니다. static/media 파일은 권한이 없어도 URL 만으로 읽기가 가능해야 하므로, 아래 ACL 설정에서 public-read로 지정할 것입니다. 디폴트는 private 이며, public-read-write 등의 다양한 옵션을 지원합니다.

91a7155fcdaf405e8ca62c164b18c4c3.jpg

Lightsail 버킷 액세스/시크릿 키 얻기

관련 설정 : AWS_S3_ACCESS_KEY_IDAWS_S3_SECRET_ACCESS_KEY

권한 페이지에서 "액세스 키 생성" 메뉴를 통해 키를 생성해주세요.

0c442d76bcb64942a3b96b4ec776103a.jpg

클릭 몇 단계를 거쳐, 아래 화면에서 2개의 키를 메모장에 복사해주세요.

898efa96dd304f45bd8206cbf9eccab0.jpg

Lightsail 포털에서 할 일은 이제 끝났습니다.

장고 설정

필요한 라이브러리

  • django-storages : 버전 1.13.2에서 테스트되었습니다.
  • boto3 : 버전 1.26.77에서 테스트되었습니다.

settings에 버킷 접근정보 등록

장고 settings에 설정할 정보들을 정리해봅시다.

  • AWS_STORAGE_BUCKET_NAME : 버킷 식별자
  • AWS_S3_ACCESS_KEY_IDAWS_S3_SECRET_ACCESS_KEY : 키 2개
  • AWS_S3_REGION_NAME : 버킷을 서울 리전으로 생성하셨다면, ap-northeast-2 값으로 지정해주셔야 합니다. 버킷 생성 시에 지정한 리전으로 지정해주셔야 합니다.

각 정보들을 잘 가지고 계시겠죠? 이제 장고 settings에 적용해봅시다. 이때 주의하실 점은 절대 소스코드에 직접 기입하지 마세요. 환경변수를 통해 설정값을 주입하는 것이 안전합니다. 각자 사용하시는 환경에 맞춰 환경변수가 로딩될 수 있도록 설정해주세요.

장고 개발환경에서의 환경변수 적용은 django-environ 라이브러리를 활용하시면 .env 파일 로딩도 지원하고, 환경변수 문자열들을 손쉽게 파싱할 수 있어서 편리합니다.

import os

AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME", "")
AWS_S3_ACCESS_KEY_ID = os.environ.get("AWS_S3_ACCESS_KEY_ID", "")
AWS_S3_SECRET_ACCESS_KEY = os.environ.get("AWS_S3_SECRET_ACCESS_KEY", "")
AWS_S3_REGION_NAME = os.environ.get("AWS_S3_REGION_NAME", "ap-northeast-2")

# django-environ 라이브러리를 쓰신 경우, 환경변수 참조하는 예시

AWS_STORAGE_BUCKET_NAME = env.str("AWS_STORAGE_BUCKET_NAME", default="")
AWS_S3_ACCESS_KEY_ID = env.str("AWS_S3_ACCESS_KEY_ID", default="")
AWS_S3_SECRET_ACCESS_KEY = env.str("AWS_S3_SECRET_ACCESS_KEY", default="")
AWS_S3_REGION_NAME = env.str("AWS_S3_REGION_NAME", default="ap-northeast-2")

static, media 별로 스토리지 클래스 구현

임의의 경로에 아래 스토리지 코드를 저장해줍니다. 저는 core/storages/aws.py 경로에 저장한 것으로 가정하겠습니다.

# core/storages/aws.py

from storages.backends.s3boto3 import S3Boto3Storage
from storages.backends.s3boto3 import S3StaticStorage

# 장고 MEDIA 파일을 다루는 각종 설정을 커스텀할 수 있습니다.
#  - "media" 폴더에 저장되도록 location 설정을 해줍니다.
#  - "public-read" 권한으로 업로드되도록 default_acl 설정을 해줍니다.
class AwsMediaStorage(S3Boto3Storage):
    location = "media"
    default_acl = "public-read"

# 장고 STATIC 파일을 다루는 각종 설정을 커스텀할 수 있습니다.
#  - "static" 폴더에 저장되도록 location 설정을 해줍니다.
#  - "public-read" 권한으로 업로드되도록 default_acl 설정을 해줍니다.
class AwsStaticStorage(S3StaticStorage):
    location = "static"
    default_acl = "public-read"

settings에 static/media 스토리지 클래스 지정하기

액세스/시크릿키 및 버킷명이 로딩된 상황에서만 파일/스태틱 스토리지를 변경해주도록 하겠습니다. 아래의 코드를 적용한다면, 3가지 설정 중에 하나라도 누락이 된다면 스토리지 변경은 되지 않고, 로컬 파일시스템에 media/static을 저장하고 관리하게 됩니다.

# settings

import django

if AWS_S3_ACCESS_KEY_ID and AWS_S3_SECRET_ACCESS_KEY and AWS_STORAGE_BUCKET_NAME:
    # 장고 4.2부터 스토리지 클래스 지정방법이 변경되었습니다.
    if django.VERSION < (4, 2):
        DEFAULT_FILE_STORAGE = "core.storages.aws.AwsMediaStorage"
        STATICFILES_STORAGE = "core.storages.aws.AwsStaticStorage"
    else:
        STORAGES = {
            "default": {
                "BACKEND": "core.storages.aws.AwsMediaStorage",
            },
            "staticfiles": {
                "BACKEND": "core.storages.aws.AwsStaticStorage",
            },
        }

collectstatic 동작 확인

이제 collectstatic 명령을 내리면, Lightsail 버킷으로 프로젝트내 static 파일들이 자동으로 복사됩니다. 명령을 여러 번 수행하면, 변경된 파일들만 복사됩니다.

478ffd9d06214316bea8e07e16665b69.jpg

Lightsail 버킷 static 폴더 내에 파일들이 복사된 것을 확인하실 수 있습니다.

2617bf048f4c45fcab35a0f209643a3a.jpg

장고 서버를 띄우시고, 웹페이지 소스보기를 해보시면 각 static 파일들의 주소가 AWS S3 주소로 변경되어있음을 확인하실 수 있습니다. 웹페이지에서도 static 파일들이 잘 로딩될 것입니다.

08d825fffcf94b5d8168e81488e900ae.jpg

media 동작 테스트는 직접 해보세요.

모델에 models.FileField, models.ImageField 타입의 필드가 있다면, 이 필드를 통해 파일을 저장해보세요. Lightsail 버킷 media 폴더에 저장이 됨을 확인하실 수 있습니다.

AWS S3에서의 IAM 설정과 Private 스토리지 설정이 궁금하시다면?

testdriven.ioStoring Django Static and Media Files on Amazon S3 포스팅을 참고해보세요. ;-)

마치며

장고와 Amazon Lightsail 스토리지 연동에 대해서 살펴봤습니다. Amazon S3와의 연동도 환경변수 값만 변경하면 동일하게 동작합니다.

이 외에도 애저/구글/FTP/드랍박스 등의 스토리지도 비슷한 방식으로 구현이 되니 응용하여 구현해보세요.

여러분의 해피 장고 라이프를 응원합니다. ;-)

  • 마지막 편집일시 : 2023년 4월 6일 4:08 오후
  • 최초 생성일시 : 2023년 2월 25일 10:45 오전
🌟 본 포스팅이 도움이 되셨다면 댓글 하나 남겨주시고, 널리 공유도 부탁드립니다. 🌟

댓글

Seongwoo_Lukaid's avatar
Seongwoo_Lukaid 2023년 2월 28일 1:08 오후 (KST)

사이드 프로젝트에서 서버 고민이 있었는데, lightsail도 선택지로 생각해봐야겠군요!!

이진석's avatar
이진석 2023년 3월 1일 12:38 오후 (KST)

좋습니다. AWS EC2를 고려하고 계신다면, 사이드 프로젝트라면 Lightsail을 먼저 고려해보세요. EC2의 맛보기 버전인데, 가격도 저렴하고 무료지원 폭도 넓습니다. ;-)

Lightsail의 컴퓨팅/데이터베이스/버킷을 모두 쓰셔도 좋구요. 1년 동안 무료로 지원되는 서버도 있죠.

무료 지원 이후에 media 스토리지가 따로 필요없으시다면, fly.io를 고려해보시는 것도 좋습니다. 도커 배포를 지원하고 PostgreSQL 데이터베이스도 지원해줍니다. 무료 범위도 크고 $5/월까지는 과금하지 않습니다. 단 스토리지 서비스가 없습니다.

저도 따로 운영해보는 서비스에서 $3.5 나왔는 데, 아래 메일을 보내주더라구요.

Good news from Fly.io! We don’t collect bills smaller than $5.00.
This month, your bill of $3.50 falls below that threshold, so we’re discounting it by 100%.

혹은 fly.io + lightsail 버킷 조합도 괜찮구요.

Seongwoo_Lukaid's avatar
Seongwoo_Lukaid 2023년 3월 2일 12:13 오후 (KST)

와우 자세한 답변 감사합니다..!! fly.io라는 서비스는 처음 들어봤는데, 알아봐야겠네요! 항상 좋은 지식 공유해주셔서 감사합니다 ㅎㅎ