Настройка сервера Linux для Tornado в CentOS 7, Debian 9 Stretch, Ubuntu 18.04 Bionic

Tornado — популярный минималистичный фреймворк для разработки web-сервисов с помощью Python. Он часто применяется как для создания обычных сервисов с RESTful-интерфейсом, так и для реализации приложений, использующих Websocket, что идеально реализуется с помощью асинхронных функций языка.

Разработка фреймворка ведется на GitHub. На следующем изображении вы можете видеть, что Tornado активно разрабатывается сообществом:

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

Закончив чтение данного руководства, вы научитесь самостоятельно настраивать минималистичный сервер для для Tornado без лишних компонентов. Ваше приложение будет доступно по защищенному протоколу HTTPS с поддержкой бесплатного сертификата Let’s Encrypt, балансировка трафика между выполняющимися экземплярами приложения Tornado будет осуществляться с помощью Nginx.

Базовая установка сервера для среды исполнения Tornado

Сначала настроим сервер Linux с балансирующим прокси-сервером Nginx и поддержкой сертификата Let’s Encrypt.

Настройка обратного прокси Nginx в CentOS 7 с доступом по SSL, защищенным сертификатом Let’s Encrypt.

Настройка обратного прокси Nginx в Debian 9 Stretch с доступом по SSL, защищенным сертификатом Let’s Encrypt.

Настройка обратного прокси Nginx в Ubuntu 18.04 Bionic Beaver с доступом по SSL, защищенным сертификатом Let’s Encrypt.

Стоит отметить, что в рамках данной настройки возможно использование двух вариантов настройки — с использованием Docker и без его использования. Мы рассмотрим в этой статье варинт настройки без Docker.

Подготовка среды исполнения для Tornado без использования Docker

В этом разделе мы выполним установку Python3, настроим автоматический запуск нескольких экземпляров Tornado, которые будут обрабатывать запросы. Затем, зарместим Tornado за балансирующим прокси-сервером Nginx, который будет осуществлять равномерное распределение нагрузки между серверами Tornado.

Установка Python3

CentOS 7. В CentOS 7 Python 3 устанавливается из дополнительного репозитория Software Collections. По умолчанию используется Python 2.7.

sudo yum install -y centos-release-scl
sudo yum install -y rh-python36
sudo yum groupinstall -y 'Development Tools'

Ubuntu 18.04. Установка Python 3 производится из стандартного репозитория:

sudo apt-get update
sudo apt-get install -y python3 python3-venv

Debian 9. Установка Python 3 производится из стандартного репозитория:

sudo apt-get update
sudo apt-get install -y python3 python3-venv

Подготовка среды для приложения Tornado

На этом шаге создадим VENV для исполнения приложения Tornado:

mkdir application
cd application
python3 -m venv application_env
source application_env/bin/activate
echo "tornado" > requirements.txt
pip install wheel
pip install -r requirements.txt

Тестовое приложение Tornado

Реализуем простое приложение Tornado, которое будем использовать для примера сервиса:

#!/usr/bin/env python

import tornado.ioloop
import tornado.web
import sys

class PingHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("pong\n")

app = tornado.web.Application([(r'/ping', PingHandler)])


if __name__ == "__main__":
    app.listen(int(sys.argv[1]), address='127.0.0.1')
    tornado.ioloop.IOLoop.current().start()

Создайте файл service.py с вышеуказанным содержимым:

cat > service.py
#!/usr/bin/env python

import tornado.ioloop
import tornado.web
import sys

class PingHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("pong\n")

app = tornado.web.Application([(r'/ping', PingHandler)])


if __name__ == "__main__":
    app.listen(int(sys.argv[1]), address='127.0.0.1')
    tornado.ioloop.IOLoop.current().start()

Ctrl^D

Установите права доступа, необходимые для исполнения:

chmod +x service.py

Проверим работу сервиса, запустив его и открыв в браузере http://server:port/ping:

# запустим в фоновом режиме
./service.py 8888 &

# проверим ответ
curl http://localhost:8888/
pong

# завершим процесс
kill %1
[1]+  Завершено      ./service.py 8888

# выйдем из VENV
deactivate
cd ..

Настройка автоматического запуска приложения с помощью systemd

Подготовим скрипт application/run.sh запуска приложения в рамках VENV со следующим содержимым:

#!/usr/bin/env bash

BASEDIR=$(dirname "$0")
echo "Executing App in '$BASEDIR'"

PORT=$1

source $BASEDIR/application_env/bin/activate

python $BASEDIR/service.py $PORT

Установим права на исполнение и протестируем его запуск:

chmod +x application/run.sh
./application/run.sh 8888

Запускать приложение будем с помощью systemd. Для этого создадим параметризованный файл для сервиса:

sudo nano /etc/systemd/system/tornado-app@.service

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

[Unit]
Description=Tornado App

[Service]
ExecStart=/home/administrator/application/run.sh %I
User=administrator
Restart=on-failure
Type=simple

[Install]
WantedBy=multi-user.target

Внимание. Путь, указанный в ExecStart и имя пользователя, указанное в User необходимо изменить для соответствия вашей среде.

Теперь проверим работоспособность запуска сервиса через systemd:

sudo systemctl enable tornado-app@8888.service

Created symlink from /etc/systemd/system/multi-user.target.wants/tornado-app@8888.service to /etc/systemd/system/tornado-app@.service.

sudo systemctl start tornado-app@8888.service
ps -x -opid,cmd | grep service

25161 python /home/administrator/application/service.py 8888

sudo systemctl restart tornado-app@8888.service
ps -x -opid,cmd | grep service

25166 python /home/administrator/application/service.py 8888

sudo systemctl stop tornado-app@8888.service
ps -x -opid,cmd | grep service

Создадим столько серверов Tornado, сколько необходимо. Вы можете захотеть запустить сервисов по количеству ядер, если используете эффективную асинхронную модель разработки, либо запустить сервисов столько, сколько возможно на узле, если асинхронная модель разработки не используется:

for port in $(seq 8889 8900); 
do 
  sudo systemctl enable tornado-app@$port.service && \
  sudo systemctl start tornado-app@$port.service
done

Проверим, что все сервисы запустились и работают:

ps -x -ocmd | grep service
python /home/administrator/application/service.py 8889
python /home/administrator/application/service.py 8890
python /home/administrator/application/service.py 8891
python /home/administrator/application/service.py 8892
python /home/administrator/application/service.py 8893
python /home/administrator/application/service.py 8894
python /home/administrator/application/service.py 8895
python /home/administrator/application/service.py 8896
python /home/administrator/application/service.py 8897
python /home/administrator/application/service.py 8898
python /home/administrator/application/service.py 8899
python /home/administrator/application/service.py 8900

Перезагрузите сервер для того, чтобы убедиться в том сервис запускается автоматически при старте системы.

Настройка проксирования через Nginx

В секции upstream, которую мы создали при настройке обратного прокси-сервера Nginx, замените содержимое на адреса upstream-сервисов.

Было:

upstream dirlist {
        ip_hash; # липкая балансировка по IP-клиента
        server 127.0.0.1:8081;
        server 127.0.0.1:8082;
}

Должно стать:

upstream service {
        ip_hash; # липкая балансировка по IP-клиента
        server 127.0.0.1:8888;
        server 127.0.0.1:8889;
        server 127.0.0.1:8890;
        server 127.0.0.1:8891;
        server 127.0.0.1:8892;
        server 127.0.0.1:8893;
        server 127.0.0.1:8894;
        server 127.0.0.1:8895;
        server 127.0.0.1:8896;
        server 127.0.0.1:8897;
        server 127.0.0.1:8898;
        server 127.0.0.1:8899;
        server 127.0.0.1:8900;
}

Измените соответствующим образом proxy_pass http://dirlist/; на proxy_pass http://service/;. Проверьте корректность конфигурации и перезапустите Nginx:

sudo nginx -t && sudo systemctl restart nginx

Теперь вы можете обращаться к приложению по доменному имени с помощью защищенного протокола HTTPS, который обеспечивается сертификатом Let’s Encrypt.

Что еще сделать после установки?

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

  • повысить безопасность сервера с помощью тонкой настройки файрвола:
  • установить сайт под защиту CloudFlare;
  • настроить почтовый сервер, если вы планируете осуществлять отправку почты локально с сервера, а не по SMTP: