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

Вступление

Цель данной статьи – помочь установить и настроить все необходимые для развертывания приложения компоненты.  Для начала нужно ознакомиться с особенностями HTTP-сервера Gunicorn WSGI, а затем научиться разворачивать веб-приложение Python WSGI, разработанное на основе различных фреймворков.

Примечание: чтобы получить информацию о других веб-серверах Python WSGI, читайте статью «Сравнение веб-серверов приложений на основе Python»

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

Gunicorn

Gunicorn – автономный веб-сервер с обширной функциональностью, предоставленной в удобном виде. Он изначально поддерживает различные фреймворки и адаптеры, что делает его чрезвычайно простой в использовании прямой заменой для многих серверов разработки.

Технически Gunicorn работает подобно Unicorn, популярному веб-серверу приложений Ruby. Они оба используют так называемую pre-fork модель (это значит, что главный процесс управляет инициированными рабочими процессами различного типа, создает сокеты и соединения, и т.п.).

Особенности сервера Gunicorn

  • Запускает любое приложение (и фреймворк) WSGI Python.
  • Служит заменой серверам Paster/Pyramid (сервер разработки Django), web2py и т.п.
  • Поставляется с различными конфигурациями и типами процессов.
  • Автоматически управляет процессами.
  • Поддерживает HTTP/1.0 и HTTP/1.1 с помощью синхронных и асинхронных процессов.
  • Поддерживает SSL.
  • Расширяется с помощью специальных точек входа.
  • Поддерживает Python 2.6+ и 3.x.

Развертывание веб-приложения с помощью Nginx

Nginx – это веб-сервер/инвертированный прокси очень высокой производительности.

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

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

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

Почему именно Nginx? Многие фреймворки и серверы приложений (в том числе и Gunicorn) могут обслуживать статические файлы (например, 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

Примечание: чтобы узнать необходимое количество серверов/процессов, читайте раздел «Настройка и оптимизация Gunicorn».

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

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

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

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

Примечание: здесь приведены краткие инструкции. Более подробную информацию можно получить, прочитав статью «Общие инструменты 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 2.7.6 и 3.3.3 на CentOS 6.4 и 5.8, прочтите данную статью.

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

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

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

Для установки python-dev запустите:

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
|..
|.

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

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

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

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

pip install gunicorn

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

Нижеприведенные инструкции недействительны для системы 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 (Precise Pangolin)».

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

Данный раздел демонстрирует работу WSGI-приложений с Gunicorn. Этот процесс состоит из предоставления серверу callable объекта WSGI-приложения (например, application = (..)) как точки входа.

WSGI

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

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

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

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

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

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

Конечно, вместо имени «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
|..
|.

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

Чтобы приложение обслуживалось, выполните:

gunicorn [опция] [опция2] .. [файл wsgi]

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

gunicorn -b 0.0.0.0:8080 wsgi

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

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

gunicorn -b 0.0.0.0:8080 wsgi &

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

Настройка и оптимизация Gunicorn

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

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

[!] Важно: Все перечисленные ниже настройки и параметры конфигураций необходимо «сцепить» (внести один за другим), чтобы запустить gunicorn и обслуживать приложение. После запуска сервера изменять настройки нельзя. Любая использованная опция должна сопровождаться файлом WSGI, содержащим точку входа в приложение.

Пример:

# Чтобы просто запустить сервер (как показано выше):
gunicorn -b 0.0.0.0:8080 wsgi
# Запустить сервер и 5 процессов:
gunicorn -b 0.0.0.0:8080 --workers=5 wsgi

Подсчет процессов

В целом, считается, что приложения зависят скорее от I/O, чем от CPU. Это значит, что узкое место вызвано не вычислительной мощностью виртуального сервера, а диском. Идея такова: пока один процесс занят дисковыми операциями, другой все еще использует CPU для обработки запросов.

Потому рекомендуемое количество процессов, как правило, вычисляется по следующей формуле:

# (2 Workers * CPU Cores) + 1
# ---------------------------
# For 1 core  -> (2*1)+1 = 3
# For 2 cores -> (2*2)+1 = 5
# For 4 cores -> (2*4)+1 = 9

Указать количество процессов можно с помощью аргумента –workers=[n].

# Синтаксис: gunicorn --workers=[количество_процессов] # Пример: gunicorn --workers=5

Примечание: такой сценарий не сработает с неблокируемыми процессами.

Настройки сокетов

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

# Синтаксис: gunicorn -b [адрес:порт] # Пример: gunicorn -b 127.0.0.1:8080

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

Выбор типа процесса

Как уже было сказано, Gunicorn предоставляет возможность использовать разные типы процессов.

В большинстве случаев используется sync – стандартный процесс, установленный по умолчанию и, следовательно, не требующий подробной настройки.

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

# Синтаксис: gunicorn -k [процесс] # Пример: gunicorn -k sync
# или: gunicorn -k gevent

Доступные типы процессов:

  • sync
  • eventlet
  • gevent
  • tornado

Количество одновременных подключений для процессов Eventlet / Gevent

Чтобы изменить количество одновременных подключений для процессов Eventlet и Gevent:

# Синтаксис: gunicorn -k [процесс] --worker-connections [количество] # Пример: gunicorn -k gevent --worker-connections 1001

Журналы доступа

Чтобы явно определить файл для ведения журнала доступа:

# Синтаксис: gunicorn --log-file [файл] # Пример: gunicorn --log-file error_logs.log

По умолчанию данная опция имеет значение None.

Журналы ошибок

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

# Синтаксис: gunicorn --access-logfile [файл] # Пример: gunicorn --access-logfile acclogs

Уровни журналов

Это необходимо для повышения степени детализации результата, выведенного журналами ошибок. Доступные уровни:

  • debug
  • info
  • warning
  • error
  • critical

# Синтаксис: gunicorn --log-level [уровень] # Пример: gunicorn --log-level error

Наименование процессов

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

# Синтаксис: gunicorn --name [имя] # Пример: gunicorn --name my_application

Настройка Nginx

Настроив и запустив Gunicorn, нужно настроить Nginx, чтобы он мог взаимодействовать с сервером Gunicorn при запуске приложения. Для этого нужно отредактировать 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 app_servers {
server 127.0.0.1:8080;
# server 127.0.0.1:8081;
# ..
# .
}
# Configuration for Nginx
server {
# Running port
listen 80;
# Settings to serve static files
location ^~ /static/  {
# Example:
# root /full/path/to/application/static/file/dir;
root /app/static/;
}
# Serve a static file (ex. favico)
# outside /static directory
location = /favico.ico  {
root /app/favico.ico;
}
# Proxy connections to the application servers
# app_servers
location / {
proxy_pass         http://app_servers;
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

Готово!

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

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