Настройка uWSGI и Nginx для обслуживания приложений Python в Ubuntu 14.04

Данное руководство поможет настроить простое приложение WSGI, обслуживаемое uWSGI. Веб-сервер Nginx используется в качестве обратного прокси-сервера для более надёжного соединения.

Примечание: Все компоненты установлены на сервер Ubuntu 14.04.

Основные понятия и подходы

Прежде чем приступить к работе, нужно разобраться с основными терминами и понятиями. Следующие три термина на первый взгляд кажутся взаимозаменяемыми, но на самом деле они совсем разные:

  • WSGI: спецификация Python, которая определяет стандартный интерфейс для взаимодействия приложения/фреймворка с сервером приложений/веб-сервером. Её цель – упростить и стандартизировать взаимодействие этих компонентов. По сути, WSGI определяет интерфейс API, который можно использовать с другими протоколами.
  • uWSGI: сервер приложений, который обеспечивает полноценную платформу для разработки и развертывания веб-приложений и сервисов. Этот сервер приложений может обрабатывать приложения, написанные на разных языках. Он взаимодействует с приложением согласно спецификации WSGI. Он может взаимодействовать с другими веб-серверами при помощи различных протоколов. Этот компонент трансформирует запросы стандартного веб-сервера в формат, который может обработать приложение.
  • uwsgi: быстрый бинарный протокол, который реализуется сервером uWSGI для взаимодействия с другими полнофункциональными протоколами. Это wire протокол, а не транспортный протокол. Он лучше всего подходит для взаимодействия с веб-серверами, которые проксируют запросы для uWSGI.

Требования к приложениям WSGI

WSGI определяет интерфейс между веб-сервером и приложением. В данном контексте веб-сервером является uWSGI, который отвечает за передачу запросов клиента приложению в понятном формате. Это упрощает взаимодействие и создаёт слабосвязанные компоненты, которые можно легко заменить или удалить.

Веб-сервер (uWSGI) должен иметь возможность отправлять запросы приложению. Callable (или точка входа)– псевдотип данных, «нечто, что можно вызвать как функцию». Ожидаемым параметром является словарь с переменными окружения и точка входа веб-сервера.

В ответ приложение отправляет итератор, при помощи которого будет сгенерировано тело запроса клиента. Также оно вызовет точку входа веб-сервера, которую оно получило в виде параметра. Первым параметром при извлечении точки входа будет код состояния HTTP, а вторым – список наборов, каждый из которых определяет заголовок ответа и значение, которое нужно вернуть клиенту.

Установка компонентов

Для начала нужно установить все необходимые программы на сервер Ubuntu 14.04. Для этого можно использовать apt и pip.

Обновите индекс пакетов и установите библиотеку разработки Python, pip (пакетный менеджер Python) и веб-сервер Nginx.

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

После завершения установки вы получите доступ к пакетному менеджеру pip. С его помощью можно установить пакет virtualenv, который позволяет изолировать окружение приложения Python от остальных программ системы.

sudo pip install virtualenv

После этого можно создать общую структуру приложения. Создайте виртуальное окружение и установите в него сервер приложений uWSGI.

Создание каталога и виртуальной среды приложения

Теперь создайте папку для приложения. В ней вы сможете развернуть виртуальную среду и хранить точку входа WSGI.

mkdir ~/myapp/

Откройте этот каталог:

cd ~/myapp

Создайте виртуальную среду с помощью команды virtualenv (для простоты в руководстве она называется myappenv)

virtualenv myappenv

Теперь в каталоге myappenv развёрнуто новое окружение Python. Включите его:

source myappenv/bin/activate

После этого командная строка изменится. Это значит, что виртуальная среда активна:

(myappenv)username@host:~/my_app$

Чтобы покинуть виртуальную среду, используйте команду:

deactivate

Примечание: Если вы вышли из виртуальной среды только что, вернитесь в неё.

Когда виртуальная среда включена, все устанавливаемые приложения Python будут помещены в иерархию этого каталога. Они не смогут повлиять на общесистемные приложения Python. Теперь можно установить сервер uWSGI с помощью pip. Его пакет называется uwsgi (однако не следует путать пакет сервера uWSGI с протоколом uwsgi).

pip install uwsgi

Чтобы убедиться, что установка прошла успешно, запросите версию:

uwsgi --version

Команда должна вернуть версию сервера uWSGI.

Создание приложения WSGI

Теперь нужно создать простое приложение WSGI согласно спецификации WSGI. Это приложение должно состоять из таких компонентов:

  • Интерфейс для callable.
  • Точка входа должна в качестве параметра содержать словарь, в котором хранятся переменные в виде пар «ключ-значение», и точку входа сервера uWSGI.
  • Точка входа должна возвращать итератор, что сгенерирует тело для отправки клиенту.
  • Приложение должно вызывать точку входа веб-сервера с состоянием 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, потому функция названа именно так. Как видите, она берёт два параметра.

Первый параметр называется environ и задаёт словарь переменных. Второй параметр называется start_response и сообщает точке входа веб-сервера uWSGI имя приложения.

Приложение будет выполнять два действия. Во-первых, оно вызовет точку входа, полученную с кодом состояния HTTP и заголовками. В таком случае отправляется ответ 200 ОК, а text/html получает заголовок Content-Type.

Во-вторых, приложение будет возвращать итератор в качестве тела запроса. В данном приложении используется одна строка HTML. Строки тоже относятся к итератору, но в списке uWSGI может обрабатывать целую строку при помощи одного итератора.

Такой файл, скорее всего, будет использоваться как ссылка на остальной код приложения. к примеру, Django-проекты включают файл wsgi.py по умолчанию. Он переводит запросы веб-сервера uWSGI в понятный приложению формат. Упрощенный интерфейс WSGI остаётся таким независимо от сложности самого кода приложения.

Сохраните и закройте файл.

Чтобы протестировать код, запустите uWSGI. Сервер будет использовать HTTP и прослушивать порт 8080. Передайте серверу название сценария:

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

Теперь посетите в браузере IP-адрес или доменное имя, задав порт 8080. На экране появится фраза:

Hello There!

Остановите сервер, нажав CTRL-C.

Теперь приложение готово. Отключите виртуальную среду:

deactivate

Конфигурационный файл uWSGI

В вышеприведённом примере вы вручную запустили сервер uWSGI и передали ему несколько параметров. Чтобы не делать это вручную всегда, создайте конфигурационный файл.

uWSGI может читать конфигурации в разных форматах; в руководстве для простоты используется формат .ini. Создайте файл myapp.ini:

nano ~/myapp/myapp.ini

В этом файле нужно создать раздел кода [uwsgi]. В нём будут храниться все конфигурации. Задайте настройки самого приложения. Сервер uWSGI должен знать о местонахождении точки входа приложения.

[uwsgi] module = wsgi:application

Начальный процесс uwsgi должен быть ведущим (master) и порождать множество рабочих процессов (в данном примере 5).

[uwsgi] module = wsgi:application
master = true
processes = 5

Теперь нужно изменить протокол, с помощью которого uWSGI взаимодействует с другими компонентами. Во время тестирования был установлен протокол –protocol=http, чтобы приложение можно было просмотреть в браузере. Однако в в дальнейшем будет настроен обратный прокси-сервер Nginx, который реализует механизм проксирования uwsgi (быстрый бинарный протокол, с помощью которого uWSGI взаимодействует с другими серверами). Протокол uwsgi является протоколом uWSGI по умолчанию, потому достаточно просто не задавать протокол, чтобы сервер использовал uwsgi.

Поскольку этот конфигурационный файл должен поддерживать взаимодействие с Nginx, замените стандартный порт сокетом Unix. Это более быстрый и безопасный вариант. Сокет будет создан в текущем каталоге (в руководстве он будет называться myapp.sock). Измените права доступа к нему, указав 664, чтобы веб-сервер Nginx имел право на редактирование. Добавьте опцию vacuum, которая удалит сокет сразу после остановки процесса:

[uwsgi] module = wsgi:application
master = true
processes = 5
socket = myapp.sock
chmod-socket = 664
vacuum = true

Осталось добавить последнюю опцию, которая нужна для поддержки файла Upstart. Upstart и uWSGI по-разному воспринимают сигнал SIGTERM. Чтобы устранить эту проблему, просто добавьте опцию die-on-term.

[uwsgi] module = wsgi:application
master = true
processes = 5
socket = myapp.sock
chmod-socket = 664
vacuum = true
die-on-term = true

Сохраните и закройте файл.

Создание файла Upstart

Теперь можно настроить автозапуск uWSGI во время загрузки сервера. Поместите его в каталог /etc/init, который проверяет система Upstart (в руководстве файл называется 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]

Теперь установите пользователя и группу, с помощью которых будет запущен процесс. В качестве группы можно указать www-data, чтобы сервер Nginx имел доступ к приложению.

description "uWSGI instance to serve myapp"
start on runlevel [2345] stop on runlevel [!2345] setuid demo
setgid www-data

После этого нужно добавить команды для запуска uWSGI. Вы можете предоставить полный путь к uWSGI, а можете включить виртуальную среду.

После этого добавьте блок script. В нем можно открыть каталог приложения, включить виртуальную среду (вместо символа . используйте source) и запустите uWSGI с помощью файла .ini.

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

Сценарий готов. Сохраните и закройте его.

Запустите сервис:

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 очень проста. Нужно только создать новый файл в каталоге sites-available в иерархии Nginx (имя файла должно совпадать с именем приложения, потому в руководстве файл называется myapp).

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

В этом файле нужно задать номер порта и доменное имя, к которому относится данный блок server. В данном случае используется стандартный порт 80.

server {
listen 80;
server_name server_domain_or_IP;
}

Чтобы приложение WSGI могло отправлять все запросы на этот домен или IP, нужно создать блок location для запросов, которые начинаются с / (это соответствует всем запросам). Добавьте в него директиву include, чтобы внести ряд параметров по умолчанию из конфигурационного каталога Nginx. Этот файл называется uwsgi_params. После этого нужно передать трафик приложению uWSGI через протокол uwsgi. Для этого используется сокет unix.

server {
listen 80;
server_name server_domain_or_IP;
location / {
include         uwsgi_params;
uwsgi_pass      unix:/home/demo/myapp/myapp.sock;
}
}

Этих настроек достаточно для поддержки простого приложения. Сложным приложениям нужна более тонкая настройка (например, можно определить количество upstream-серверов 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

После этого откройте в браузере доменное имя или IP (без номера порта). На экране появится:

Hello There!

Заключение

Теперь у вас есть полностью рабочее простое приложение WSGI. Его можно использовать как шаблон для создания более сложного приложения.

uWSGI может управлять несколькими приложениями, для этого используется так называемый «emperor mode». Вы можете расширить настройки Nginx, добавив балансировку нагрузки. Все компоненты достаточно гибкие, их можно настроить согласно требованиям вашего приложения.

Tags: , , , , , ,

1 комментарий

Добавить комментарий