Поиск по сайту:

Как обслуживать приложения Flask с помощью uWSGI и Nginx в Ubuntu 16.04


Введение

В этом руководстве мы настроим простое приложение Python с использованием микрофреймворка Flask в Ubuntu 16.04. Основная часть этой статьи будет посвящена настройке сервера приложений uWSGI для запуска приложения и Nginx для работы в качестве внешнего обратного прокси-сервера.

Предпосылки

Прежде чем приступить к работе с этим руководством, на вашем сервере должен быть настроен пользователь без полномочий root. Этот пользователь должен иметь привилегии sudo, чтобы он мог выполнять административные функции. Чтобы узнать, как это настроить, следуйте нашему руководству по начальной настройке сервера.

Чтобы узнать больше о uWSGI, нашем сервере приложений и спецификации WSGI, вы можете прочитать связанный раздел этого руководства. Понимание этих концепций облегчит понимание этого руководства.

Когда будете готовы продолжить, читайте дальше.

Установите компоненты из репозиториев Ubuntu

Нашим первым шагом будет установка всех необходимых нам частей из репозиториев. Мы установим pip, менеджер пакетов Python, чтобы установить и управлять нашими компонентами Python. Мы также получим файлы разработки Python, необходимые для сборки uWSGI, и сейчас же установим Nginx.

Нам нужно обновить локальный индекс пакетов, а затем установить пакеты. Необходимые пакеты зависят от того, использует ли ваш проект Python 2 или Python 3.

Если вы используете Python 2, введите:

  1. sudo apt-get update
  2. sudo apt-get install python-pip python-dev nginx

Если вместо этого вы используете Python 3, введите:

  1. sudo apt-get update
  2. sudo apt-get install python3-pip python3-dev nginx

Создайте виртуальную среду Python

Далее мы настроим виртуальную среду, чтобы изолировать наше приложение Flask от других файлов Python в системе.

Начните с установки пакета virtualenv с помощью pip.

Если вы используете Python 2, введите:

  1. sudo pip install virtualenv

Если вы используете Python 3, введите:

  1. sudo pip3 install virtualenv

Теперь мы можем создать родительский каталог для нашего проекта Flask. Перейдите в каталог после его создания:

  1. mkdir ~/myproject
  2. cd ~/myproject

Мы можем создать виртуальную среду для хранения требований Python нашего проекта Flask, набрав:

  1. virtualenv myprojectenv

Это установит локальную копию Python и pip в каталог с именем myprojectenv в каталоге вашего проекта.

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

  1. source myprojectenv/bin/activate

Ваше приглашение изменится, чтобы показать, что вы сейчас работаете в виртуальной среде. Это будет выглядеть примерно так: (myprojectenv)user@host:~/myproject$.

Настройте приложение Flask

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

Установите Flask и uWSGI

Мы можем использовать локальный экземпляр pip для установки Flask и uWSGI. Введите следующие команды, чтобы получить эти два компонента:

Независимо от того, какую версию Python вы используете, при активации виртуальной среды следует использовать команду pip (не pip3).

  1. pip install uwsgi flask

Создайте пример приложения

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

Хотя ваше приложение может быть более сложным, мы создадим наше приложение Flask в одном файле, который назовем myproject.py:

  1. nano ~/myproject/myproject.py

В этом файле мы разместим код нашего приложения. По сути, нам нужно импортировать Flask и создать экземпляр объекта Flask. Мы можем использовать это для определения функций, которые должны запускаться при запросе определенного маршрута:

from flask import Flask
app = Flask(__name__)

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

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

Это в основном определяет, какой контент будет отображаться при доступе к корневому домену. Сохраните и закройте файл, когда закончите.

Если вы следовали руководству по первоначальной настройке сервера, у вас должен быть включен брандмауэр UFW. Чтобы протестировать наше приложение, нам нужно разрешить доступ к порту 5000.

Откройте порт 5000, набрав:

  1. sudo ufw allow 5000

Теперь вы можете протестировать свое приложение Flask, набрав:

  1. python myproject.py

Посетите доменное имя или IP-адрес вашего сервера, а затем :5000 в веб-браузере:

http://server_domain_or_IP:5000

Вы должны увидеть что-то вроде этого:

Когда вы закончите, несколько раз нажмите CTRL-C в окне терминала, чтобы остановить сервер разработки Flask.

Создайте точку входа WSGI

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

Назовем файл wsgi.py:

  1. nano ~/myproject/wsgi.py

Файл невероятно прост, мы можем просто импортировать экземпляр Flask из нашего приложения, а затем запустить его:

from myproject import app

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

Сохраните и закройте файл, когда закончите.

Настроить uWSGI

Теперь наше приложение написано, и точка входа установлена. Теперь мы можем перейти к uWSGI.

Тестирование обслуживания uWSGI

Первое, что мы сделаем, это протестируем, чтобы убедиться, что uWSGI может обслуживать наше приложение.

Мы можем сделать это, просто передав ему имя нашей точки входа. Он состоит из имени модуля (минус расширение .py, как обычно) плюс имя вызываемого объекта в приложении. В нашем случае это будет wsgi:app.

Мы также укажем сокет, чтобы он запускался на общедоступном интерфейсе, и протокол, чтобы он использовал HTTP вместо бинарного протокола uwsgi. Мы будем использовать тот же номер порта, который мы открыли ранее:

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

Посетите доменное имя или IP-адрес вашего сервера с :5000, добавленным к концу, в веб-браузере еще раз:

http://server_domain_or_IP:5000

Вы должны снова увидеть вывод вашего приложения:

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

Теперь мы закончили с нашей виртуальной средой, поэтому мы можем ее деактивировать:

  1. deactivate

Любые команды Python теперь снова будут использовать системную среду Python.

Создание файла конфигурации uWSGI

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

Давайте поместим это в каталог нашего проекта и назовем его myproject.ini:

  1. nano ~/myproject/myproject.ini

Внутри мы начнем с заголовка [uwsgi], чтобы uWSGI знал, как применить настройки. Мы укажем модуль, обратившись к нашему файлу wsgi.py, за вычетом расширения, и что вызываемый объект в файле называется \app:

[uwsgi]
module = wsgi:app

Затем мы скажем uWSGI запуститься в режиме мастера и создать пять рабочих процессов для обслуживания фактических запросов:

[uwsgi]
module = wsgi:app

master = true
processes = 5

Во время тестирования мы выставили uWSGI на сетевой порт. Однако мы собираемся использовать Nginx для обработки реальных клиентских подключений, которые затем будут передавать запросы в uWSGI. Поскольку эти компоненты работают на одном компьютере, сокет Unix предпочтительнее, поскольку он более безопасен и быстрее. Мы назовем сокет myproject.sock и поместим его в этот каталог.

Нам также придется изменить разрешения на сокете. Позже мы передадим группе Nginx право собственности на процесс uWSGI, поэтому нам нужно убедиться, что владелец группы сокета может читать информацию из него и записывать в него. Мы также очистим сокет, когда процесс остановится, добавив опцию «вакуум»:

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

Последнее, что нам нужно сделать, это установить параметр die-on-term. Это может помочь гарантировать, что система инициализации и uWSGI имеют одинаковые предположения о том, что означает каждый сигнал процесса. Установка этого параметра выравнивает два системных компонента, реализуя ожидаемое поведение:

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

die-on-term = true

Вы могли заметить, что мы не указываем протокол, как в командной строке. Это связано с тем, что по умолчанию uWSGI использует протокол uwsgi, быстрый двоичный протокол, предназначенный для связи с другими серверами. Nginx может говорить по этому протоколу нативно, поэтому лучше использовать его, чем навязывать связь по HTTP.

Когда вы закончите, сохраните и закройте файл.

Создайте файл модуля systemd

Следующей частью, о которой нам нужно позаботиться, является файл сервисного модуля systemd. Создание файла модуля systemd позволит системе инициализации Ubuntu автоматически запускать uWSGI и обслуживать наше приложение Flask при каждой загрузке сервера.

Для начала создайте юнит-файл с расширением .service в каталоге /etc/systemd/system:

  1. sudo nano /etc/systemd/system/myproject.service

Внутри мы начнем с раздела [Unit], который используется для указания метаданных и зависимостей. Мы разместим здесь описание нашей службы и скажем системе инициализации запускать ее только после достижения цели сети:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

Далее мы откроем раздел [Service]. Мы укажем пользователя и группу, под которыми мы хотим запустить процесс. Мы предоставим нашей обычной учетной записи пользователя право собственности на процесс, поскольку она владеет всеми соответствующими файлами. Мы передадим групповое владение группе www-data, чтобы Nginx мог легко взаимодействовать с процессами uWSGI.

Затем мы создадим карту рабочего каталога и установим переменную окружения PATH, чтобы система инициализации знала, где находятся наши исполняемые файлы для процесса (в нашей виртуальной среде). Затем мы укажем команду для запуска службы. Systemd требует, чтобы мы указали полный путь к исполняемому файлу uWSGI, который установлен в нашей виртуальной среде. Мы передадим имя файла конфигурации .ini, который мы создали в каталоге нашего проекта:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

Наконец, мы добавим раздел [Install]. Это сообщит systemd, с чем связать эту службу, если мы разрешим ее запуск при загрузке. Мы хотим, чтобы эта служба запускалась, когда обычная многопользовательская система запущена и работает:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

[Install]
WantedBy=multi-user.target

На этом наш служебный файл systemd завершен. Сохраните и закройте его сейчас.

Теперь мы можем запустить созданную нами службу uWSGI и включить ее, чтобы она запускалась при загрузке:

  1. sudo systemctl start myproject
  2. sudo systemctl enable myproject

Настройка Nginx для прокси-запросов

Теперь наш сервер приложений uWSGI должен быть запущен и работать, ожидая запросов к файлу сокета в каталоге проекта. Нам нужно настроить Nginx для передачи веб-запросов в этот сокет с использованием протокола uwsgi.

Начните с создания нового файла конфигурации блока сервера в каталоге Nginx sites-available. Мы просто назовем этот myproject, чтобы соответствовать остальной части руководства:

  1. sudo nano /etc/nginx/sites-available/myproject

Откройте блок сервера и скажите Nginx прослушивать порт 80 по умолчанию. Нам также нужно указать ему использовать этот блок для запросов доменного имени или IP-адреса нашего сервера:

server {
    listen 80;
    server_name server_domain_or_IP;
}

Единственное, что нам нужно добавить, это блок местоположения, который соответствует каждому запросу. В этот блок мы включим файл uwsgi_params, в котором указаны некоторые общие параметры uWSGI, которые необходимо установить. Затем мы будем передавать запросы в сокет, который мы определили с помощью директивы uwsgi_pass:

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/sammy/myproject/myproject.sock;
    }
}

Собственно, это все, что нам нужно для обслуживания нашего приложения. Сохраните и закройте файл, когда закончите.

Чтобы включить конфигурацию блока сервера Nginx, которую мы только что создали, свяжите файл с каталогом sites-enabled:

  1. sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

С файлом в этом каталоге мы можем проверить наличие синтаксических ошибок, набрав:

  1. sudo nginx -t

Если это возвращается без каких-либо проблем, мы можем перезапустить процесс Nginx, чтобы прочитать нашу новую конфигурацию:

  1. sudo systemctl restart nginx

Последнее, что нам нужно сделать, это снова настроить наш брандмауэр. Нам больше не нужен доступ через порт 5000, поэтому мы можем удалить это правило. Затем мы можем разрешить доступ к серверу Nginx:

  1. sudo ufw delete allow 5000
  2. sudo ufw allow 'Nginx Full'

Теперь вы сможете перейти к доменному имени или IP-адресу вашего сервера в веб-браузере:

http://server_domain_or_IP

Вы должны увидеть вывод вашего приложения:

После настройки Nginx следующим шагом должна быть защита трафика на сервер с помощью SSL/TLS. Это важно, потому что без него вся информация, включая пароли, пересылается по сети в виде обычного текста.

Самый простой способ получить SSL-сертификат для защиты вашего трафика — использовать Let’s Encrypt. Следуйте этому руководству, чтобы настроить Let’s Encrypt с помощью Nginx в Ubuntu 16.04.

Заключение

В этом руководстве мы создали простое приложение Flask в виртуальной среде Python. Мы создаем точку входа WSGI, чтобы любой сервер приложений с поддержкой WSGI мог взаимодействовать с ней, а затем настроили сервер приложений uWSGI для предоставления этой функции. После этого мы создали служебный файл systemd для автоматического запуска сервера приложений при загрузке. Мы создали серверный блок Nginx, который пропускает трафик веб-клиента на сервер приложений, ретранслируя внешние запросы.

Flask — это очень простой, но чрезвычайно гибкий фреймворк, предназначенный для предоставления вашим приложениям функциональности без чрезмерных ограничений в отношении структуры и дизайна. Вы можете использовать общий стек, описанный в этом руководстве, для обслуживания приложений flask, которые вы разрабатываете.