Деплой flask с uwsgi и Nginx


Фреймворк Flask — очень распространенное решение для разработки веб-приложений на Python. В production используется обычно связка flask uwsgi Nginx.



Фреймворк Flask, настройка работы Flask uwsgi Nginx


Рассмотрим настройку сервера для приложения на Flask. Простой проект будем создавать с нуля.


Установим нужные пакеты

apt-get install python3-dev nginx python3-pip

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


pip3 install virtualenv


Скрипты разместим в отдельном каталоге

mkdir /home/todolist


Создаем одноименное окружение

virtualenv todolist


Оно будет представлять собой каталог todolist с определенной структурой внутри


Активируем окружение

source todolist/bin/activate

(todolist) root@server:/home/todolist#


Его имя теперь отображается в консоли. Можно устанавливать пакеты.



Создание простого приложения на фреймворке Flask


pip install uwsgi flask


Каталог /home/todolist будет домашним для непривелегированного пользователя, добавляем пользователя

useradd todo -m -d /home/todolist/ -s /bin/bash


Теперь само приложение. Слово Hi! крупным шрифтом серого цвета.

mcedit app.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:grey'>Hi!</h1>"

if __name__ == "__main__":
     app.run(host='0.0.0.0')

Его уже можно запустить вручную

python app.py

веб фреймворк Flask

Так запускать проект в production не стоит, поскольку процесс может быть в любой момент завершен — например, OOM.


Для автоматического перезапуска используется wsgi. Создаем конфигурационный файл.

mcedit wsgi.py

from app import app

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

Из существующего скрипта app.py импортируется функция app.



Приложение можно вновь запустить вручную, в этот раз уже через uwsgi

uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

Здесь указан TCP сокет, протокол, конфигурационный файл (wsgi) и функция в нем (app). Протокол — http. Он используется с TCP сокетом. По умолчанию задействуется протокол uWSGI.



Убедившись в том, что то же содержимое выводится — деактивируем окружение.

deactivate



Добавляем конфигурационный файл с настройками uwsgi

mcedit todo.ini

[uwsgi]
module = wsgi:app
master = true
processes = 5
socket = todo.sock
chmod-socket = 660
vacuum = true
die-on-term = true

Протокол в production будем исспользовать uWSGI (при ручном запуске был http). uWSGI — более быстрое и безопасное решение, он по умолчанию поддерживается Nginx.


HTTP следует выбирать только когда Nginx и uwsgi работают на разных машинах. При такой ситуации был бы указан socket 0.0.0.0:5000, protocol=http

Отказоустойчивости и автоматического запуска процесса пока нет. Для него потребуется конфигурационный файл init / upstart / systemd



В Ubuntu 18 и более современных дистрибутивах используется systemd, убеждаемся в этом

file /sbin/init

/sbin/init: symbolic link to /lib/systemd/systemd


 

Создаем Unit файл Systemd


mcedit /etc/systemd/system/todo.service

[Unit]
Description=uWSGI instance to serve todolist
After=network.target
[Service]
User=todo
Group=www-data
WorkingDirectory=/home/todolist
Environment="PATH=/home/todolist/todolist/bin"
ExecStart=/home/todolist/todolist/bin/uwsgi --ini todo.ini
[Install]
WantedBy=multi-user.target

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

systemctl start todo


Сейчас уже через uwsgi приложение должно работать на UNIX сокете

systemctl status todo

[…skipped…]

Active: active (running)

[…skipped…]


Проверяем наличие сокета

ss -l | grep todo

u_str LISTEN 0 100 todo.sock 1210456 * 0



Конфигурация Nginx для Flask с uwsgi


Последний шаг — настройка проксирования запросов на создаваемый сокет. В Nginx задается имя сайта или IP адрес, порт (обычно 80). Также путь к сокету. Это может быть и TCP сокет.


mcedit /etc/nginx/sites-enabled/todo

server {
listen 80;
server_name todo.example.com;

location / {
include uwsgi_params;
uwsgi_pass unix:/home/todolist/todo.sock;
}

}


Виртуальный хост нужно активировать

ln -s /etc/nginx/sites-availible/todo /etc/nginx/sites-enabled/


Затем проверяем конфигурацию и перезапускаем Nginx

nginx -t

nginx -s reload


Служба должна работать на порту 80

netstat -nltp | grep 80

tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 29624/nginx: master



Устанавливаем нужного владельца на файлы приложения

chown todo -R /home/todolist/


Перезапускаем uwsgi сервис

systemctl restart todo


Настройки на этом завершены. Если возникает 502 ошибка — нужно проверить логи Nginx

tail /var/log/nginx/error.log


Если есть необходимость изменять Unit файл — всегда нужно перезапускать демон Systemd

systemctl daemon-reload



Деплой готового приложения


Для того чтобы развернуть настоящее приложение достаточно переименовать файл app.py

mv app.py app.py_example


В каталоге с проектом выполнить

git clone https://github.com/YOUR-REPO/task-runner-py.git


И перезапустить

systemctl restart todo



Если основной файл называется app.py и в нем присутствует одноименная функция — других настроек не требуется.

flask uwsgi Nginx

В результате получится работающее в production приложение. Оно устойчиво к любым нештатным ситуациям: OOM-ам, закончившемуся месту на диске и будет автоматически перезапускаться при аварийном завершении процесса.



Если проект переносится с другого сервера помимо установки uwsgi и flask потребуется поставить все, что указано в requirements.txt

Сказать спасибо