Развертывание приложения Python WSGI с помощью uWSGI+Nginx

Вступление

Как говорится в статье «Сравнение веб-серверов приложений на основе Python», uWSGI является масштабным проектом, который способен не только обслуживать приложения, но и выполнять намного более сложные задания. Широкий спектр функциональных возможностей в сочетании с относительной легкостью настройки делают uWSGI отличным вариантом для развертывания многих приложений, особенно в сочетании с Nginx.

Данная статья подробно рассматривает uWSGI, а также охватывает все действия, которые необходимо выполнить для установки сервера и развертывания приложений Python (как маленьких, так и масштабных) на основе различных фреймворков.

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

Что такое uWSGI и Nginx?

uWSGI является амбициозным проектом. Его набор инструментов позволяет выполнять гораздо более сложные задания, чем просто хостинг веб-приложений. Зарекомендовав себя как надежный и многофункциональный проект, на протяжении многих лет uWSGI остается незаменимым инструментом развертывания приложений для многих системных администраторов и разработчиков.

Начиная с версии 0.8.40, Nginx поддерживает протокол uwsgi (собственный протокол uWSGI). Это позволяет приложениям WSGI, запущенным на uWSGI, лучше взаимодействовать с Nginx. Благодаря этому развертывание приложений становится очень простым в настройке, чрезвычайно гибким, функциональным, а также может пользоваться преимуществами поставляемых оптимизаций. Все это делает сочетание uWSGI+Nginx великолепным вариантом для многих сценариев развертывания.

Кратко о uWSGI

Ниже приведен отрывок из статьи «Сравнение веб-серверов приложений на основе Python»:

Несмотря на очень запутанное соглашение об именах, сам uWSGI является обширным проектом, который состоит из большого количества компонентов, которые предоставляют полный набор программного обеспечения для построения хостинговых услуг. Один из этих компонентов, сервер uWSGI, запускает приложения Python WSGI. Он может использовать различные протоколы, в том числе и собственный протокол uwsgi, идентичный SCGI. Поскольку автономные HTTP-серверы по сравнению с серверами приложений более популярны, веб-серверы NGINX и Cherokee разработаны как модульные, что позволяет uWSGI использовать собственный протокол с высокой производительностью и обеспечивает прямой контроль над процессами.

Особенности uWSGI

  • Поставляется с адаптером WSGI и полностью поддерживает приложения Python на WSGI.
  • Связан с libpython. Он загружает код приложения при запуске и действует как интерпретатор Python, а также анализирует входящие запросы и вызывает Python.
  • Поставляется с прямой поддержкой популярного веб-сервера NGINX (а также Cherokee и Lighttpd).
  • Написан на языке C.
  • Различные компоненты могут сделать гораздо больше, чем просто запуск приложения, что может быть полезно для расширения функций.
  • В настоящее время (по состоянию на конец 2013 года), uWSGI активно развивается, регулярно появляются новые версии.
  • Имеет различные механизмы для запуска приложений (асинхронного и синхронного).
  • Невысокое потребление памяти при запуске.
  • Развертывание приложений на Nginx
  • Nginx – это веб-сервер/инвертированный прокси очень высокой производительности.

Он стал популярен потому, что он относительно легок в использовании, мало весит и легко расширяется (с помощью дополнений и плагинов). Благодаря своей архитектуре он способен обрабатывать множество запросов (практически без ограничений), с которыми более старые альтернативы справляются с трудом (в зависимости от загрузки приложения или веб-сайта).

Запомните: технически обработка соединения означает, что соединение не только установлено, но и постоянно обслуживается. То есть, приложение и база данных должны правильно работать, чтобы Nginx мог обслуживать ответы клиентов, не выводя сообщений об ошибках.

Nginx как инвертированный прокси +uWSGI

Многие фреймворки и серверы приложений могут обслуживать статические файлы (например, JavaScript, CSS, изображения и т.д.) вместе с ответами от приложений. Тем не менее, лучше установить инвертированный прокси-сервер (как Nginx), который будет обслуживать эти файлы и управлять соединениями (запросами). Это существенно снизит нагрузку на сервер приложений, тем самым улучшая общую производительность.

По мере роста приложения появится необходимость его оптимизации и распределения на несколько серверов (VPS), чтобы иметь возможность обрабатывать больше соединений одновременно (и обеспечить более надежную архитектуру в целом). Инвертированный прокси-сервер выполняет все это с самого начала.

Расширяемость Nginx (то есть, кэширование наряду с отказоустойчивостью и другими механизмами) – еще одно огромное преимущество этого сервера перед более простыми серверами приложений.

Пример базовой архитектуры сервера:

Client Request ----> Nginx (Reverse-Proxy)
________________________|
_______________________/|\
______________________| | `-> App. Server I. 127.0.0.1:8081
______________________| `--> App. Server II. 127.0.0.1:8082
_______________________`----> App. Server III. 127.0.0.1:8083

Примечание: когда приложение прослушивает входящие соединения на 127.0.0.1, доступ к нему можно получить только локально. При использовании 0.0.0.0, оно также будет принимать соединения извне.

Подготовка сервера к производству

Данный раздел посвящен подготовке виртуального сервера к производству (то есть, к развертыванию приложения).

Для начала нужно:

  • Обновить операционную систему по умолчанию;
  • Скачать и установить общие инструменты Python (pip и virtualenv);
  • Создать виртуальную среду, которая будет содержать приложение, а также его зависимости (uWSGI).

Примечание: здесь приведены краткие инструкции. Более подробную информацию можно получить, прочитав статью «Общие инструменты Python: использование virtualenv, установка пакетов с помощью pip и управление пакетами».

Обновление операционной системы

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

Итак, чтобы обеспечить использование последней доступной версии необходимых приложений, необходимо обновить систему. Для обновления систем на основе Debian (Ubuntu, Debian):

aptitude    update
aptitude -y upgrade

Для обновления систем на основе RHEL (CentOS):

yum -y update

Установка Python, pip и virtualenv

Примечание для пользователей CentOS / RHEL

По умолчанию CentOS / RHEL поставляются почти чистыми. Набор инструментов на данном сервере предоставляется не для запуска приложений пользователя, а для питания инструментов системы (например, yum).

Чтобы подготовить систему CentOS, нужно установить (то есть, скомпилировать из исходного кода) Python, а затем установить pip и virtualenv при помощи специального интерпретатора Python.

Чтобы получить подробную информацию по установке Python 2.7.6 и 3.3.3 на CentOS 6.4 и 5.8, прочтите данную статью.

На Ubuntu и Debian последняя версия интерпретатора Python (который можно использовать) поставляется по умолчанию. Потому все, что осталось установить:

  • python-dev – средства разработки
  • pip- для управления пакетами
  • virtualenv- для создания изолированной виртуальной среды

python-dev: общесистемный пакет, который содержит расширенные средства разработки для построения модулей Python

Для установки python-dev с помощью aptitude запустите:

aptitude install python-dev

pip: менеджер пакетов, который помогает устанавливать необходимые пакеты приложений.

Выполните следующие команды для установки pip:

curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py | python -
curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python -
export PATH="/usr/local/bin:$PATH"

На данном этапе могут понадобиться привилегии sudo.

Virtualenv:

Приложение Python вместе со всеми его зависимостями рекомендуется хранить в отдельной среде. Проще говоря, среда – это изолированное место (каталог) для размещения пакетов веб-приложения. Для этого используется инструмент под названием virtualenv.

Чтобы установить virtualenv с помощью pip, используйте:

sudo pip install virtualenv

Создание автономной виртуальной среды Python

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

Запомните: если на локальной машине разработки нет virtualenv (или виртуальной среды), необходимо создать ее и переместить туда приложение и его зависимости.

Для начала нужно создать папку, которая будет содержать виртуальную среду и модуль приложения:

mkdir my_app

Конечно, папку можно назвать согласно требованиям разработчика или проекта.

Затем нужно войти в эту папку и создать в ней новую виртуальную среду:

cd my_app
virtualenv my_app_venv

Виртуальную среду также можно назвать как угодно.

Теперь создайте новую папку для модуля приложения Python:

mkdir app

Активируйте интерпретатор внутри виртуальной среды:

source my_app_venv/bin/activate

Пожалуйста, убедитесь в том, что заменили имя виртуальной среды «my_app_venv» именем своей venv (в случае, если она имеет другое имя).

Теперь главный каталог развертывания приложений должен выглядеть так:

my_app              # Main Folder to Contain Everything Together
|
|=== my_app_venv  # V. Env. folder with the Python Int.
|=== app          # Your application module
|..
|.

Загрузка и установка uWSGI

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

В случае, если виртуальная среда дезактивирована, uWSGI будет установлен общесистемно (глобально), чего делать не рекомендуется.

Чтобы установить uWSGI с помощью pip, запустите:

pip install uwsgi

Примечание: чтобы узнать об инструменте pip больше, читайте статью «Общие инструменты Python: использование virtualenv, установка пакетов с помощью pip и управление пакетами».

Загрузка и установка Nginx

Примечание для пользователей CentOS / RHEL

Приведенные ниже инструкции недействительны для системы CentOS. При необходимости, пожалуйста, обратитесь к руководству «Как установить nginx на CentOS 6 с помощью yum».

Запустите следующую команду, чтобы установить Nginx с помощью aptitude, менеджера пакетов по умолчанию:

sudo aptitude install nginx

Чтобы запустить Nginx, используйте:

sudo service nginx start

Чтобы выключить Nginx, запустите:

sudo service nginx stop

Чтобы перезапустить Nginx:

sudo service nginx restart

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

Чтобы получить дополнительные инструкции по установке Nginx на Ubuntu, читайте статью «Установка Nginx на Ubuntu 12.04 LTS».

Обслуживание приложений Python WSGI с помощью uWSGI

Данный раздел демонстрирует работу WSGI-приложений с uWSGI. В целом, обслуживание приложений Python WSGI с помощью uWSGI не имеет существенных отличий от этого процесса с использованием других контейнеров приложений. Как и другим серверам, uWSGI необходимо, чтобы приложение предоставило ему точку входа, так называемый callable объект. При запуске callable объект вместе с переменными конфигураций передаются uWSGI, и сервер начинает работать. При поступлении запроса uWSGI обрабатывает его и передает в контроллер приложения.

Архитектура:

........
_/|\
| | `-> App. Server I.   127.0.0.1:8080  <--> Application
|  `--> App. Server II.  127.0.0.1:8081  <--> Application
.....

WSGI

Очень упрощенно говоря, WSGI представляет собой интерфейс между веб-сервером и самим приложением. Он устанавливает стандартное соединение между различными серверами и приложениями (фреймворками), что обеспечивает их взаимозаменяемость в случае необходимости (например, переход от среды разработки к производственной среде), что очень важно в настоящее время.

Примечание: для получения дополнительной информации о WSGI и веб-серверах Python читайте статью “Сравнение веб-серверов для приложений на основе Python“.

Callable объект приложения WSGI: wsgi.py

Как уже было сказано, веб-серверам, запущенным на WSGI, необходим объект приложения.

Для большинства фреймворков и приложений данный объект приложения (или callable) находится в файле wsgi.py, который предоставляет его серверу.

Для начала создайте образец wsgi.py для использования его сервером uWSGI.

Конечно, вместо имени «wsgi.py» можно выбрать любое другое имя. Но имя wsgi.py считается стандартным и используется чаще всего (например, в Django).

Итак, можно приступить к созданию файла wsgi.py, который будет содержать базовое приложение WSGI.

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

nano wsgi.py

Теперь нужно переместить (скопировать и вставить) в него базовый код приложения WSGI (замените его собственным callable приложения):

def application(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ["Hello!"]

Каждый раз, когда поступает запрос, сервер использует этот callable приложения, чтобы запустить его обработчики запросов (контроллеры), анализируя URL (например, mysite.tld/controller/method/variable).

Разместив код приложения в файле, нажмите CTRL+X, чтобы сохранить файл в папке my_app наряду с виртуальной средой и модулем приложения (нажмите Y для подтверждения).

Примечание: данное WSGI-приложение является самым базовым примером. Необходимо заменить данный блок кода, чтобы внести свой собственный объект приложения.

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

my_app              # Main Folder to Contain Everything Together
|
|=== my_app_venv  # V. Env. folder with the Python Int.
|=== app          # Your application module
|
|--- wsgi.py      # File containing application callable
|..
|.

Запуск сервера

Гибкий сервер uWSGI обладает огромным количеством опций и конфигураций, что позволяет настроить его согласно требованиям пользователя или проекта. Чтобы не усложнять разработку с самого ее начала, рекомендуется установить простые конфигурации и усложнять их в ходе работы над приложением.

Простой пример использования:

uwsgi [опция] [опция 2] .. -w [файл с callable объектом]

Чтобы uWSGI начал обслуживать приложение файла wsgi.py, запустите

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

Это запустит сервер в приоритетном режиме. Чтобы отключить его, нажмите клавиши CTRL + C.

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

uwsgi --socket 127.0.0.1:8080 --protocol=http -w wsgi &

[!] Важно: используя настройки из раздела «Настройка Nginx», не забудьте удалить –protocol=http из цепи аргументов, иначе Nginx и uWSGI не смогут взаимодействовать.

Запуская приложение в фоновом режиме, используйте менеджер процессов (например, htop), чтобы прервать его.

Управление сервером uWSGI и его процессами с помощью сигналов

Существуют различные сигналы для управления сервером:

  • SIGHUP -HUP постепенно перезагружает процессы и приложения
  • SIGTERM -TERM сразу перезагружает процессы и приложения
  • SIGINT -INT и SIGQUIT -QUIT немедленно прерывает все процессы
  • SIGUSR1 -USR1 выводит статистику (stdout)
  • SIGUSR2 -USR2 выводит состояние процесса
  • SIGURG -URG состояние сокета
  • SIGTSTP -TSTP приостанавливает или возобновляет процесс
  • SIGWINCH -WINCH возобновляет процесс, заблокированный системным вызовом.

Перезапуск сервера с SIGHUP

Данный сигнал постепенно перезагружает процессы и приложения сервера. Это значит, что он ожидает, пока процесс выполнит текущую задачу, а затем прерывает его и запускает снова, сохраняя его параметры.

kill -HUP [PID]

Чтобы не указывать PID, используйте опцию pidfile, которая говорит uWSGI записывать данные в файл, который позже можно использовать для управления процессами.

 Остановка сервера с SIGINT

Чтобы остановить сервер и его процессы, нужно использовать сигнал –INT. Это прервет все в фоновом режиме:

kill -INT [PID]

Настройка Nginx

Настроив и запустив uWSGI, нужно настроить Nginx, чтобы он мог взаимодействовать с сервером uWSGI при запуске приложения. Для этого нужно отредактировать nginx.conf, конфигурационный файл Nginx.

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

sudo nano /etc/nginx/nginx.conf

Затем замените содержимое файла приведеными ниже конфигурациями, чтобы Nginx был запущен как инвертированный прокси и взаимодействовал с приложением.

Примечание: чтобы активировать поддрежку SSL, пожалуйста, прочтите статью «Создание SSL-сертификата на Nginx».

Пример конфигураций для веб-приложения:

worker_processes 1;
events {
worker_connections 1024;
}
http {
sendfile on;
gzip              on;
gzip_http_version 1.0;
gzip_proxied      any;
gzip_min_length   500;
gzip_disable      "MSIE [1-6]\.";
gzip_types        text/plain text/xml text/css
text/comma-separated-values
text/javascript
application/x-javascript
application/atom+xml;
# Configuration containing list of application servers
upstream uwsgicluster {
server 127.0.0.1:8080;
# server 127.0.0.1:8081;
# ..
# .
}
# Configuration for Nginx
server {
# Running port
listen 80;
# Settings to by-pass for static files
location ^~ /static/  {
# Example:
# root /full/path/to/application/static/file/dir;
root /app/static/;
}
# Serve a static file (ex. favico) outside static dir.
location = /favico.ico  {
root /app/favico.ico;
}
# Proxying connections to application servers
location / {
include            uwsgi_params;
uwsgi_pass         uwsgicluster;
proxy_redirect     off;
proxy_set_header   Host $host;
proxy_set_header   X-Real-IP $remote_addr;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header   X-Forwarded-Host $server_name;
}
}
}

Завершив редактирование конфигураций, нажмите CTRL+X, чтобы сохранить изменения и выйти, а затем Y для подтверждения.

Для перезапуска Nginx используйте:

sudo service nginx stop
sudo service nginx start

Настройка uWSGI

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

  • О передаче конфигураций как аргументов;
  • Об использовании для конфигурирования файлов .ini;
  • Об использовании файлов .json.

Примечание: uWSGI поддерживает различные протоколы и может извлекать конфигурации из этих файлов разными способами.

Вариант 1: передача конфигураций как аргументов

Итак, основной способ запустить uWSGI (как и любой другой скрипт оболочки) – это  предоставить ему необходимые конфигурации в качестве аргументов.

Пример использования:

# uwsgi [опция] [опция 2] .. -w [wsgi.py с callable объектом]

# Простой запуск сервера *wsgi*
uwsgi --socket 127.0.0.1:8080 -w wsgi

# Запуск приложений Pyramid (Paster)
uwsgi --ini-paste production.ini

# Запуск приложений web2py
uwsgi --pythonpath /path/to/app --module wsgihandler

# Запуск приложений WSGI с помощью имени модуля / callable объекта
uwsgi --module имя_модуля_wsgi --callable имя_callable_объекта_приложения
uwsgi -w имя_модуля_wsgi: имя_callable_объекта_приложения

Чтобы получить дополнительную информацию и примеры использования, читайте документацию.

Вариант 2: использование файлов .ini для конфигурирования

Другой (и, возможно, более удобный) способ предоставления серверу uWSGI конфигураций – использование файлов .ini. Такие файлы имеют простую структуру (см. пример ниже) и явно передаются при каждом выполнении скрипта запуска uWSGI.

Пример структуры файла .ini (example_config.ini)

[uwsgi] # -------------
# Settings:
# key = value
# Comments >> #
# -------------
# socket = [addr:port] socket = 127.0.0.1:8080
# Base application directory
# chdir = /full/path
chdir  = /my_app
# WSGI module and callable
# module = [wsgi_module_name]:[application_callable_name] module = app:application
# master = [master process (true of false)] master = true
# processes = [number of processes] processes = 5
..

Пример использования:

uwsgi --ini example_config.ini

Вариант 3: использование файлов .json для конфигурирования

В целом, файлы .json не отличаются от от описанных выше файлов ничем, кроме структуры.

Пример структуры файла .json (example_config.json)

{
"uwsgi": {
"socket": ["127.0.0.1:8080"],
"module": "my_app:app",
"master": true,
"processes": 5,
}
}

Пример использования:

uwsgi --json example_config.json

Чтобы подробно ознакомиться с настройкой uWSGI, читайте документацию по данной ссылке.

Общие конфигурации uWSGI

По умолчанию данный сервер разработан как независимый от используемых платформ фреймворк/приложение. Хотя этот сервер, вероятно, поддерживает абсолютно все, что может понадобиться, некоторые опции необходимо явно установить в соответствии с требованиями проекта.

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

Синтаксис, используемый в приведенных ниже примерах, рассчитан на файлы .ini. Их можно отредактировать относительно требований конкретного проекта (например, для приложений на основе файлов .json).

Sockets (Сокеты)

http-socket: привязывает uWSGI к определенному HTTP-сокету. Пример:

http-socket = :8080

socket: привязывает uWSGI к указанному сокету согласно протоколу по умолчанию. Пример:

socket = 127.0.0.1:8080

processes (workers): количество процессов, созданных для того, чтобы принимать запросы. Пример:

processes = 5

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

protocol = http

Management (Управление)

master: данная опция активирует/дезактивирует главный процесс uWSGI. Главные процессы нужны для управления остальными процессами, которые принимают и обрабатывают входящие запросы. Эта опция имеет множество преимуществ, в том числе и последовательный перезапуск процессов, не затрагивающий сокеты, что делает возможным обновления без простоев. Пример:

master = true

max-requests: эта опция автоматически перезапускает процессы после обработки заданного количества запросов,что позволяет бороться с утечками памяти. Пример:

max-requests = 1001

threads: эта опция запускает каждый процесс с указанным количеством потоков. Можно совместить эту опцию с опцией processes с целью скорректировать работу процессов. Пример:

threads = 2

Logging (Ведение журнала)

disable-logging: отключает функцию журналирования. Пример:

disable-logging = true

uWSGI processes (процессы uWSGI)

procname: позволяет установить имя процесса на свое усмотрение. Пример:

procname = My Application

uid: устанавливает идентификатор пользователя (uid) для пользвателя сервера uWSGI. Пример:

uid = 1001

gid: Позволяет установить gid для сервера uWSGI. Пример:

gid = 555

vacuum: удаляет все сгенерированные pidfiles/sockets при выходе.

daemonize: этот параметр записывает лог в определенное место. Пример:

daemonize = /tmp/uwsgi_daemonize.log

pidfile: говорит uWSGI записывать PID процесса в указанный здесь файл. Данный параметр очень полезен в управлении запуском процессов uWSGI. Пример:

pidfile = /tmp/proj_pid.pid

Другие параметры

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

harakiri = 30

Чтобы ознакомиться с остальными доступными параметрами, читайте их  полный список в официальной документации параметров конфигураций.

Tags: , , , , , , , , , , , , , , , ,

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