Django-Deploy_EC2(static)

본 문서는 패스트캠퍼스 ‘Web-Programming School’ 수업 자료를 바탕으로 작성되었습니다.


Static file 와 Media file

staitc 파일 참고 사이트

Static file(css,image,js)은 웹 서비스에 사용하려고 미리 준비해 놓은 정적 파일이다. 서비스 중에도 수시로 추가되거나 변경될 수 있다.
Media file은 사용자가 웹에 업로드하는 파일이다. 파일자체는 정적이지만, 언제 제공되고 필요한지에 대해선 알 수 없다.

# config/settings.py
# Static
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(ROOT_DIR, '.static')
# Media (User-uploaded files)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(ROOT_DIR, '.media')

STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [
    STATIC_DIR,
]
  • STATIC_URL : 웹 페이지에서 사용할 정적 파일의 최상위 URL 경로(URL만 존재)
  • STATIC_ROOT: Django 프로젝트에서 사용하는 모든 정적 파일을 한곳에 모아넣은 경로. DEBUGTrue이면 STATIC_ROOT 설정 작용되지 않음. 웹 서버에서 접근하여 정적파일을 제공하는 곳
  • STATICFILES_DIRS: 개발 단계에서 사용하는 정적파일 경로 지정하는 설정 항목. list나 tuple 로 작성해야 한다.
  • MEDIA_ROOT : 업로드가 끝난 파일을 배치할 최상위 경로 지정하는 설정 항목
  • MEDIA_URL : STATIC_URL과 비슷한 역할

Django에서 정적파일 제공 기능(개발단계)

  • 로컬 서버에서 static url(static/photo/.jpg)로 접근하면 해당 이미지파일을 제대로 볼 수 있다. 그러나 media/ url로 접근한 경우 Page not found 에러가 발생한다. 왜냐하면 Django에서 media file에 대한 처리는 urls.pystatic메소드를 사용해서 정적 파일을 제공하도록 하지만 static file은 아래와 같은 설정이 없어도 제공되도록 설정되어있다.
# config/urls.py
from django.contrib import admin
from django.urls import path, re_path
from config.views import serve_media
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
]

urlpatterns += static(
    settings.MEDIA_URL,
    document_root=settings.MEDIA_ROOT,
)

동작원리

# config/urls.py
from django.contrib import admin
from django.urls import path, re_path
from config.views import serve_media
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'media/(?P<path>.*)$', serve_media),
]

# config/settings.py
def serve_media(request, path):
    # path에는 미디어 파일의 경로가 주어짐
    # 주어진 미디어파일의 경로를 setttings.MEIDA_ROOT를 기준으로해서
    # 해당 파일을 리턴해주는 view함수 구현

    media_file = os.path.join(settings.MEDIA_ROOT, path)

    # rb - 이진파일을 읽기전용 모드로 열기
    return FileResponse(open(media_file, 'rb'))
  • FileResponse : 바이너리 파일에 최적화된 StreamingHttpResponse의 하위 객채
  • StreamingHttpResponse : 장고에서 브라우저로부터의 응답을 스트리밍하는데 사용한다. / 큰 파일을 브라우저에 스트리밍할 때 유용
  • 이렇게 실행을 하면, 이진파일을 그대로 출력하기 때문에 제대로 된 이미지 파일을 볼 수 없다. 이를 위해, 이미지 파일의 형식을 함께 전달해줘야 한다.
def serve_media(request, path):
    media_file = os.path.join(settings.MEDIA_ROOT, path)
    content_type = mimetypes.guest_type(path)

    return FileResponse(open(media_file, 'rb'),
                    content_type=content_type)

웹 서버

# 일반적인 runserver
-  브라우저 -> runserver -> Django

# Deploy
Browser                   -> EC2 -> Nginx -> uWSGI -> Django
Browser (/static/,/media/)-> EC2 -> Nginx

서버 Media

  • DEBUG = False를 하는 경우엔 static/media/ url 모두가 이미지처리를 제대로 하지 못한다.
  • 정적파일의 경우 웹 서버 Nginx가 처리하는게 빠르기 때문에 이러한 설정을 따로 지정해야한다.
<!-- ec2-deploy/.config/nginx-app.conf -->

server {
    listen 80;
    server_name *.amazonaws.com;
    charset utf-8;
    client_max_body_size 128M;

    location / {
        uwsgi_pass unix:///tmp/app.sock;
        include uwsgi_params;
    }

    location /media/ {
        alias /srv/ec2-deploy/.media/;
    }
}
  • 설정파일 설정 후 http://ec2-13-125-207-76.ap-northeast-2.compute.amazonaws.com/media/photo/<이미지파일> 접속 하면 404 에러가 아닌 이미지를 볼 수 있다.

서버 Static

collectstatic

  • staitc 파일은 애플리케이션을 구성할 때 생성되는 파일이다.
  • app/static 파일의 경우 ec2-deploy 프로젝트를 위해 존재하는 파일이다. 이 외에도 여러곳에 static폴더가 있다. (ex django.contrib.admin.static파일이 존재) 이러한 파일을 개별적으로 추가해서 사용하는 것은 번거롭다. 그래서 static 파일을 한 곳에 모아서 관리해보자.
>> ./manage.py collectstatic

Django문서_collectstatic

  • collectsatic : 기본값은 STATICFILES_DIRS 및 INSTALLED_APPS 설정에 지정된 앱의 모든 static디렉토리를 찾는다. 명령이 실행 된후에는 STATICFILES_STORAGE의 post_process () 메소드를 호출하고 관리 명령에 의해 발견 된 경로 목록을 전달한다.
  • 명령어 실행 후에는 config/settings.py 에 설정한 STATIC_ROOT에 모든 static 파일이 존재하는 .static디렉토리가 생성된다.
  • .gitignore에 버전관리와 관련없는 .static 파일을 추가하자

nginx-app.conf 설정

server {
    listen 80;
    server_name *.amazonaws.com;
    charset utf-8;
    client_max_body_size 128M;

    location / {
        uwsgi_pass unix:///tmp/app.sock;
        include uwsgi_params;
    }

    location /media/ {
        alias /srv/ec2-deploy/.media/;
    }


    location /static/ {
        alais /srv/ec2-deploy/.static/;
    }
}
  • 설정 후 http://ec2-13-125-213-17.ap-northeast-2.compute.amazonaws.com/static/< 이미지파일>으로 접속하면 이미지파일이 제대로 출력된다.

deploy.sh

# 그환경에 있는  bash를 사용해라
#!/usr/bin/env bash
export DJANGO_SETTINGS_MODULE=config.settings.production

# Nginx에 존재하던 모든 enabled서버 설정 링크 삭제
sudo rm -rf /ect/nginx/sites-enabled/*
# 프로젝트의 Nginx 설정 (nginx-app.conf)
sudo cp -f /srv/ec2-deploy/.config/nginx-app.conf /etc/nginx/sites-available/nginx-app.conf
sudo ln -sf /ect/nginx/sites-available/nginx-app.conf /etc/nginx/sites-enabled/nginx.conf
sudo cp -f /srv/ec2-deploy/.config/uwsgi.service /etc/systemd/system/uwsgi.service

cd /srv/ec2-deploy/app
# ubuntu 유저로 collectstatic  명령어를 실행 (deploy 스크립트가 root로 설정되서)
/bin/bash -c \
'/home/ubuntu/.pyenv/versions/fc-ec2-deploy/bin/python \
 /srv/ec2-deploy/app/manage.py collectstatic --noinput' ubuntu
sudo systemctl enable uwsgi
sudo systemctl daemon-reload
sudo systemctl restart uwsgi nginx
  • 매번 scp로 복사하고 셋팅을 위해 명령어 치는 것이 불편해서 쉘 스크립트로 정리
  • 이 경우, chmod -R 755 deploy.sh 설정을 통해 실행 권한을 주자