воскресенье, 30 июня 2013 г.

Настройка приложения Flask в режиме FastCGI

Перевод статьи: FastCGI

FastCGI - это один из вариантов развёртывания приложения на серверах nginx, lighttpd и cherokee; за описанием других опций обратитесь к разделам uWSGI и Самостоятельные контейнеры WSGI. Для использования приложения WSGI с любым из этих серверов необходимо сначала настроить сервер FastCGI. Наиболее популярен flup, который будет использоваться в этом руководстве. Убедитесь в том, что установили его, прежде чем продолжить чтение.

Предварительная проверка

Удостоверьтесь, что вызовы app.run() в файле приложения находятся внутри блока if __name__ == '__main__': или вынесены в отдельный файл. Просто убедитесь в отсутствии подобных вызовов, потому что если вы решили воспользоваться FastCGI для запуска приложения, то запускать локальный сервер WSGI не нужно.

Создание файла .fcgi

Для начала нужно создать файл сервера FastCGI. Давайте назовём его yourapplication.fcgi:
#!/usr/bin/python
from flup.server.fcgi import WSGIServer
from yourapplication import app
if __name__ == '__main__':
    WSGIServer(app).run()
Этого достаточно для работы Apache, однако nginx и старые версии lighttpd требуют явного указания сокетов для связи с сервером FastCGI. Для этого нужно передать путь к сокет-файлу в WSGIServer:
WSGIServer(application, bindAddress='/path/to/fcgi.sock').run()
Этот путь должен быть точно таким же, какой был указан в настройках сервера.

Сохраните файл yourapplication.fcgi где-нибудь, где вы сможете потом найти его. Неплохо положить его в /var/www/yourapplication или в какое-то другое подходящее место.

Убедитесь, что у этого файла установлен флаг выполнения, чтобы сервер мог его выполнить:
# chmod +x /var/www/yourapplication/yourapplication.fcgi
Настройка Apache

Приведённый выше пример достаточно хорош для того, чтобы использовать его при развёртывании с Apache, однако файл .fcgi будет встречаться в URL приложения, например: example.com/yourapplication.fcgi/news/. Есть несколько способов настройки приложения для того, чтобы убрать yourapplication.fcgi из URL. Предпочтительный способ - это использование директивы ScriptAlias:
<VirtualHost *>
  ServerName example.com
  ScriptAlias / /path/to/yourapplication.fcgi/
</VirtualHost>
Если задать ScriptAlias нельзя, например на веб-узле, настроенном для нескольких пользователей, то можно воспользоваться промежуточным приложением WSGI для удаления yourapplication.fcgi из URL. Настройте .htaccess:
<IfModule mod_fcgid.c>
  AddHandler fcgid-script .fcgi
  <Files ~ (\.fcgi)>
    SetHandler fcgid-script
    Options +FollowSymLinks +ExecCGI
  </Files>
</IfModule>

<IfModule mod_rewrite.c>
  Options +FollowSymlinks
  RewriteEngine On
  RewriteBase /
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ yourapplication.fcgi/$1 [QSA,L]
</IfModule>
Теперь настроим yourapplication.fcgi:
#!/usr/bin/python
#: не обязательный путь к каталогу с локальными пакетами python
import sys

sys.path.insert(0, '<локальный_путь>/lib/python2.6/site-packages')

from flup.server.fcgi import WSGIServer
from yourapplication import app

class ScriptNameStripper(object):
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        environ['SCRIPT_NAME'] = ''
        return self.app(environ, start_response)

app = ScriptNameStripper(app)

if __name__ == '__main__':
    WSGIServer(app).run()
Настройка lighttpd

Базовая настройка FastCGI для lighttpd выглядит следующим образом:
fastcgi.server = ("/yourapplication.fcgi" =>
  ((
    "socket" => "/tmp/yourapplication-fcgi.sock",
    "bin-path" => "/var/www/yourapplication/yourapplication.fcgi",
    "check-local" => "disable",
    "max-procs" => 1
  ))
)

alias.url = (
  "/static/" => "/path/to/your/static"
)

url.rewrite-once = (
  "^(/static($|/.*))$" => "$1",
  "^(/.*)$" => "/yourapplication.fcgi$1"
Не забудьте включить модули FastCGI, alias и rewrite. Эта настройка закрепит приложение за /yourapplication. Если нужно, чтобы приложение работало в корне URL, понадобится обойти недоработку lighttpd при помощи промежуточного приложения LighttpdCGIRootFix.

Убедитесь, что применяете его лишь в том случае, если подключили приложение к корню URL. А также, обратитесь к документации Lighttpd за более подробной информацией о FastCGI и Python (отметим, что явная передача сокет-файла в run() больше не требуется).

Настройка nginx

Установка приложений FastCGI в nginx немного отличается, потому что по умолчанию программе не передаются параметры FastCGI.

Базовая конфигурация FastCGI nginx для flask выглядит следующим образом:
location = /yourapplication { rewrite ^ /yourapplication/ last; }
location /yourapplication { try_files $uri @yourapplication; }
location @yourapplication {
  include fastcgi_params;
  fastcgi_split_path_info ^(/yourapplication)(.*)$;
  fastcgi_param PATH_INFO $fastcgi_path_info;
  fastcgi_param SCRIPT_NAME $fastcgi_script_name;
  fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}
Эта конфигурация привязывает приложение к /yourapplication. Привязать приложение к корню URL несколько проще, потому что не нужно думать о том, какие значения использовать в PATH_INFO и SCRIPT_NAME:
location / { try_files $uri @yourapplication; }
location @yourapplication {
  include fastcgi_params;
  fastcgi_param PATH_INFO $fastcgi_script_name;
  fastcgi_param SCRIPT_NAME "";
  fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}
Запуск процессов FastCGI

Поскольку Nginx и другие серверы не загружают приложения FastCGI, это нужно сделать самостоятельно. Процессами FastCGI может управлять программа Supervisor. Можно поискать другие диспетчеры процессов FastCGI или написать сценарий для запуска файла .fcgi во время загрузки, например, с помощью сценария SysV init.d. В качестве временного решения может подойти запуск сценария .fcgi из программы GNU screen. Обратитесь к странице руководства screen за более подробной информацией, однако стоит заметить, что после перезагрузки системы запуск придётся повторять вручную:
$ screen
$ /var/www/yourapplication/yourapplication.fcgi
Отладка

На большинстве веб-серверов становится всё труднее отлаживать приложения FastCGI. Довольно часто единственное, о чём сообщают журналы сервера, - это о неожиданном окончании заголовков. Для отладки приложения единственное подходящее средство диагностики - это переключиться на нужного пользователя и запустить приложение вручную.

В следующем примере предполагается, что приложение называется application.fcgi, а веб-сервер работает от имени пользователя www-data:
$ su www-data
$ cd /var/www/yourapplication
$ python application.fcgi
Traceback (most recent call last):
File "yourapplication.fcgi", line 4, in <module>
ImportError: No module named yourapplication
В данном случае ошибка вызвана тем, что yourapplication не найден в путях поиска python. Обычно это происходит по одной из следующих причин:
  • Указаны относительные пути, которые не работают относительно текущего каталога.
  • Выполнение программы зависит от переменных окружения, которые не заданы для веб-сервера.
  • Используется интерпретатор python другой версии.
Примечания переводчика

В случае настройки Lighttpd не нужно писать никаких сценариев SysV init.d, потому что:

1. Lighttpd может сам управлять FastCGI-процессами на локальном компьютере, самостоятельно порождая необходимое их количество (с учётом настроенного лимита),

2. в рамках проекта Lighttpd разрабатывается собственный диспетчер процессов FastCGI - spawn-fcgi, который не настолько продвинут, чтобы регулировать количество необходимых процессов, но по крайней мере указанное количество процессов запустить и поддерживать сможет.

Обычно spawn-fcgi применяется в тех случаях, когда приложение FastCGI работает на отдельном от веб-сервера компьютере или нужно запустить приложение от имени другого пользователя, например, для изоляции друг от друга приложений разных пользователей, работающих на одном сервере. Например, так: Настройка FastCGI и PHP с индивидуальными правами пользователей.

И, наконец, никто не мешает использовать spawn-fcgi совместно с nginx.

Этот и другие переводы можно найти на сайте проекта перевода документации по Flask. Автор проекта - Виталий Кузьмин aka ferm32.

Комментариев нет: