아래의 코드 한 줄 이면 서버 가동부터 재시작까지 모두 다해주는 우리 runserver
평생 같이 할 줄 알았는데 Django의 내장 서버 (runserver)는 실서비스에 부적합하다.
라는 이야기를 듣고 왜인지 찾아봤습니다.
python manage.py runserver
이전까지 저는 runserver를 이용해 백그라운드로 돌려도 상관없지 않나?
라는 생각을 해 온 사람으로써 해당 글을 보고 다시 한 번 깨우치게 되었습니다🤦♂️
Django는 왜 runserver를 사용하지 않을까?
결론은 Django 내장 서버는 보안과 성능테스트를 거치지 않았기에 개발용으로만 사용하고, 실제 운영중인 환경 구축은 wsgi와 웹서버로 서비스하도록 권장하고 있습니다.
Gunicorn
은 Python WSGI로 WEB Server(Nginx)
로부터 서버사이드 요청을 받으면 WSGI
를 통해 서버 어플리케이션(Django)
로 전달해주는 역할을 수행합니다. 종합적으로 정리해보면, 웹서버와 Django 사이에서 Request를 처리해주는 역할을 한다고 보면 됩니다. 이 과정에서 WSGI를 사용하는데 파이썬에서 대표적으로 uWSGI, gunicorn이 존재합니다. 두 개 중 gunicorn의 퍼포먼스가 조금 더 좋고 가볍다는 의견이 많기 때문에 저 역시 gunicorn을 사용해보려 합니다.
아래의 명령 한 줄이면 단숨에 설치 가능합니다.
pip install gunicorn
gunicorn --bind 0:8000 [wsgi가 있는 앱 이름].wsgi:application
ex). gunicorn --bind 0:8000 config.wsgi:application
위의 명령을 쪼개서 봐보면 다음의 의미를 가지고 있고,
즉, python manage.py runserver 0.0.0.0:8000
의 명령어를 대체했다고 볼 수 있습니다.
- --bind 0:8000 : 8000번 포트로 WSGI 서버를 수행한다는 의미
- config.wsgi:application : WSGI 서버와 연결된 WSGI 애플리케이션은 config/wsgi.py 파일의 application이라는 의미이다.
여기까지 진행해보면 서버가 오류없이 잘 시작되는 것을 확인해볼 수 있습니다. 다만 웹 브라우저로 접속 시 gunicorn은 동적인 부분을 담당하기 때문에 정적 파일들을 읽어오지 못하고 있는 것을 확인할 수 있습니다. 이 부분 처리는 웹 서버에서 다뤄보겠습니다.
Gnincorn은 앞서 본 것 처럼 포트를 이용해 서버를 가동할 수 있습니다. 하지만 Unix 계열 시스템에서는 포트로 서비스하기보다는 유닉스 소켓을 사용하는 것이 빠르고 효율적입니다.
사용 방법은 크게 어렵지 않고 다음의 명령어를 입력해주면 됩니다.
gunicorn --bind unix:/tmp/gunicorn.sock config.wsgi:application
가동이 되는 것을 확인했으니 종료하고 다음 작업을 해보겠습니다.
Tip!
유닉스 소켓 방식으로 Gunicorn 서버를 실행하면 단독으로 Gunicorn 서버에 접속하여 실행할 수 없습니다.
유닉스 소켓 방식으로 실행한 Gunicorn 서버는 Nginx와 같은 웹 서버에서 유닉스 소켓으로 WSGI 서버에 접속하도록 설정해야 합니다.
이번에는 AWS 서버에 Gunicorn을 서비스로 등록해보려 합니다. 그 이유는 Gunicorn의 시작, 중지를 쉽게 하고, 또 AWS 서버를 재가동할 때 Gunicorn을 자동으로 실행시켜주기 위함입니다. Gunicorn을 서비스로 등록하려면 서비스 파일
을 작성해야 합니다.
# vi /etc/systemd/system/gunicorn.service 파일 생성
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=<계정명>
Group=<계정명>
WorkingDirectory=<프로젝트 경로. 즉 manage.py가 위치한 디렉토리 pwd>
ExecStart=<gunicorn이 설치된 가상환경 위치> \
--workers 1 \
--bind unix:/home/foo/django_test/run/gunicorn.sock \
<wsgi.py가 있는 디렉토리 이름>.wsgi:application
[Install]
WantedBy=multi-user.target
여기서 --workers 1는 Gunicorn 프로세스를 1개 사용하라는 의미입니다.
서비스를 새로 등록하거나 수정한 경우 데몬을 리로드 시켜주어야 합니다.
$ sudo systemctl daemon-reload
$ sudo systemctl start gunicorn # 실행
$ sudo systemctl enable gunicorn # 등록
systemctl start [파일명] - systemd에 작성한 파일을 실행하는 명령어
systemctl enable [파일명] - 서버를 재시작할 때마다 자동으로 실행해주는 명령어
정상적으로 등록이 완료되었다면 초록색의 active 상태로 확인 가능합니다.
$ sudo systemctl status gunicorn # 상태 확인
$ sudo systemctl stop gunicorn #gunicorn.service 중지
$ sudo systemctl restart gunicorn #gunicorn.service 재시작
특히, Django framework 사용 시, views.py 등 django 내부 파일 수정 후에는 sudo systemctl restart gunicorn
명령어로 gunicorn 재시작 해주어야 서버에 반영됩니다.
# config/settings.py
STATIC_ROOT = os.path.join(BASE_DIR, 'templates/')
# config/urls.py
from django.conf.urls.static import static
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
여기까지 진행한 결과, Gunicorn 서비스 상태는 active로 돌아가고, 소켓 방식으로 가동되고 있는 서버에 접속한 페이지는 정상 작동 하지 않아야합니다. 이유는 소켓으로 연결했고 웹 서버에서 유닉스 소켓으로 연동해주어야 정상 작동합니다. 이제 그 연동을 진행보러 갑시다~
참고자료 📩
Django는 왜 runserver를 사용하지 않을까?
Django Gunicorn - wikidocs
Gunicorn - 화해 블로그
Gunicorn Docs
Gunicorn 정리 잘해주신 블로그님
에러 팁 -> 4. guicorn.service 에서 WorkingDirectory에 절대경로로 DJango프로젝트가 설정되어있으니 ExecStart 에서 [wsgi파일이있는폴더].wsgi:application 는 상대경로로 지정해주시면 됩니다..