AWS EC2 ubuntu 16.04에 Django runserver 배포하기

AWS EC2 ubuntu 16.04에 Django runserver 배포하기

runserver는 장고의 개발서버이다. 로컬환경에서 개발의 편의성을 위해서 기본적으로 제공해주는 서버이며 실제로 외부로 배포하는 경우는 없다. 하지만 EC2에 적응할 겸, 그리고 최종적으로 nginx + uwsgi + django 를 배포하는 과정으로 가는 과정 중 하나라고 생각하고 정리하려고 한다.

runserver 배포하기

개발서버인 runserver를 배포하는 방법은 크게 어렵지 않다.

1
python manage.py runserver 0.0.0.0:8000

평소 runserver를 하듯이하고 외부 접속을 위해 0.0.0.0 라고 아이피를 명시해준다. 그리고 포트번호는 개발서버와 마찬가지로 8000으로 했다. 물론 포트번호도 변경 가능하다. 그리고 중요한 것이 있는데 AWS EC2에는 인스턴스들의 보안을 위해서 보안그룹이라는 기능이 있다. 해당 EC2의 인스턴스가 속한 보안그룹의 Inbound에서 TCP 8000번 포트를 열어주어야지만 외부에서 접속가능하다.

Share

Nginx와 uWSGI를 이용하여 Django 배포하기

Nginx와 uWSGI를 이용하여 Django 배포하기

웹 서버 Nginx와 uwsgi를 통해 Django를 배포하는 과정을 정리해본다.

엔진엑스와 아파치

Nginx는 웹 서버 중 하나로써 아파치 웹 서버의 C10K문제(한 시스템에 동시접속자 수가 1만명 이 넘어갈때의 효율적인 처리 방법)를 해결하기 위해서 Event-Driven 구조로 되어있는 웹 서버이다.

이벤트 드리븐 방식으로 동작한다는 것은 한 개 또는 고정된 프로세스만을 생성하고 그 프로세스 내에서 비동기 방식으로 요청을 처리하는 것을 의미한다고 한다. 따라서 동시 접속 요청이 많아지게 되더라도 프로세스나 스레드를 생성하는 비용이 존재하지 않기 때문에 보다 더 효율적으로 처리를 할 수 있다고 한다.

  • Apache

    • 스레드 및 프로세스 기반 -> HTTP 요청 하나가 스레드 하나에 의해서 처리
    • 동시 요청이 많으면 많은 스레드가 생성되며 메모리 및 CPU의 낭비가 심해짐
  • Nginx

    • 비동기 Event-Driven 기반 구조 -> 많은 요청을 효과적으로 처리
    • 아파치에 비해 적은 스레드로 클라이언트 요청 처리 가능

연동하기

본격적으로 nginx와 uwsgi 그리고 Django를 연동해보자. 아래와 같은 구성을 가지게 될 것이다.

1
Client <-> Nginx <-> uWSGI <-> Django

엔진엑스 설정

시스템에 nginx가 설치되어 있다면 환경설정을 위한 파일들은 모두 /etc/nginx 아래에 위치할 가능성이 높다. 엔진엑스는 여러 개의 가상 호스트를 지원하기 때문에 각 호스트 별로 다른 설정파일을 가질 수 있는데 이번에는 하나만 서빙하는 것을 목표로 정리하려고 한다.

myproject라는 장고 프로젝트가 있고 기타 설정들은 모두 되어있다고 하자.

conf 파일 생성

myproject를 위한 nginx conf를 생성해주어야 한다. 경로는 /etc/nginx/conf.d 아래에 위치하며 위에서 말한 것 처럼 꼭 하나만 있어야 할 필요는 없다.(여러 호스트를 붙여서 사용하고 싶다면 여러개의 설정 파일이 존재할 수 있다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# cd /etc/nginx/conf.d
# vi myproject.conf

upstream myproject {
# 둘 중 하나만 필요하다
server 127.0.0.1:8000; # 웹 소켓 이용
server unix:///home/ubuntu/myproject/myproject.sock; # 유닉스 소켓 이용
}

server {
listen 80; # 80번 포트를 통해 접속 가능
server_name <server_ip>; # 해당 서버의 주소
charset utf-8;

location / { # / (루트 경로)로 들어오는 주소는 upstream 으로 가게 된다
uwsgi_pass myproject;
include /etc/nginx/uwsgi_params; # uwsgi_params가 있는 파일 경로
}

location /static {
alias /home/ubuntu/myproject/staticfiles; # 장고에서 STATIC_ROOT의 절대경로
}
}

크게 보면 myproject.conf는 upstream 블록과 server 블록으로 나뉘어진다. 80번 포트로 요청이 들어오게 되면 uwsgi_pass에 적혀있는 myproject upstream으로 들어가게된다. nginx와 uwsgi를 연결해주는 부분에 유의해야 하는데 개인적으로 이 부분에서 조금 해맸던 것 같다.

nginx와 uwsgi

nginx와 uwsgi 사이에서 통신하는 방법에는 두 가지가 있다. 첫 번째 방법은 웹 소켓을 이용하는 것이고 두 번째 방법은 유닉스 소켓을 이용하는 것이다. 웹 소켓을 이용하는 방법은 오버헤드가 비교적 크기 때문에 유닉스 소켓을 사용하는 것을 권장한다고 한다.

1
2
3
upstream myproject {
server unix:///home/ubuntu/myproject/myproject.sock; # 소켓이 위치할 경로를 명시하자
}

upstream 블록에서 uwsgi와 통신할때 웹 소켓으로 할지 유닉스 소켓으로 할지 방법에 따라서 uwsgi를 실행하는 옵션이 달라진다.

자세히 살펴보기 전에 nginx를 사용하지 않고 uwsgi - django를 배포할때의 uwsgi 옵션을 떠올려보자. 아마도 아래와 같은 옵션을 주었을 것이다.

1
uwsgi --http :8000 --module myproject.wsgi

클라이언트에서 접속하기 위해서 서버주소에 포트번호 8000번을 더했을 것이다.

웹 소켓 사용 시

웹 소켓을 사용해서 nginx - uwsgi 간에 통신을 한다면 아래와 같이 uwsgi의 옵션을 주어야 한다.

1
uwsgi --socket :8000 --module myproject.wsgi

http 옵션이 아닌 socket 옵션을 주어야한다!! 정말 주의해야한다. http 옵션을 주게되면 오랜시간 접속을 시도하다가 끊키게되며 방법을 찾는 데에 큰 어려움을 겪게 될 것이다.

유닉스 소켓 사용 시

유닉스 소켓을 사용한다면 소켓의 이름과 권한을 정확하게 설정해주어야 한다. 에러가 발생한다면 nginx의 에러로그(/var/log/nginx/error.log)를 보면서 해결책을 찾는 것이 큰 도움이 된다.

1
uwsgi --socket myproject.sock --chmod-socket=666 --module myproject.wsgi

위의 두 가지만 유의한다면 nginx + uwsgi + Django를 배포하는 데에도 큰 어려움을 없을 것 같다. 더 나아가서 해결해야할 것들이 있다면 uwsgi를 서비스에 등록하는 것이 있는데 이는 추후에 더 실습을 해보고 정리하자.

Share

uwsgi와 함께하는 Django 배포하기

uWSGI는 무엇일까?

python으로 웹 개발을 하려고하면 WSGI라는 걸 마주치기 마련이다. uWSGI란 WSGI라는 규칙을 따라서 만들어진 소프트웨어이며 정적인 웹 서버(Apache / Nginx)와 python으로 작성된 Web Framework(Flask / Django) 사이의 통신을 도와주는 역할을한다.

그렇다면 WSGI라는 규칙은 무엇일까? 기본적으로 웹 서버는 HTTP 형식의 요청을 받아서 처리한 뒤 응답해주는 기능을 한다. 이와 같은 처리은 1차적으로 nginx를 통해 이루어지며 서버에서 처리해야 할 작업이 있다면 Django와 같은 WAS(Web Application Server)가 필요하다. 하지만 Django는 python으로 이루어져있기 때문에 HTTP 요청을 이해할 수 없는데 이때에 uWSGI와 같은 소프트웨어가 필요한 것이다. 즉, 파이썬 어플리케이션이 웹 서버와 통신하기 위한 명세라고 보면 된다.

즉, 파이썬 어플리케이션이 웹 서버와 통신하기 위한 명세가 WSGI인 것이다.

uWSGI는 일종의 어플리케이션 컨테이너(Application Container)로써 동작한다고 볼 수 있다. 적재한 어플리케이션(Django)을 실행만 시켜주는 역할을 하기 때문이다.

최종적으로 Django가 돌아가는 환경을 그려보면 아래와 같을 것이다.

1
Client <-> Nginx <-> uWSGI <-> Django

uWSGI와 WSGI에 대해서 알아봤으니 Django와 uWSGI를 연동하는 방법에 대해서 알아보자.

설치하기

uwsgi를 설치해야 한다. 파이썬 패키지 관리자로 설치 할 수 있다.

1
pip install uwsgi

uwsgi를 입력했을때 실행되었다가 바로 종료된다면 제대로 설치된 것이다.

Django 설정

Django 프로젝트를 생성하고 설정을 한다.

1
2
3
4
django-admin startproject myproject

# vi myproject/settings.py
ALLOWED_HOSTS=["*"]

Django 서버를 돌렸을때 접근가능한 호스트를 적어준다. 해당하는 IP를 명시적으로 적어도 되고 위와 같이 모든 주소를 받겠다는 표시를 해도 된다. runserver를 통해 제대로 동작하는지 확인한다.

1
python manage.py runserver

uWSGI 설정

uWSGI를 실행하여 Django와 연동해보자.

1
uwsgi --http :8001 --chdir /home/ubuntu/myproject --module myproject.wsgi

–chdir 옵션에 manage.py가 있는 Django 프로젝트의 경로를 적어준다. –module 옵션은 wsgi 파일을 입력해주면 되는데 프로젝트 이름과 같은 이름으로 적는다. 마지막 –http 옵션은 접속할 포트 번호를 적는다. 즉, 위와 같은 명령을 실행하면 서버의 아이피주소에 8001번 포트를 붙여서 접속할 수 있게된다.

하지만 가상환경을 사용 중이라면 추가적인 옵션이 필요하다.

1
uwsgi --http :8001 --virtualenv /home/ubuntu/.pyenv/versions/3.7.3/envs/myvenv --chdir /home/ubuntu/myproject --module myproject.wsgi

나머지 옵션은 동일하며 –virtualenv 옵션이 추가되었다. 사용중인 가상환경을 입력하자. 위 예시의 가상환경이름은 myvenv이다. uwsgi를 구동하기 위해서는 항상 위와 같이 번거로운 작업을 해야할까? .ini 확장자의 설정파일을 만들어서 uwsgi 실행에 필요한 옵션들을 관리할 수 있다.

uWSGI 설정파일 만들기

확장자는 ini이다. 하나의 머신에 여러 프로젝트를 사용할 수 있으므로 uWSGI를 위한 디렉토리를 만들고 설정파일을 모아서 관리하도록 한다.

1
2
mkdir -p /etc/uwsgi/sites
touch /etc/uwsgi/sites/myproject.ini

apt와 같은 패키지 매니저로 소프트웨어를 설치하는 것처럼 /etc 디렉터리 하위에 폴더를 생성해 주고 설정파일을 만들었다. 보통 어떤이름으로 만드는지 모르겠지만 Django 프로젝트와 같은 이름으로 생성해주었다.

1
2
3
4
5
6
# vi /etc/uwsgi/sites/myproject.ini
[uwsgi]
virtualenv = /home/ubuntu/.pyenv/versions/3.7.3/envs/myvenv
chdir = /home/ubuntu/myproject
module = myproject.wsgi
http = :8001

CLI 상에서 나열했던 옵션을 설정파일에 정의했다. 그리고 uwsgi를 실행할때 위의 옵션을 이용하여 구동하게 하면된다.

uWSGI 구동

1
uwsgi -i /etc/uwsgi/sites/myproject.ini

-i 옵션은 –ini의 약자이며 이전에 만든 설정파일을 이용해 uwsgi를 구동할 수 있게 해준다. uwsgi가 바로 꺼지지 않았다면 제대로 동작하는 것이다.

지금까지 uWSGI와 Django를 연동하는 법을 알아보았다. uWSGI를 단독으로 사용하는 경우는 없다고 하며 앞 단에 Nginx와 같은 웹 서버를 두는 것이 일반적인 구성이라고 생각하면 될 것 같다. 그리고 현재까지 진행했던 방법으로는 부족한 면이 없지않아 있는데 그 이유는 uWSGI를 수동으로 작동시켜야 하기 때문이다. 이 와 같은 문제를 해결하려면 uWSGI를 구동하는 서비스를 등록해 주어야하며 나중에 정리하기로 하자.

Share