Python

Развертывание приложения на Django с uWSGI и nginx в производственной среде

Spread the love

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

Концепция

Веб-сервер может обслуживать статичные файлы (HTML, изображения, CSS и т. д.) напрямую из файловой системы. Но он не может напрямую общаться с приложением на Django. Для этого ему нужно что-то, что будет запускать приложение, отправлять запросы от веб-клиентов (браузеров) и возвращать ответы. Для этого создан Web Server Gateway InterfaceWSGI. WSGI — это спецификация, которая описывает, как веб-сервер взаимодействует с веб-приложениями и как веб-приложения могут быть объединены в цепочку для обработки одного запроса.

uWSGI — это одна из реализаций WSGI в Python. В этом руководстве мы настроим uWSGI таким образом, чтобы он создавал сокет или порт и обслуживал запросы/ответы веб-сервера по протоколу uwsgi. В итоге наш полный стек компонентов будет выглядеть так:

the web client <-> the web server <-> the socket/the port <-> uwsgi <-> Django

Прежде чем начать настройку uWSGI

virtualenv

Убедитесь, что вы используете virtualenv, если нет его нужно установить (позже мы опишем, как установить общесистемный uwsgi):

virtualenv uwsgi-tutorial
cd uwsgi-tutorial
source bin/activate

Django

Установите Django в свой virtualenv, создайте новый проект и перейдите в проект:

pip install Django
django-admin.py startproject mysite
cd mysite

О домене и о порте

В этом статье мы назовем наш домен example.com. Замените это доменное имя на свое полное доменное имя или IP-адрес.

Повсеместно, мы будем использовать порт 8000 для публикации на веб-сервере, так же, как сервер запуска Django делает это по умолчанию. Конечно, вы можете использовать любой порт, который хотите, но я выбрал этот, чтобы он не конфликтовал с тем, что веб-сервер уже может делать.

Базовая установка и настройка uWSGI

Установите uWSGI в свой virtualenv

pip install uwsgi

Конечно, есть и другие способы установки uWSGI, но этот так же хорош, как и любой другой. Помните, что вам нужно будет установить пакеты разработки Python. В случае Debian или систем, производных от Debian, таких как Ubuntu, вам нужно установить pythonX.Y-dev, где X.Y — ваша версия Python.

Базовый тест

Создайте файл с названием test.py:

# test.py
def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"] # python3
    #return ["Hello World"] # python2

Примечание

Учтите, что Python 3 требует bytes().

Запуск uWSGI:

uwsgi --http :8000 --wsgi-file test.py

Эти опции означают:

  • http :8000: использовать протокол http и порт 8000
  • wsgi-file test.py: загружаем файл test.py

При обращение через браузере к http://example.com:8000 вы должны сообщение «Hello World».

Теперь наш стек компонентов выглядит следующим образом:

the web client <-> uWSGI <-> Python

Протестируем проект Django

Теперь мы хотим, чтобы uWSGI делал то же самое, но вместо приложения test.py запускал сайт на Django.

Если вы еще этого не сделали, убедитесь, что ваш проект на Django действительно работает:

python manage.py runserver 0.0.0.0:8000

И далее запустите его с помощью uWSGI:

uwsgi --http :8000 --module mysite.wsgi
  • module mysite.wsgi: означает загрузку указанный модуля wsgi

Если теперь зайти через браузер на сервер должно отобразиться приложение а наш стек компонентом будет таким:

the web client <-> uWSGI <-> Django

Но как правило, браузер не должен напрямую обращаться к uWSGI. Это работа для веб-сервера, который будет действовать как посредник.

Основы nginx

Установка nginx

sudo apt-get install nginx
sudo /etc/init.d/nginx start    # start nginx

После установки проверьте, работает ли nginx, посетив страницу по умолчанию в веб-браузере по порту 80 — вы должны получить сообщение от nginx: «Welcome to nginx!». В этом случае наш стек будет таким:

the web client <-> the web server

Настройте nginx для своего сайта

Далее вы можете использовать файл uwsgi_params, который доступен в каталоге nginx дистрибутива uWSGI или по адресу https://github.com/nginx/nginx/blob/master/conf/uwsgi_params

Скопируйте его в каталог вашего проекта. Далее мы укажем nginx как его использовать.

Теперь создайте файл с именем mysite_nginx.conf со следующим содержимым:

# mysite_nginx.conf

# the upstream component nginx needs to connect to
upstream django {
    # server unix:///path/to/your/mysite/mysite.sock; # for a file socket
    server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name .example.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /media  {
        alias /path/to/your/mysite/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /path/to/your/mysite/static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
    }
}

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

Создайте ссылку на этот файл в /etc/nginx/sites-enabled, чтобы nginx смог его увидеть:

sudo ln -s ~/path/to/your/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/

Развертывание статических файлов

Перед запуском nginx вы должны собрать все статические файлы Django в папке со статикой. Для этого вы должны отредактировать mysite/settings.py, добавив в него:

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

а потом запустить

python manage.py collectstatic

Базовый тест nginx

Перезапустите nginx:

sudo /etc/init.d/nginx restart

Чтобы проверить, что медиа-файлы обслуживаются правильно, добавьте изображение с именем media.png в каталог /path/to/your/project/project/media, а затем посетите http://example.com:8000/media/media.png — если это работает, вы будете знать, по крайней мере, что nginx правильно обслуживает файлы.

nginx и uWSGI и test.py

Давайте еще раз запустим приложение «hello world» test.py.

uwsgi --socket :8001 --wsgi-file test.py

Это почти так же, как и раньше, за исключением того, что один из вариантов отличается:

  • socket :8001: использует протокол uwsgi, порт 8001

В то же время nginx настроен на связь с uWSGI через этот порт и с внешним миром через порт 8000. Посетите:

http://example.com:8000

Теперь наш стек будет следующим:

the web client <-> the web server <-> the socket <-> uWSGI <-> Python

Между тем, вы можете попытаться взглянуть на вывод uswgi по адресу http://example.com:8001 — но вполне вероятно, что он не будет работать, потому что ваш браузер работает по протоколу http, а не через протокол uWSGI, хотя вы должны увидеть вывод uWSGI в терминале.

Использование Unix-сокетов вместо портов

До сих пор мы использовали порты TCP, потому что это проще, но на самом деле лучше использовать сокеты Unix, — так как в этом случае будет меньше накладных расходов.

Отредактируйте mysite_nginx.conf, изменив следующее:

server unix:///path/to/your/mysite/mysite.sock; # for a file socket
# server 127.0.0.1:8001; # for a web port socket (we'll use this first)

и перезапустите nginx.

Запустите uWSGI снова:

uwsgi --socket mysite.sock --wsgi-file test.py

На этот раз опция socket сообщает uWSGI, какой файл сокетов использовать.

Попробуйте http://example.com:8000/ в браузере.

Если это не работает

Проверьте ваш журнал ошибок nginx (/var/log/nginx/error.log). Если вы видите что-то вроде:

connect() to unix:///path/to/your/mysite/mysite.sock failed (13: Permission
denied)

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

В этом случае попробуйте следующую команду:

uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=666 # (very permissive)

или:

uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=664 # (more sensible)

Возможно, вам также придется добавить своего пользователя в группу nginx (которая, вероятно, относится к www-data) или наоборот, чтобы nginx мог правильно читать и записывать в ваш сокет.

Запуск приложения Django с помощью uwsgi и nginx

Давайте теперь запустим наше приложение Django:

uwsgi --socket mysite.sock --module mysite.wsgi --chmod-socket=664

Теперь uWSGI и nginx должны обслуживать не просто модуль «Hello World», а ваш проект Django.

Настройка uWSGI для работы с INI-файлом

Мы можем поместить в файл те же параметры, которые мы использовали с uWSGI, а затем попросить uWSGI запуститься с этим файлом.

Создайте файл с именем mysite_uwsgi.ini:

# mysite_uwsgi.ini file
[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /path/to/your/project
# Django's wsgi file
module          = project.wsgi
# the virtualenv (full path)
home            = /path/to/virtualenv

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /path/to/your/project/mysite.sock
# ... with appropriate permissions - may be needed
# chmod-socket    = 664
# clear environment on exit
vacuum          = true

И запустите uwsgi, используя этот файл:

uwsgi --ini mysite_uwsgi.ini # the --ini option is used to specify a file

Еще раз, проверьте, что сайт Django работает, как ожидалось.

Установите uWSGI для всей системы

Пока у нас uWSGI был установлен только в нашей виртуальной среде; иногда может возникнуть, чтобы он был установлен в масштабе всей системы.

Деактивируйте virtualenv:

deactivate

и установите uWSGI для всей системы:

sudo pip install uwsgi

# Or install LTS (long term support).
pip install https://projects.unbit.it/downloads/uwsgi-lts.tar.gz

Вики uWSGI описывает несколько процедур установки (installation procedures). Перед установкой uWSGI для всей системы стоит подумать, какую версию выбрать и какой подходящий способ ее установки.

Проверьте еще раз, что вы все еще можете запускать uWSGI так же, как и раньше:

uwsgi --ini mysite_uwsgi.ini # the --ini option is used to specify a file

Режим Emperor

uWSGI может работать в режиме «emperor». В этом режиме он следит за каталогом конфигурационных файлов uWSGI и порождает экземпляры («vassals») для каждого найденного файла.

Всякий раз, когда в конфигурационный файл вносятся изменения, emperor автоматически перезапускает vassal.

# create a directory for the vassals
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
# symlink from the default config directory to your config file
sudo ln -s /path/to/your/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/
# run the emperor
uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

Вам может потребоваться запустить uWSGI с помощью sudo:

sudo uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

Эти опции означают:

  • emperor: каталог где искать vassals (конфигурационные файлы)
  • uid: идентификатор пользователя user id процесса после его запуска
  • gid: идентификатор группы group id процесса после его запуска

Запуск uWSGI при загрузке системы

Последний шаг — это сделать автоматический запуск uWSGI во время запуска системы.

Для многих систем самый простой (если не самый лучший) способ сделать это — использовать файл rc.local.

Отредактируйте /etc/rc.local добавив в него:

/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --daemonize /var/log/uwsgi-emperor.log

перед строкой “exit 0”.

Дальнейшая конфигурация

Хорошей практикой так же будет, если вы создадите например рядом с файлом manage.py отдельный bash файл для запуска/перезапуска приложения Django. Например можно создать server.sh со следующим содержимым:

#!/bin/bash

ROOT=`pwd`
name=app_django
prefix=prefix_name

socket=/tmp/$prefix-$name.sock 
pidfile=$ROOT/logs/run/$name.pid 
errlog=$ROOT/logs/$name.error.log
python=$WORKON_HOME/$prefix/bin/python

cd $ROOT
case "$1" in
    "start")
        uwsgi --chdir=$ROOT --module=root.wsgi \
            --env DJANGO_SETTINGS_MODULE=root.settings \
            --master --pidfile=$pidfile \
            --socket=$socket --processes=2 --harakiri=120 --post-buffering=1 \
            --max-requests=4000 --vacuum --home=$WORKON_HOME/$prefix \
            --daemonize=$errlog
        chmod o+w $socket
        ;;
    "stop")
        kill -9 `cat $pidfile`
        ;;
    "restart")
        ./server.sh stop
        ./server.sh start
        ;;
    *) 
        echo "Usage: ./server.sh {start|stop|restart}"
        ;;
esac

Так же необходимо будет изменить права доступа к файлу chmod +x server.sh. Теперь для запуска приложения Django можно использовать команду

./server.sh start

А для перезапуска

./server.sh restart
Была ли вам полезна эта статья?
[18 / 4.8]

Spread the love
Editorial Team

View Comments

  • Совет: если вы работаете из под root, то может возникнуть ошибка 403 при доступе к статическим файлам.
    Чтобы этого не было нужно в файле /etc/nginx/nginx.conf отредактировать первую строчку чтобы она была:
    user root;

    • Альтернативный совет: если вы работаете из-под рута, прекратите это делать.

  • >uwsgi --http :8000 --wsgi-file test.py
    uwsgi: unrecognized option '--wsgi-file'
    getopt_long() error

    Вот что выдает. Я так понимаю руководство уже неактуально?

  • какой умный человек создал этот гайд

    (гайдном буду)

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

10 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

10 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago