Запуск приложения на Flask с помощью uwsgi + nginx в Debian 7

Данная статья описывает настройку связки uwsgi и nginx для обслуживания сайта созданного с применением фреймворка Flask. При этом статья писалась для вполне конкретной ситуации: Установка Flask и Python 3.3 в Debian 7. То есть в Debian 7.2 мы имеем вручную установленный из исходников python 3.3, на основе которого создано виртуальное окружение.

Приложение на Flask

В качестве тестового приложения будем использовать код из руководства по Flask:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(
)

Установка и настройка Nginx

Начнем с nginx, так как его настройка оказалась тривиальной. Устанавливаем:

aptitude install nginx

Создаем конфиг:

nano /etc/nginx/sites-available/site

Со следующим содержимым:

server {
    listen       80;
    server_name  domain.tld;

    location / { try_files $uri @app; }
    location @app {
        uwsgi_pass 127.0.0.1:4242;
        include uwsgi_params;
    }
}

Где domain.tld - доменное имя сайта, app - имя вашего приложения в файле с кодом на Flask, 127.0.0.1:4242 - адрес и порт на котором слушает uwsgi. Можно также настроить на общение через сокет, но в интернете есть информация, что с данным способом могут быть некоторые проблемы.

Затем линкуем его в директорию /etc/nginx/sites-enabled:

ln -s /etc/nginx/sites-available/dev /etc/nginx/sites-enabled/

И перезапускаем nginx:

/etc/init.d/nginx restart

Установка и настройка uwsgi

Устанавливаем uwsgi в уже настроенное виртуальное окружение:

cd /var/www/dev/
. venv/bin/activate
pip install uwsgi

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

nano /var/www/dev/site.ini

В который пишем:

[uwsgi]
gid = www-data
uid = www-data
socket=127.0.0.1:4242
pidfile=/var/run/uwsgi
virtualenv=/var/www/dev/venv/
chdir=/var/www/dev/
module=site
callable=app
pythonpath=/var/www/dev/venv/lib/python3.3/site-packages/
no-site=True
touch-reload=/var/www/dev/site.py
master = true
processes = 1
threads = 10
enable-threads = True
log-syslog = uwsgi-ligo

Где uid и gid задают пользователя и группу от которых будет работать uwsgi. В socket задаем адрес и порт, в virtualenv путь до директории в которой содержится виртуальное окружение, с помощью pidfile задаем путь до файла с номером процесса, параметр chdir указывает путь до директории с кодом сайта, module - название модуля, то есть имя файла в котором содержится приложение без .py. Далее в callable указываем вызываемое приложение взятое из строки app = Flask(__name__). 

pythonpath позволяет задать набор директорий в которых искать модули python. Таких строк может быть до 64. Определить данный путь удалось экспериментальным путем, он ведет в директорию, в которой установлен Flask. Путь начинается с пути до виртуального окружения, так как Flask был установлен конкретно в этом окружении.

no-site - данный параметр мешал нормальной работе в данной ситуации, как написано в официальной справке: если сомневаетесь, то лучше выключить. touch-reload - сообщает uwsgi перезапускаться в случае изменения указанного файла. Если задать значение master, то будет запущен один главный процесс, под которым будут запущены остальные, в количестве указанном в параметре processes. Параметр threads задает количество процессов, которые может запустить процесс. enable-threads - просто включаем поддержку процессов. log-syslog - здесь задаем имя под которым будут писаться логи в syslog.

Теперь запускаем uwsgi:

/var/www/dev/venv/bin/uwsgi --ini /var/www/dev/site.ini

И получаем ошибки в виде traceback о том, что не хватает такого-то модуля python. Проблема связана с тем, что при создании виртуального окружения не все модули линкуются в виртуальное окружение. То есть модули в виртуальном окружении являются символическими ссылками на модули в основной директории python. Останавливаем uwsgi с помощью Ctrl+C и линкуем все модули в виртуальное окружение:

cd /opt/python3.3/lib/python3.3
ls -l | awk '{print "/opt/python3.3/lib/python3.3/"$NF}' | xargs ln -s -f -t /var/www/dev/venv/lib/python3.3/

Вторая и третья строки - одна строка. Проверьте, что символические ссылки создались нормально.

Теперь можно запустить uwsgi в фоне:

/var/www/dev/venv/bin/uwsgi --ini /var/www/dev/site.ini &

На экране информацию о запуске вы не увидите, ее можно почерпнуть из лога /var/log/syslog. Нормальный вывод выглядит примерно так:

*** Starting uWSGI 1.9.19 (64bit) on [Fri Nov 15 18:48:55 2013] ***
compiled with version: 4.7.2 on 15 November 2013 01:35:20
os: Linux-3.2.0-4-amd64 #1 SMP Debian 3.2.51-1
nodename: VPS
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 4
current working directory: /var/www/dev
detected binary path: /var/www/dev/venv/bin/uwsgi
setgid() to 33
setuid() to 33
your processes number limit is 47806
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address 127.0.0.1:4242 fd 7
Python version: 3.3.2 (default, Nov  6 2013, 19:45:44)  [GCC 4.7.2]
Set PythonHome to /var/www/dev/venv/
Python main interpreter initialized at 0x2201150
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 331648 bytes (323 KB) for 10 cores
*** Operational MODE: threaded ***
added /var/www/dev/venv/lib/python3.3/site-packages/ to pythonpath.
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x2201150 pid: 24919 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 24919)
spawned uWSGI worker 1 (pid: 24922, cores: 10)

Чтобы перезапустить uwsgi достаточно изменить файл /var/www/dev/site.py или "прикоснуться" к нему:

touch /var/www/dev/site.py

Напрямую можно перезапустить послав сигнал HUP в master-процесс:

kill -HUP `cat /var/run/uwsgi`

Теперь остается сделать так, чтобы uwsgi мог запускаться вместе со стартом системы. Для этого используем supervisord.

Установка и настройка supervisord

Установка, как обычно:

aptitude install supervisor

Теперь создаем конфигурационный файл:

nano /etc/supervisor/conf.d/site.conf

со следующим содержимым:

[program:dev]
directory=/var/www/dev
command=/var/www/dev/venv/bin/uwsgi --ini /var/www/dev/site.ini
user=root
autostart=true
autorestart=true
stdout_logfile=/var/log/uwsgi.log
stderr_logfile = /var/log/uwsgi_err.log
redirect_stderr=true
stopsignal=INT

Dev в первой строке - это просто идентификатор, с помощью которого можно будет производить действия над заданной командой. directory - путь до директории в которой работает проект, command - собственно команда для запуска uwsgi.

user - в этой директиве пришлось указать root, иначе uwsgi не запускался.

Теперь запускать, останавливать или перезапускать uwsgi можно с помощью команд для supervisord. К примеру:

/etc/init.d/supervisord start

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

# supervisorctl
dev                              RUNNING    pid 615, uptime 0:00:12
supervisor> help

default commands (type help <topic>):
=====================================
add    clear  fg        open  quit    remove  restart   start   stop  update
avail  exit   maintail  pid   reload  reread  shutdown  status  tail  version

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

В общем-то и все.

Наверх

Опубликовано