우분투에서 Django와 gunicorn + supervisor + nginx 연동 하기

2017. 1. 4. 10:46Programming/python

요즘은 Django + Nginx 가 대세인가 보다. 구글에서 검색해 보니 많은 사람들이 이런 식으로 사용하는 것을 확인해 볼 수 있었다.


이번 기회에 나도 Django와 Nginx를 연동해 보기로 했다.


예전에 Django와 apache 연동할 때는 아파치 모듈 중에 WSGI 모듈을 설치한 다음에 conf 파일을 수정해 주었는데, 요즘은 gunicorn이라는 python package를 많이 사용하는 것 같다.


WSGI 서버로는 uWSGI와 gunicorn, Apache/mod-wsgi를 많이 사용하는데, uWSGI 같은 경우에는 고성능 서버 성능을 지니고 있으며, gunicorn 같은 경우에는 보통 수준의 성능이지만 설치와 관리가 간단하다는 장점이 있다. 

(mod-wsgi는 별로인 걸로...)


Django 설치


우선 WSGI 서버 설치 전에 Django를 설치하고, test라는 프로젝트를 만들자.

docker 환경에서 작업했기 때문에 virtualenv는 따로 설정해 주지 않았다.


$> pip install django

$> django-admin.py startproject test


하는 김에 static 파일도 생성해두자.

settings.py에다가 아래와 같이 추가한다.


STATIC_ROOT = '/static/files/path/'


collectstatic 명령으로 static 파일을 가져온다.


$> python manage.py collectstatic


django 프로젝트가 잘 만들어졌는지 test를 해보자.


$> cd test

$> python3 manage.py runserver 0.0.0.0:8000


구동이 잘되고 해당 주소와 포트로 아래와 같은 창이 나오면 정상적으로 프로젝트가 만들어진 것이다.



gunicorn 설치


이제 다음으로 gunicorn을 설치하고 테스트 해보자.


$> pip3 install gunicorn

$> gunicorn test.wsgi:application --bind 0.0.0.0:8000



위와 같은 메시지가 나타나면 정상 동작되는 것이다.




해당 프로젝트 폴더(manage.py가 있는 폴더)에 bin 폴더를 만들고, bin 폴더 안에 아래의 내용을 담은 gunicorn_start라는 배치 파일을 만들자.


#!/bin/bash


NAME="test_app"

DJANGODIR=/home/test

SOCKFILE=/home/test/run/gunicorn.sock

USER=root

NUM_WORKERS=3

DJANGO_SETTINGS_MODULE=test.settings

DJANGO_WSGI_MODULE=test.wsgi


echo "Starting $NAME as `whoami`"


export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE

export PYTHONPATH=$DJANGODIR:$PYTHONPATH


RUNDIR=$(dirname $SOCKFILE)

test -d $RUNDIR || mkdir -p $RUNDIR


exec /usr/local/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \

  --name $NAME \

  --workers $NUM_WORKERS \

  --user=$USER \

  --bind=unix:$SOCKFILE \

  --log-level=debug \

  --log-file=-


gunicorn_start 파일의 권한을 바꿔준 후에, test를 위해 gunicorn_start를 실행해보자.


$> chmod u+x gunicorn_start

$> cd ..

$> bin/gunicorn_start


gunicorn_start를 실행시 중요한 점은 해당 파일이 있는 위치가 아니라 그 상위 폴더로 이동한 후 실행해야 한다. 만약 이렇게 하지 않을 경우 해당 프로젝트의 wsgi를 못찾아서 실행이 안되는 경우가 발생한다.


gunicorn_start 파일에 기술된 내용을 간략하게 살펴보자면, 

우선 NUM_WORKERS를 설정할 때는 2 * CPUS + 1의 공식을 적용하는 것이 바람직하다고 한다. 예를 들어 single cpu인 경우 NUM_WORKERS는 3이 된다.


NAME은 top이나 ps등의 명령어를 입력했을 때, 내가 만든 django application이 어떻게 표시되는지를 나타낸다. default로는 gunicorn이라고 표시되며, gunicorn이 많이 떠있을 경우에는 구별이 쉽지 않을 것이다.


supervisor 설치


그럼 이제 gunicorn의 설치도 끝났다. 그럼 이제 supervisor를 설치하고 이전에 작성한 gunicorn_start를 supervisor에 등록해 보자. 

우선 supervisor가 무슨 역할을 하는지 간략하게 설명하자면, 등록된 util을 모니터링 하고 죽으면 다시 기동시켜주는 역할을 하는 python package이다.


내가 만든 django app이 비정상적으로 죽을 경우 재기동을 시키기 위해 설치를 하였다. 참고로 python3에서는 supervisor가 지원되지 않기 때문에 python2에 설치해야 한다.


$> pip install supervisor


설치된 supervisor는 /etc/supervisor/conf.d 폴더 안에 정의된 conf 파일들을 모니터링하고 예외가 발생 시 재시작을 하는 것이기 때문에 test app 에 대해서 해당 conf.d 위치에 test.conf 파일을 만들어야 한다.


[program:test_app]

command = /home/test/bin/gunicorn_start

user = root

stdout_logfile = /home/test/logs/gunicorn_supervisor.log

redirect_stderr = true


supervisor에서 설정한 logfile 디렉토리와 해당 파일을 생성하자.


$> mkdir /home/test/logs

$> touch /home/test/logs/gunicorn_supervisor.log


이제 supervisor를 실행해 보자.


$> supervisord


supervisorctl을 입력하면 내가 등록한 모든 application의 상태를 확인해 볼수가 있다.


$> supervisorctl


supervisorctl reread : application의 conf를 다시 읽는다 (추가된 app이 있는지 상태확인만)

supervisorctl update : 추가된 application을 supervisor에 add 시킨다.

supervisorctl status [앱이름] : 모니터링 하고자하는 app의 상태를 확인한다.

supervisorctl stop [앱이름] : 해당하는 app을 중지한다.

supervisorctl start [앱이름] : 해당하는 app을 구동시킨다.

supervisorctl restart [앱이름] : 해당하는 app을 restart 시킨다.




Nginx 설치


웹서버로 사용하기 위해 Nginx를 설치할 것이다.


$> apt-get install nginx


Django app과와 연동을 위해서 /etc/nginx/sites-available 폴더 안에 test_app 파일을 추가해 주자.


upstream test_app_server {

server unix:/home/test/run/gunicorn.sock fail_timeout=0;

}


server {

listen 8000;

server_name 0.0.0.0;


client_max_body_size 4G;


access_log /home/test/logs/nginx-access.log;

error_log /home/test/logs/nginx-error.log;


location /static/ {

alias /home/test/static/;

}


location /media/ {

alias /home/test/media/;

}


location / {

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header Host $http_host;

proxy_redirect off;


if (!-f $request_filename) {

proxy_pass http://test_app_server;

break;

}

}


error_page 500 502 503 504 /500.html;

location = /500.html {

root /home/test/static/;

}

}


해당 파일이 추가되었으면 site-enabled에도 같은 파일을 적용하기 위해 링크를 걸어준다.


$> ln -s /etc/nginx/sites-available/test_app /etc/nginx/sites-enabled/test_app


문법에 오류가 없는지 확인을 위해 nginx 테스트를 한다.


$> nginx -t


테스트가 성공이란 메시지가 나타나면 nginx를 시작한다.


$> /etc/init.d/nginx start