WSGI, uWSGI, uwsgi 용어
일반적으로 웹 서버( Apache, Nginx )는 톰캣, PHP, Django, Node.js 등의 앞단에 배치되어 프록시, 보안, 정적 파일 제공 등의 역할을 합니다.
그런데 웹 서버는 PHP, Python, JavaScript 등의 언어를 해석할 능력이 없기 때문에 프로그래밍 언어를 해석할 수 있는 인터페이스, 즉 CGI가 필요합니다.
WSGI는 python 애플리케이션과 웹 서버가 통신하기 위해 정의된 표준 인터페이스 스펙입니다.
CGI와 WSGI는 웹 요청을 처리할 수 있는 표준 인터페이스 프로그램이라는 점에서 같지만, CGI는 WSGI보다 low level에 있습니다.
( CGI와 WSGI의 차이점에 대해서는 여기을 참고해주세요 ! )
이 글에서 주목할 것은 uWSGI이며, uWSGI는 애플리케이션을 처리 할 수 있는 애플리케이션 서버 컨테이너입니다.
WSGI 스펙에 정의 된 방법을 사용하여 python 애플리케이션과 통신하고, 프로토콜( 기본 프로토콜 : uwsgi )을 통해 다른 웹 서버와 통신합니다.
즉, 기존의 웹 서버에 대한 요청을 애플리케이션이 처리할 수 있도록 변환하는 부분이라고 생각하면 됩니다.
uwsgi는 uWSGI가 웹 서버와 통신하기 위해 구현된 프로토콜입니다.
( WSGI, uWSGI, uwsgi에 대한 보다 자세한 설명은 여기를 참고해주세요 ! )
이제 uWSGI를 통해 Nginx와 Django를 연동할 것입니다.
Django에서 프로젝트를 생성하면 WSGI 프로세스를 사용할 수 있도록 정의된 wsgi.py 파일을 제공해주기 때문에 쉽게 연동이 가능합니다.
자세한 내용은 Django를 직접 설치하면서 알아보도록 하겠습니다.
개발 환경은 CentOS 7, Python3.6이며 가상환경을 사용할 것입니다.
1. Python3.6 설정
저는 주로 Python3을 사용하기 때문에 서버의 Python 버전을 변경하도록 하겠습니다.
Python3.6으로 설정하는 방법에 대해서는 여기를 참고해주세요 !
( 아래의 절차를 Python2버전으로 진행해도 문제는 없을 것으로 생각되는데, 테스트는 해보지 않았습니다. )
2. 가상환경 설정
프로젝트마다 가상환경을 만들어줘서 각 프로젝트의 패키지들이 충돌할 수 있는 것을 방지할 수 있습니다.
즉, 가상환경을 설치하지 않으면 서버 내에 모든 프로젝트들이 하나의 환경을 공유하기 때문에, 프로젝트마다 가상환경을 사용하는 것이 좋습니다.
먼저 가상환경을 제공하는 모듈을 설치하도록 하겠습니다.
# pip3.6 install virtualenvwrapper
virtualenvWrapper는 virtualenv를 사용할 수 있도록 도와주는 모듈입니다.
virtualenv는 가상환경의 코어 기능을 제공하는데, virtualenvwrapper를 설치하면 virtualenv는 자동으로 설치됩니다.
패키지를 설치한 후 .bashrc에서 WORKON_HOME과 virtualenvwrapper를 설정해야 합니다.
# vi ~/.bashrc
export WORKON_HOME=~/Env
export VIRTUALENVWRAPPER_PYTHON=/bin/python3.6
source /usr/bin/virtualenvwrapper.sh
# source ~/.bashrc
이제 가상환경을 사용할 준비는 끝났습니다.
테스트용으로 test라는 이름으로 가상환경을 생성합니다.
# mkvirtualenv test
그 밖에 virtualenv를 사용하는 방법은 간단하게만 알아보겠습니다.
1) 가상환경 비활성화
# deactiavate
2) 가상환경 활성화
# workon 가상화경이름
3) 가상 환경에 설치된 패키지 목록 확인
# pip3.6 list
3. Django 설치 및 실행
이제 가상환경을 활성화 한 채로, Django 프로젝트가 위치 할 디렉터리를 생성하여 이동하여 프로젝트를 생성합니다.
Django에 익숙한 사용자라고 가정하고, 기본적인 Django 설명은 생략하겠습니다.
# mkdir -p /usr/local/victolee
# cd /usr/local/victolee
# pip3.6 install django
# django-admin startproject djangoTest
# cd djangoTest
브라우저에서 Django에 접속 할 수 있는지 테스트 하기 위해, django-test/settings.py 파일의 ALLOWED_HOSTS에 서버의 IP( 저 같은 경우는 192.168.245.129 )를 추가합니다.
참고로 ALLOWED_HOST는 " HTTP Host Header Attack "을 방지하기 위해 필요하다고 합니다.
# vi /usr/local/victolee/djangoTest/djangoTest/settings.py
ALLOWED_HOSTS = ['192.168.245.129']
이제 Django 서버를 실행한 후, 브라우저에서 http://192.168.245.129:8000/ 으로 접속합니다.
# python3.6 manage.py runserver 0.0.0.0:8000
Django 페이지가 응답되면 Django 설치가 잘 된 것입니다.
4. Nginx 설치 및 설정
Nginx를 yum으로 설치하기 위해서는 그 전에 repo를 등록해야 합니다.
/etc/yum.repos.d 경로에 nginx.repo 파일을 생성하여 아래와 같이 작성합니다.
# vi /etc/yum.repos.d/nginx.repo [nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=0 enabled=1
다음으로 Nginx을 yum으로 설치한 후, 서비스를 등록합니다.
# yum install -y nginx
# systemctl start nginx
# systemctl enable nginx
Nginx가 잘 설치되었는지 확인하기 위해 기본 페이지에 접근해보겠습니다.
ipconfig로 IP를 확인한 후, 브라우저에 접속합니다. ( 저같은 경우는 http://192.168.245.129 )
여기까지 준비 작업은 모두 끝났습니다.
이제 본격적으로 Nginx가 Python 언어를 해석할 수 있도록 uWSGI를 설치하고 설정해보도록 하겠습니다.
5. uWSGI 설치 및 설정
여전히 가상환경을 활성화 한 채로 uWSGI 모듈을 설치합니다.
# yum install -y gcc
# pip3.6 install uwsgi
이어서 uWSGI 설정 파일을 작성합니다.
# mkdir -p /etc/uwsgi/sites
# vi /etc/uwsgi/sites/djangoTest.ini
[uwsgi] project = myproject username = root base = /root ### Django Settings # base directory chdir = /usr/local/victolee/djangoTest # python path home = /root/Env/test/bin/python # virtualenv path virtualenv = /root/Env/test # wsgi.py path module = djangoTest.wsgi:application master = true processes = 5 uid = root socket = /run/uwsgi/djangoTest.sock chown-socket = root:nginx chmod-socket = 660 vacuum = true logto = /var/log/uwsgi/djangoTest.log
설정 내용은 다음과 같으며, 더 많은 정보를 원하시면 공식문서 ( 링크 )를 참고해주세요.
chdir
프로젝트 파일 경로
home
python 경로 ( 가상환경을 사용하는 것이 일반적이므로 가상환경의 python 경로를 작성했습니다. )
virtualenv
가상환경을 사용하고 있을 경우, 가상환경 경로를 작성합니다.
module
wsgi.py 파일이 있는 경로에 application 함수를 호출 할 수 있도록 작성합니다.
이 때 주의할 것은 wsgi.py 파일 경로는 chdir를 기준으로 한 경로여야 합니다.
socket
Nginx와 uWSGI를 함께 사용하기 위해서 network port를 사용하지 않고 unix socket을 사용할 것입니다.
디렉터리 경로는 이후에 작성할 service에서 정의할 것이므로 상관 하지 않아도 됩니다.
그리고 socket을 Nginx가 사용할 수 있도록, 소유권( chown )과 허가권( chmod )를 수정했고,
uWSGI 종료 시 socket 파일을 삭제 하도록 vacuum을 설정했습니다.
logto
log를 기록하는 경로인데, 현재 디렉터리가 없기 때문에 생성해야 합니다.
# mkdir -p /var/log/uwsgi
그리고 서버가 실행되면 uWSGI가 실행되도록 서비스를 등록한 하고, 이를 반영하기 위해 daemon-reload 명령어를 수행합니다.
( CentOS 7의 Service를 작성하는 방법은 여기를 참고해주세요 ! )
# vi /etc/systemd/system/uwsgi.service [Unit] Description=uWSGI service [Service]
ExecStartPre=/bin/mkdir -p /run/uwsgi
ExecStartPre=/bin/chown root:nginx /run/uwsgi
ExecStart=/root/Env/test/bin/uwsgi --emperor /etc/uwsgi/sites Restart=always Type=notify NotifyAccess=all [Install] WantedBy=multi-user.target
# systemctl daemon-reload
--emperor
uwsgi는 emperor 모드에서 실행할 수 있습니다.
이 모드에서는 uWSGI 설정 파일의 디렉토리를 감시하고 발견 한 각각에 대한 인스턴스를 생성하게 됩니다.
즉, emperor 모드를 통해 여러 응용 프로그램을 관리 할 수 있습니다.
6. Selinux 해제
소켓 번호가 1024이상이거나, 파일의 소유권이 root일 경우 [emerg] bind() to 0.0.0.0:80 failed (13: permission denied) 에러가 발생한다고 합니다.
일반적으로 Selinux는 끄지 않는 것이 좋지만, 위와 같은 에러가 발생한다면 Selinux를 해제 하도록 합니다.
# vi /etc/sysconfig/selinux SELINUX=enforcing => SELINUX=disabled 으로 수정 # reboot
여기까지의 상황을 정리하면,
Django 프로젝트를 생성하면 wsgi.py 파일을 생성해주기 때문에 현재 저희는 WSGI 애플리케이션을 갖고 있으며,
uWSGI가 이 파일을 읽어서 Django 애플리케이션을 수행하여 응답을 하게 됩니다.
uWSGI는 소켓에서 수신을 대기하다가 uwsgi 프로토콜을 사용하여 통신하게 됩니다.
Nginx에서는 uWSGI 프로세스와 통신하기 위해 uwsgi 프로토콜을 사용하는 reverse proxy 기능이 있고, 이는 HTTP보다 성능이 더 빠릅니다.
이제 Nginx에서 uwsgi를 프로토콜을 사용하는 proxy 설정을 하겠습니다.
djangoTest.conf 파일을 생성하여, 아래와 같이 server block{}를 작성합니다.
# vi /etc/nginx/conf.d/djangoTest.conf
server{
listen 8000;
server_name 192.168.245.129;
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/djangoTest.sock;
}
}
uwsgi_params
uwsgi_params는 uwsgi 프로토콜의 매직 변수로서, 여러 변수들을 정의한 것을 말합니다. ( 링크 )
즉, uwsgi_parama를 include 함으로써 웹 서버가 전달하는 변수들을 사용하여 uWSGI 서버를 동적으로 조정 및 구성 할 수 있습니다.
uwsgi_pass
uwsgi 프로토콜을 사용해서 uWSGI에 트래픽을 전달하는데, ini 파일에서 작성한 unxi socket을 사용합니다.
7. 테스트
이제 마지막으로 uWSGI 서비스를 활성화 한 후,
# systemctl start uwsgi
# systemctl enable uwsgi
브라우저에서 http://192.168.245.129:8000으로 접속해보면 Django 애플리케이션이 실행됩니다.
이상으로 Nginx에 uWSGI 프로토콜을 이용하여, Django를 연동해보았습니다.
내용을 정리하면 다음과 같습니다.
1) 가상환경을 설정하여 테스트를 할 Django 프로젝트 생성
2) Django 프로젝트 경로 및 가상환경 경로를 uWSGI 설정 파일에 등록하여, uwsgi 서비스를 실행할 때 호출
3) uwsgi 프로토콜을 사용하도록 Nginx proxy를 설정하여, Django과 Nginx를 연동