프로젝트[Admin Page] (2)

oswaldeff·2021년 3월 12일
1

aws rds에 이어, aws s3연결을 해보았다.

역시 django가 알아서 해주는것들은 많지만 반대로 그만큼 내장된 내용들을 이해하고 건드리는것만도 쉽지 않았다.

📃 my_settings.py

# SECURITY WARNING: keep the secret key used in production secret!
KEY = '****'

# DATABASES
DB = {
    .
    .
    .
}

# AWS S3 ACESS KEY
MY_AWS_ACESS_KEY_ID = '****'
MY_AWS_SECRET_ACESS_KEY = '****'

django key와 DB에 이어서 s3에 관한 접근값들을 설정해주었다.

aws IAM에서 사용할 s3에 대해 권한이 있는 사용자를 통하여 credentials.csv를 다운받고,
csv를 열어 해당되는 값들을 MY_AWS_ACESS_KEY_ID와 MY_AWS_SECRET_ACESS_KEY에 기입해준다.
(이 역시 편의상 별로 표기하였다.)

📃 settings.py

from pathlib import Path
from .my_settings import KEY, DB, MY_AWS_ACESS_KEY_ID, MY_AWS_SECRET_ACESS_KEY
import os
import pymysql
import boto3
.
.
.
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
.
.
.
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

# AWS S3 setting

AWS_ACESS_KEY_ID = MY_AWS_ACESS_KEY_ID
AWS_SECRET_ACESS_KEY = MY_AWS_SECRET_ACESS_KEY

AWS_REGION = 'ap-northeast-2'
AWS_STORAGE_BUCKET_NAME = '[s3 bucket name]'
AWS_S3_CUSTOM_DOMAIN = f's3.{AWS_REGION}.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}'

AWS_S3_HOST = 's3.ap-northeast-2.amazonaws.com'
AWS_QUERYSTRING_AUTH = False

AWS_S3_FILE_OVERWRITE = False
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_DEFAULT_ACL = 'public-read'
AWS_LOCATION = '[folder name in bucket]'

# from storages.py

MEDIA_URL = ''
DEFAULT_FILE_STORAGE = '[name]_admin_project.storages.MediaStorage'

boto3는 python에서 AWS로 이미지, 영상파일을 올릴 수 있도록 해주는 라이브러리이다.
boto3.client와 boto3.resource로 s3에 접근할 수 있는데
bucket name을 할당하여 직접 1:1맵핑할 수 있는 client를 사용했다.
(resource는 연결된 계정의 모든 버킷을 for문으로 받아올 수 있도록 할 수 있다고 하며, 상대적으로 client가 low level의 interface라고 한다.)

사실 boto3로만 s3로의 접근이 가능한 줄 알고 시도하다 헤맸는데 결국 awscli를 설치하고
aws configure명령어를 통해 직접적으로 연결해주었다.

media는 사용할 일이 없는 서비스라고 하여 따로 분리하지 않고 default로 설정하였고,
static은 루트폴더 아래에 경로를 지정해주었다.(보안상 static으로 똑같이 명시하지는 않는다고 한다.)

장고는 DEBUG default값을 True로 하여 오류가 나면 해당오류에 대해 내역을 보여준다.
그렇기에 프로젝트를 서버에 올리고난 후 외부에서 접근하였을 때,
보안상 오류에 대한 표기를 해주지 않도록 DEBUG = False로 변경하였다.

코드 중 aws s3고유값들에 대해서는 파이썬 문법과 구분짓도록 { }가 아닌 [ ]로 표기하였다.

📃 storages.py

from storages.backends.s3boto3 import S3Boto3Storage
from .settings import AWS_LOCATION

class MediaStorage(S3Boto3Storage):
    location = AWS_LOCATION

별도의 storages.py파일을 만들어 storage에 대한 class를 생성한다.
location뿐만이 아니라 다른 값들도 여기서 할당할 수 있다.

📃 models.py

from django.db import models
import boto3
from tadoc_admin_project.settings import MEDIA_URL, AWS_STORAGE_BUCKET_NAME

class shop(models.Model):
    .
    .
    .
    img = models.ImageField(upload_to=MEDIA_URL, null=True)
    .
    .
    .
    def delete(self, *args, **kwargs):
    	s3_resource = boto3.client('s3')
        s3_resource.delete_object(Bucket=AWS_STORAGE_BUCKET_NAME, Key=f'{self.img}')
        self.img.delete()
        super(shop, self).delete(*args, **kwargs)

장고내에 이미 정의된 delete()메서드를 override하여 특정 오브젝트에 대하여 delete기능을 수행할 때,
연결된 s3의 해당 이미지파일도 삭제되도록 하였다.

장고에서 저장/삭제를 할때 override하는법은 admin/model에서 접근하는 2가지 방법이 있는데,
request, obj, form, change의 객체에서 값을 꺼내서 사용하는것이 아닌 model내의 특정 오브젝트에 대한 데이터만을 삭제하는데 목적이 있기 때문에 models.py에서 작성해주었다.

override개념 및 코드작성과 관련해서는 아래를 참고하였다.

  1. model method override: https://djangojeng-e.github.io/2020/08/12/Django-Models-15%ED%8E%B8-%EC%9D%B4%EB%AF%B8-%EC%A0%95%EC%9D%98%EB%90%9C-%EB%AA%A8%EB%8D%B8-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%93%9C-%ED%95%98%EA%B8%B0/

  2. override deletion: https://stackoverflow.com/questions/28896237/override-djangos-model-delete-method-for-bulk-deletion

  3. delete object using boto3: https://www.youtube.com/watch?v=ggfvnu4LgCc

한가지 우려되는 부문은 override된 모델 method들은 대량으로 객체를 변경할 수 없다고 하여,
admin page에서 여러 오브젝트들을 한번에 삭제할때 구동이 안될 수도 있을 것 같다.

📂 static

└── [name]_admin_django
	├── static
    	│   └── admin
    	│       └── css
    	│       └── fonts
    	│       └── img
    	│       └── js

DEBUG = False로 변경해주었으므로 이제 더이상 장고 application server를 통해
정적파일들을 제공하지 않는다.(따라서 runserver로 실행하는 것이 아닌 wsgi를 통해 실행할 것이다.)
따라서 python manage.py collectstatic를 통해 static_root 경로에 admin page에 대한 css및 정적파일들을 저장해준다.

aws ec2에서 nginx 웹서버를 구축할 경우 nginx설정을 통해 정적파일들에 대한 경로를 알려줄 수 있다.

🛠 static.conf

server {
    listen 80;
    server_name *.compute.amazonaws.com;
    charset utf-8;
    client_max_body_size 128M;
    
    location / {
        include proxy_params;
        proxy_pass http://127.0.0.1:8000;
        }
    
    location /static/ {
        alias /var/www/[name]_admin/[name]_admin_django/static/;
    }
}

client로부터 http요청이 오면 nginx가 이 요청을 처리해주는데 static.conf는 이에대한 설정파일이다.(nginx.conf로 파일이름을 해야 맞는것 같다. admin page의 css를 받게끔하는데 급급하다보니..)

listen을 통해 기본포트인 80번포트로 요청을 받을 것과 server_name을 통해 요청을 받을 서버주소를
지정해준다.
(도메인이름이 있다면 도메인이름을 지정해주어도 좋다. 편의상 구체적인 주소가 아닌 아마존 서버를 받도록 명시해주었다.)

location을 통해 요청이 dynamic한것이면, proxy_pass를 설정하여 wsgi서버인 gunicorn서버의 주소로 redirect 해주고 static한것이면 aws ec2내의 static경로를 지정해준다.
(alias는 특정 URL이 서빙할 파일 경로를 변경하는 역할을 해준다고 한다.
다만, alias를 사용할 경우 경로끝에 /를 반드시 붙여주어야 한다!
예를들어, 웹페이지에[http://*.compute.amazonaws.com/static/xxx.png]일 때
실제 경로는 [/생략/[name]_admin/[name]_admin_django/static/]이다.)

이제 django, nginx, gunicorn으로 aws ec2를 구축하면 배포가 완료된다.

0개의 댓글