Ubuntu 14.04에서 uWSGI 및 Nginx 설정하여 Python 앱 제공하는 방법은 무엇인가요?

소개

이 가이드에서는 간단한 WSGI 애플리케이션을 uWSGI로 제공하는 방법을 설정할 것입니다. Nginx 웹 서버를 애플리케이션 서버의 역방향 프록시로 사용하여 더 견고한 연결 처리를 제공합니다. 이러한 구성 요소를 Ubuntu 14.04 서버에 설치하고 구성할 것입니다.

정의 및 개념

일부 용어 설명

시작하기 전에, 다룰 상호 관련된 개념과 관련된 혼란스러운 용어를 다루어야합니다. 실제로 구별되는 다음 세 가지 별도 용어에 대해 알아보겠습니다:

  • WSGI: 응용 프로그램 또는 프레임워크와 응용 프로그램/웹 서버 간의 통신을 위한 표준 인터페이스를 정의하는 Python 사양입니다. 이것은 이러한 구성 요소 간의 통신을 일관성 있게하고 교환 가능하게하기 위해 만들어졌습니다. 이것은 사실 다른 프로토콜을 통해 사용할 수있는 API 인터페이스를 정의합니다.
  • : 웹 애플리케이션 및 서비스를 개발하고 배포하기 위한 완전한 스택을 제공하려는 응용 프로그램 서버 컨테이너입니다. 주요 구성 요소는 여러 가지 언어의 앱을 처리할 수 있는 애플리케이션 서버입니다. 이는 WSGI 사양에서 정의된 방법을 사용하여 응용 프로그램과 통신하며 다른 웹 서버와 다양한 프로토콜을 통해 통신합니다. 이것은 일반적인 웹 서버의 요청을 응용 프로그램이 처리할 수 있는 형식으로 변환하는 부분입니다.
  • uwsgi: uWSGI 서버에서 더 많은 기능을 갖춘 웹 서버와 통신하기 위해 구현된 빠른 이진 프로토콜입니다. 이는 전송 프로토콜이 아닌 와이어 프로토콜입니다. 이것은 uWSGI에 요청을 프록시하는 웹 서버와 대화하는 선호되는 방법입니다.

WSGI 응용 프로그램 요구 사항

WSGI 사양은 스택의 웹 서버 및 애플리케이션 부분 간의 인터페이스를 정의합니다. 이 문맥에서 “웹 서버”는 uWSGI 서버를 의미하며, 이 서버는 WSGI 사양을 사용하여 클라이언트 요청을 애플리케이션으로 변환하는 역할을 합니다. 이는 통신을 간소화하고 교체 가능한 컴포넌트를 생성하여 양쪽을 쉽게 교체할 수 있도록 합니다.

웹 서버 (uWSGI)는 정의된 “callable”을 트리거하여 응용 프로그램에 요청을 보낼 수 있어야합니다. Callable은 간단히 말해서 응용 프로그램으로의 진입점이며, 여기서 웹 서버는 일부 매개변수와 함께 함수를 호출할 수 있습니다. 예상되는 매개변수는 환경 변수의 사전과 웹 서버 (uWSGI) 구성 요소에서 제공하는 callable입니다. 응용 프로그램은 이에 대한 반응으로 클라이언트 응답 본문을 생성하는 데 사용될 iterable을 반환합니다. 또한 매개변수로 받은 웹 서버 구성 요소 callable을 호출합니다. 웹 서버 callable을 트리거할 때의 첫 번째 매개변수는 HTTP 상태 코드이고, 두 번째는 각각 응답 헤더와 값을 정의하는 튜플 목록입니다. 이 상호 작용의 “웹 서버” 구성 요소는이 경우에 uWSGI에서 제공되므로 응용 프로그램이 위에서 설명한 품질을 갖도록만하면됩니다. 우리는 또한 실제 클라이언트 요청을 처리하고 이를 uWSGI 서버로 프록시하는 Nginx를 설정할 것입니다.

구성 요소 설치

시작하려면 Ubuntu 14.04 서버에 필요한 구성 요소를 설치해야합니다. 주로 aptpip를 사용하여이 작업을 수행 할 수 있습니다.

먼저 apt 패키지 인덱스를 새로 고치고 Python 개발 라이브러리 및 헤더, pip Python 패키지 관리자, Nginx 웹 서버 및 역방향 프록시를 설치합니다:

sudo apt-get update
sudo apt-get install python-dev python-pip nginx

패키지 설치가 완료되면 pip Python 패키지 관리자에 액세스할 수 있게 됩니다. 이를 사용하여 우리는 우리의 애플리케이션의 Python 환경을 시스템에 존재할 수 있는 다른 환경들로부터 격리하는 데 사용할 virtualenv 패키지를 설치할 수 있습니다:

sudo pip install virtualenv

이 작업이 완료되면 애플리케이션의 일반적인 구조를 생성할 수 있습니다. 우리는 위에서 언급한 가상 환경을 만들고 이 환경 내에 uWSGI 애플리케이션 서버를 설치할 것입니다.

앱 디렉토리 및 가상환경 설정

우리는 우리 앱을 위한 폴더를 만들어서 시작하겠습니다. 이 폴더는 더 완벽한 애플리케이션에서 실제 애플리케이션 코드가 포함된 중첩된 폴더를 가질 수 있습니다. 우리의 목적에는 이 디렉토리가 우리의 가상 환경과 WSGI 진입점을 단순히 가지고 있을 것입니다:

mkdir ~/myapp/

다음으로, 애플리케이션의 환경을 설정하기 위해 해당 디렉토리로 이동합니다:

cd ~/myapp

virtualenv 명령어로 가상 환경을 만듭니다. 간단하게 myappenv라고 부르겠습니다:

virtualenv myappenv

A new Python environment will be set up under a directory called myappenv. We can activate this environment by typing:

source myappenv/bin/activate

프롬프트가 변경되어 가상 환경 내에서 작동 중임을 나타내야 합니다. 다음과 같이 보일 것입니다:

(myappenv)username@host:~/my_app$

언제든지 이 환경을 떠나고 싶다면, 간단히 다음을 입력하면 됩니다:

deactivate

환경을 비활성화한 경우, 가이드를 계속하려면 다시 활성화하십시오.

이 환경이 활성화되면 설치된 Python 패키지는 이 디렉토리 계층 구조 내에 포함됩니다. 시스템의 Python 환경과 간섭하지 않습니다. 이를 염두에 두고 이제 pip를 사용하여 환경에 uWSGI 서버를 설치할 수 있습니다. 이 패키지의 이름은 uwsgi입니다(이것은 여전히 uWSGI 서버이며 uwsgi 프로토콘이 아닙니다):

pip install uwsgi

이제 다음을 입력하여 사용 가능한지 확인할 수 있습니다:

uwsgi --version

버전 번호가 반환되면 uWSGI 서버를 사용할 수 있습니다.

WSGI 응용 프로그램 만들기

다음으로, 우리는 앞서 논의한 WSGI 사양 요구 사항을 사용하여 매우 간단한 WSGI 응용 프로그램을 만들겠습니다. 반복해서 말하지만, 제공해야 하는 응용 프로그램 구성 요소는 다음과 같은 특성을 가져야 합니다:

  • 호출 가능한을 통한 인터페이스를 제공해야 합니다(호출할 수 있는 함수 또는 기타 언어 구조)
  • 호출 가능은 환경 변수와 유사한 키-값 쌍을 포함하는 사전과 서버(uWSGI)에서 액세스할 수 있는 호출 가능을 매개변수로 받아야 합니다.
  • 응용 프로그램의 호출 가능은 클라이언트에 보낼 본문을 생성할 반복 가능한(iterable)을 반환해야 합니다.
  • 응용 프로그램은 웹 서버의 호출 가능을 HTTP 상태와 요청 헤더와 함께 호출해야 합니다.

우리는 우리의 응용 프로그램 디렉토리에 wsgi.py라는 파일에 응용 프로그램을 작성할 것입니다:

nano ~/myapp/wsgi.py

이 파일 안에는 우리가 만들 수 있는 가장 간단한 WSGI 호환 애플리케이션을 생성할 것입니다. 모든 파이썬 코드와 마찬가지로 들여쓰기에 주의하십시오:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ["<h1 style='color:blue'>Hello There!</h1>"]

위의 코드는 완전한 WSGI 애플리케이션을 구성합니다. 기본적으로 uWSGI는 application이라는 호출 가능한 함수를 찾을 것입니다. 이것이 우리가 함수를 application으로 호출한 이유입니다. 보시다시피 두 개의 매개변수를 사용합니다.

첫 번째로는 환경 변수와 유사한 키-값 사전으로 사용할 environ이라는 이름을 지었습니다. 두 번째는 앱이 내부적으로 웹 서버 (uWSGI)에서 보내는 호출 가능한 함수를 참조하기 위해 사용할 start_response입니다. 이러한 매개변수 이름은 단순히 WSGI 상호 작용을 정의하는 PEP 333 명세의 예제에서 사용된 이름입니다.

우리의 애플리케이션은 이 정보를 가져와 두 가지 작업을 수행해야 합니다. 첫째, 받은 호출 가능한 함수를 사용하여 HTTP 상태 코드와 보낼 헤더를 호출해야 합니다. 이 경우 “200 OK” 응답을 보내고 Content-Type 헤더를 text/html로 설정합니다.

둘째, 응답 본문으로 사용할 반복 가능한 객체를 반환해야 합니다. 여기서는 HTML 문자열이 포함된 단일 문자열 리스트를 사용했습니다. 문자열도 반복 가능하지만 리스트 내에서는 uWSGI가 한 번의 반복으로 전체 문자열을 처리할 수 있습니다.

실제 시나리오에서는 이 파일이 아마도 응용 프로그램 코드의 나머지에 대한 링크로 사용될 것입니다. 예를 들어, Django 프로젝트에는 기본적으로 웹 서버 (uWSGI)에서 요청을 응용 프로그램 (Django)으로 변환하는 wsgi.py 파일이 포함됩니다. 단순화된 WSGI 인터페이스는 실제 응용 프로그램 코드가 얼마나 복잡하든지 변하지 않습니다. 이것이 인터페이스의 강점 중 하나입니다.

작업이 완료되면 파일을 저장하고 닫습니다.

코드를 테스트하려면 uWSGI를 시작할 수 있습니다. 일시적으로 HTTP를 사용하도록 지시하고 포트 8080에서 수신하도록합니다. 스크립트의 이름을 전달합니다 (접미사 제거) :

uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi

이제 웹 브라우저에서 서버의 IP 주소 또는 도메인 이름 뒤에 :8080을 입력하면 wsgi.py 파일에서 본문으로 전달한 첫 번째 수준의 헤더 텍스트가 표시됩니다:

작동을 확인한 후 CTRL-C를 사용하여 서버를 중지합니다.

이 시점에서 실제 응용 프로그램을 설계하는 데 완료되었습니다. 필요에 따라 가상 환경을 비활성화할 수 있습니다:

deactivate

uWSGI 구성 파일 구성

위의 예에서는 uWSGI 서버를 수동으로 시작하고 명령 줄에서 일부 매개 변수를 전달했습니다. 이를 구성 파일을 만들어 피할 수 있습니다. uWSGI 서버는 다양한 형식의 구성을 읽을 수 있지만 간단함을 위해 .ini 형식을 사용할 것입니다.

지금까지 사용해 온 명명 규칙을 계속 사용하려면 파일을 myapp.ini로 지정하고 애플리케이션 폴더에 배치합니다:

nano ~/myapp/myapp.ini

내부에서는 [uwsgi]라는 섹션을 설정해야 합니다. 이 섹션에는 모든 구성 항목이 들어갑니다. 먼저 애플리케이션을 식별합니다. uWSGI 서버는 애플리케이션의 호출 위치를 알아야 합니다. 파일과 내부 함수를 지정할 수 있습니다:

[uwsgi]
module = wsgi:application

초기 uwsgi 프로세스를 마스터로 표시한 다음 여러 개의 워커 프로세스를 생성하려고 합니다. 일단 다섯 개의 워커로 시작하겠습니다:

[uwsgi]
module = wsgi:application

master = true
processes = 5

실제로 uWSGI가 외부와 통신하는 데 사용하는 프로토콜을 변경할 것입니다. 애플리케이션을 테스트할 때 우리는 웹 브라우저에서 볼 수 있도록 --protocol=http를 지정했습니다. uWSGI 앞에 Nginx를 역 프록시로 구성할 것이므로 이를 변경할 수 있습니다. Nginx는 uWSGI가 다른 서버와 통신하는 데 사용할 수 있는 빠른 이진 프로토콜인 uwsgi 프록시 메커니즘을 구현합니다. 실제로 uwsgi 프로토콜은 uWSGI의 기본 프로토콜이므로 프로토콜을 지정하지 않으면 자동으로 uwsgi로 되돌아갑니다.

이 설정을 Nginx와 함께 사용하기 위해 구성 중입니다. 네트워크 포트 대신 Unix 소켓을 사용하도록 변경할 것입니다. 이것은 더 안전하고 빠릅니다. 상대 경로를 사용하면 현재 디렉토리에 소켓이 생성됩니다. 우리는 myapp.sock이라고 부를 것입니다. 권한을 “664”로 변경하여 Nginx가 쓸 수 있도록 할 것입니다 (우리는 Nginx가 사용하는 www-data 그룹으로 uWSGI를 시작할 것입니다). 또한 프로세스가 중지될 때 소켓을 제거할 vacuum 옵션을 추가할 것입니다:

[uwsgi]
module = wsgi:application

master = true
processes = 5

socket = myapp.sock
chmod-socket = 664
vacuum = true

마지막으로 Upstart 파일을 만들 예정이므로 하나의 추가 옵션이 필요합니다. Upstart와 uWSGI는 애플리케이션에 SIGTERM 신호를 어떻게 처리해야 하는지에 대해 다른 관점을 가지고 있습니다. Upstart로 예상대로 프로세스를 처리할 수 있도록이 불일치를 해결하기 위해 die-on-term이라는 옵션을 추가하기만 하면 uWSGI가 프로세스를 종료하도록 할 것입니다:

[uwsgi]
module = wsgi:application

master = true
processes = 5

socket = myapp.sock
chmod-socket = 664
vacuum = true

die-on-term = true

작업을 마치면 파일을 저장하고 닫으십시오. 이 구성 파일은 이제 Upstart 스크립트와 함께 사용할 수 있도록 설정되어 있습니다.

앱을 관리하기 위한 Upstart 파일 생성

우리는 부팅 시 uWSGI 인스턴스를 시작하여 애플리케이션이 항상 사용 가능하도록 할 것입니다. 이를 Upstart가 확인하는 /etc/init 디렉토리에 배치할 것입니다. 우리는 이것을 myapp.conf라고 부를 것입니다:

sudo nano /etc/init/myapp.conf

먼저, 서비스에 대한 설명을 시작하고 시스템 실행 수준을 선택하여 자동으로 실행할 수 있도록 합니다. 표준 사용자 실행 수준은 2부터 5까지입니다. 시스템이 재부팅되거나 단일 사용자 모드일 때와 같이 이 그룹 외의 실행 수준에서 서비스를 중지하도록 Upstart에게 알려줄 것입니다:

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

다음으로, Upstart에게 프로세스를 실행할 사용자와 그룹에 대해 알려줄 것입니다. 이 가이드에서는 자체 계정 아래에서 응용 프로그램을 실행하고 있습니다(여기서는 demo를 사용하고 있지만 사용자의 사용자로 대체해야 합니다). 그러나 Nginx가 사용하는 www-data 사용자의 그룹을 설정하려고 합니다. 이는 웹 서버가 .ini 파일이 만들어 낼 소켓을 읽고 쓸 수 있어야 하기 때문에 필요합니다:

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

setuid demo
setgid www-data

다음으로, uWSGI를 시작하는 실제 명령을 실행할 것입니다. 가상 환경에 uWSGI를 설치했으므로 몇 가지 추가 작업이 필요합니다. uWSGI 실행 파일의 전체 경로를 제공할 수도 있지만 대신 가상 환경을 활성화할 것입니다. 이렇게 하면 환경에 설치된 추가 소프트웨어에 의존하는 경우 더 쉽게됩니다:

이를 위해 script 블록을 사용할 것입니다. 내부에서는 응용 프로그램 디렉토리로 변경하고 가상 환경을 활성화한 다음(스크립트에서는 source 대신 .를 사용해야 함) .ini 파일을 가리키는 uWSGI 인스턴스를 시작할 것입니다:

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

setuid demo
setgid www-data

script
    cd /home/demo/myapp
    . myappenv/bin/activate
    uwsgi --ini myapp.ini
end script

이로써 Upstart 스크립트가 완료되었습니다. 종료하려면 파일을 저장하고 닫으십시오.

이제 다음을 입력하여 서비스를 시작할 수 있습니다:

sudo start myapp

시작되었는지 확인하려면 다음을 입력할 수 있습니다:

ps aux | grep myapp
demo   14618  0.0  0.5  35868  5996 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14619  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14620  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14621  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14622  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14623  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   15520  0.0  0.0  11740   936 pts/0    S+   15:53   0:00 grep --color=auto myapp

부팅시에 자동으로 시작합니다. 언제든지 서비스를 중지하려면 다음을 입력하십시오:

sudo stop myapp

Nginx를 uWSGI로 프록시 설정

이 시점에서 WSGI 앱이 준비되었고 uWSGI가 이를 읽고 제공할 수 있는지 확인했습니다. 구성 파일과 Upstart 스크립트를 만들었습니다. uWSGI 프로세스는 소켓을 통해 수신하고 uwsgi 프로토콜을 사용하여 통신할 것입니다.

이제 Nginx를 역방향 프록시로 구성할 차례입니다. Nginx는 uWSGI와 통신하기 위해 uwsgi 프로토콜을 사용하여 프록시하는 기능이 있습니다. 이는 HTTP보다 빠른 프로토콜이며 성능이 향상됩니다.

설정할 Nginx 구성은 매우 간단합니다. Nginx의 구성 계층 내 sites-available 디렉토리에 새 파일을 만듭니다. 파일 이름은 사용 중인 앱 이름과 일치하도록 myapp이라고 지정합니다:

sudo nano /etc/nginx/sites-available/myapp

이 파일에서 이 서버 블록이 응답해야 하는 포트 번호와 도메인 이름을 지정할 수 있습니다. 우리의 경우, 기본 포트 80을 사용할 것입니다:

server {
    listen 80;
    server_name server_domain_or_IP;
}

이 도메인 또는 IP 주소의 모든 요청을 WSGI 애플리케이션으로 보내고자 하기 때문에, 요청이 /으로 시작하는 단일 위치 블록을 생성할 것입니다. 이 블록은 모든 것과 일치해야 합니다. 내부에서는 합리적인 기본값을 가진 여러 매개변수를 Nginx 구성 디렉터리의 파일인 uwsgi_params에서 포함시키기 위해 include 지시문을 사용할 것입니다. 그런 다음 트래픽을 이전에 구성한 uWSGI 인스턴스로 uwsgi 프로토콜을 통해 전달할 것입니다. 우리는 이전에 구성한 유닉스 소켓을 사용할 것입니다.

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:/home/demo/myapp/myapp.sock;
    }
}

실제로 간단한 애플리케이션에 필요한 모든 것입니다. 더 완전한 애플리케이션을 위해 몇 가지 개선 사항이 있습니다. 예를 들어, 이 블록 외부에서 여러 개의 업스트림 uWSGI 서버를 정의하고 그것들을 전달할 수 있습니다. 더 많은 uWSGI 매개변수를 포함할 수도 있습니다. 또한 Nginx에서 정적 파일을 직접 처리하고 동적 요청만을 uWSGI 인스턴스로 전달할 수도 있습니다.

하지만 우리의 세 줄 앱에는 이러한 기능이 필요하지 않으므로 파일을 저장하고 닫을 수 있습니다.

우리가 만든 서버 구성을 sites-enabled 디렉토리에 링크하여 활성화합니다:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled

구문 오류가 없는지 확인하기 위해 구성 파일을 확인합니다:

sudo service nginx configtest

문제가 감지되지 않았다고 보고되면 서버를 다시 시작하여 변경 사항을 적용합니다:

sudo service nginx restart

Nginx를 다시 시작하면 구성한 애플리케이션을 볼 수 있어야 합니다. 서버의 도메인 이름 또는 IP 주소(포트 번호 없이)로 이동하여 확인하세요:

결론

지금까지 당신은 간단한 WSGI 애플리케이션을 생성하고 더 복잡한 애플리케이션을 설계해야 하는 방법에 대해 어느 정도 이해를 얻었습니다. 우리는 uWSGI 애플리케이션 컨테이너/서버를 우리의 애플리케이션을 제공하기 위한 목적으로 만든 가상 환경에 설치했습니다. 이 프로세스를 자동화하기 위해 구성 파일과 Upstart 스크립트를 만들었습니다. uWSGI 서버 앞에는 uWSGI 프로세스와 통신할 수 있는 Nginx 역방향 프록시를 설정했습니다. uwsgi 와이어 프로토콜을 사용합니다.

실제 제품 환경을 설정할 때 이것이 어떻게 확장될 수 있는지 쉽게 볼 수 있습니다. 예를 들어, uWSGI는 “emperor mode”라는 것을 사용하여 여러 애플리케이션을 관리할 수 있습니다. Nginx 구성을 확장하여 uWSGI 인스턴스 간의 로드 밸런싱을 수행하거나 애플리케이션의 정적 파일을 처리할 수 있습니다. 여러 애플리케이션을 제공할 때는 필요에 따라 가상 환경이 아닌 전역으로 uWSGI를 설치하는 것이 좋을 수 있습니다. 이 구성 요소들은 모두 상당히 유연하므로 다양한 시나리오에 맞게 구성을 조정할 수 있어야 합니다.

Source:
https://www.digitalocean.com/community/tutorials/how-to-set-up-uwsgi-and-nginx-to-serve-python-apps-on-ubuntu-14-04