Деплой 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