Некоторое время назад озадачился поиском способа развертывания проектов Django, к которому предъявлялись два требования:
По второму пункту мой выбор склонился в пользу Nginx + uWSGI. По первому же, из рассмотренных мною вариантов больше всего понравились обвязки для uWSGI в Debian.
Поддержка uWSGI появилась в Nginx с версии 0.8.40, но ни первого, ни второго в стабильной ветке Debian нет. Поэтому Nginx будем брать из бэкпортов, а uWSGI – из нестабильной ветки. Для этого добавим следующие строчки в /etc/apt/sources.list:
И создадим примерно такой /etc/apt/preferences:
Синхронизируемся с помощью aptitude update и устанавливаем необходимые пакеты:
Рассмотрим развертывание для проекта example. Для определенности, предположим, что все проекты размещаются в подкаталоге proj домашнего каталога пользователя web. Так же в proj имеется подкаталог static, где будут размещаться статические файлы проектов, за раздачу которых будет отвечать Nginx. Для проекта example получим следующие пути:
В settings.py проекта example имеем настройки:
Таким образом менеджмент-команда collectstatic будет собирать всю статику проекта в /home/web/proj/static/example.
Виртуальное окружение для проекта example будет находиться в /home/web/envs/example.
Конфигурационный файл uWSGI для проекта example будет называться /etc/uwsgi/apps-available/example.ini и примет следующий вид:
Также создаем символическую ссылку на него в /etc/uwsgi/apps-enabled:
После чего запускаем демон uWSGI: /etc/init.d/uwsgi start example
Конфигурационный файл Nginx назовем /etc/nginx/sites-available/example. Его минимальный вариант может быть таким:
Точно так же создаем символическую ссылку в /etc/nginx/sites-enabled:
И перезапускаем Nginx: /etc/init.d/nginx restart
Сначала вкратце остановлюсь на пераметрах в конфигурационном файле uWSGI. Параметр plugins явно задает версию Python. Параметры chdir и pythonpath добавляют каталог проекта и его родительский каталог в пути поиска Python. Параметры env и module позволяют обойтись без создания специального скрипта для запуска проекта демоном uWSGI. Параметр touch-reload позволяет делать перезагрузку проекта с помощью команды touch /home/web/proj/example/touchme.
Такой лаконичный файл конфигурации для uWSGI получился потому, что стартовый скрипт /etc/init.d/uwsgi использует еще один конфигурационный файл /usr/share/uwsgi/conf/default.ini, в котором для всех остальных необходимых параметров заданы достаточно разумные значения по умолчанию. При необходимости их можно переопределить в /etc/uwsgi/apps-available/example.ini. За удалением некоторых комментариев, содержимое /usr/share/uwsgi/conf/default.ini будет следующим:
В обвязках к uWSGI в Debian введено понятие конфигурационного пространства имен. В default.ini оно представлено с помощью переменной %(deb-confnamespace) со значением по умолчанию app. Имя конфигурационного пространства имен определяется следующим образом: стартовый скрипт /etc/init.d/uwsgi ищет в каталоге /etc/uwsgi все подкаталоги, заканчивающиеся на s-enabled, и часть имени подкаталога, предшествующая s-enabled становится именем конфигурационного пространства для файлов в этом подкаталоге. В нашем случае можно было бы создать в /etc/uwsgi более привычные подкаталоги sites-available и sites-enabled, в которые поместить файл конфигурации example.ini и символическую ссылку на него соответственно; pidfile и socket для этой конфигурации находились бы в /run/uwsgi/site/example/pid и /run/uwsgi/site/example/socket, а управление демоном uWSGI для этой конфигурации осуществлялось бы с помощью команд /etc/init.d/uwsgi start|stop|restart site/example. При отсутствии префикса подразумевается пространство имен app.
- Удобное управление запуском/остановкой/перезапуском нескольких проектов на одном хосте
- Поддержка разных виртуальных сред для разных проектов
По второму пункту мой выбор склонился в пользу Nginx + uWSGI. По первому же, из рассмотренных мною вариантов больше всего понравились обвязки для uWSGI в Debian.
Установка ПО
Поддержка uWSGI появилась в Nginx с версии 0.8.40, но ни первого, ни второго в стабильной ветке Debian нет. Поэтому Nginx будем брать из бэкпортов, а uWSGI – из нестабильной ветки. Для этого добавим следующие строчки в /etc/apt/sources.list:
deb http://backports.debian.org/debian-backports squeeze-backports main contrib non-free deb http://ftp.ru.debian.org/debian testing main non-free contrib deb http://ftp.ru.debian.org/debian unstable main non-free contrib
И создадим примерно такой /etc/apt/preferences:
Package: * Pin: release a=stable Pin-Priority: 700 Package: * Pin: release a=squeeze-backports Pin-Priority: 675 Package: * Pin: release a=testing Pin-Priority: 650 Package: * Pin: release a=unstable Pin-Priority: 600
Синхронизируемся с помощью aptitude update и устанавливаем необходимые пакеты:
aptitude -t squeeze-backports install nginx aptitude -t unstable install uwsgi aptitude -t unstable install uwsgi-plugin-python aptitude -t unstable install python-virtualenv
Структура каталогов для проектов
Рассмотрим развертывание для проекта example. Для определенности, предположим, что все проекты размещаются в подкаталоге proj домашнего каталога пользователя web. Так же в proj имеется подкаталог static, где будут размещаться статические файлы проектов, за раздачу которых будет отвечать Nginx. Для проекта example получим следующие пути:
/home/web/proj/example /home/web/proj/static/example
В settings.py проекта example имеем настройки:
STATIC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '../static/example')) STATIC_URL = '/static/'
Таким образом менеджмент-команда collectstatic будет собирать всю статику проекта в /home/web/proj/static/example.
Виртуальное окружение для проекта example будет находиться в /home/web/envs/example.
Настройка uWSGI и Nginx
Конфигурационный файл uWSGI для проекта example будет называться /etc/uwsgi/apps-available/example.ini и примет следующий вид:
[uwsgi] plugins = python27 virtualenv = /home/web/envs/example/ chdir = /home/web/proj/example/ pythonpath = .. env = DJANGO_SETTINGS_MODULE=example.settings module = django.core.handlers.wsgi:WSGIHandler() touch-reload = /home/web/proj/example/touchme
Также создаем символическую ссылку на него в /etc/uwsgi/apps-enabled:
cd /etc/uwsgi/apps-enabled ln -s ../apps-available/example.ini .
После чего запускаем демон uWSGI: /etc/init.d/uwsgi start example
Конфигурационный файл Nginx назовем /etc/nginx/sites-available/example. Его минимальный вариант может быть таким:
server { listen 80; server_name example; access_log /var/log/nginx/example.access.log; error_log /var/log/nginx/example.error.log; location /static/ { alias /home/web/proj/static/example/; } location / { include uwsgi_params; uwsgi_pass unix:///var/run/uwsgi/app/example/socket; } }
Точно так же создаем символическую ссылку в /etc/nginx/sites-enabled:
cd /etc/nginx/sites-enabled/ ln -s ../sites-available/example .
И перезапускаем Nginx: /etc/init.d/nginx restart
Под капотом
Сначала вкратце остановлюсь на пераметрах в конфигурационном файле uWSGI. Параметр plugins явно задает версию Python. Параметры chdir и pythonpath добавляют каталог проекта и его родительский каталог в пути поиска Python. Параметры env и module позволяют обойтись без создания специального скрипта для запуска проекта демоном uWSGI. Параметр touch-reload позволяет делать перезагрузку проекта с помощью команды touch /home/web/proj/example/touchme.
Такой лаконичный файл конфигурации для uWSGI получился потому, что стартовый скрипт /etc/init.d/uwsgi использует еще один конфигурационный файл /usr/share/uwsgi/conf/default.ini, в котором для всех остальных необходимых параметров заданы достаточно разумные значения по умолчанию. При необходимости их можно переопределить в /etc/uwsgi/apps-available/example.ini. За удалением некоторых комментариев, содержимое /usr/share/uwsgi/conf/default.ini будет следующим:
[uwsgi] # try to autoload appropriate plugin if "unknown" option has been specified autoload = true # enable master process manager master = true # spawn 2 uWSGI worker processes workers = 2 # automatically kill workers on master's death no-orphans = true # write master's pid in file /run/uwsgi/<confnamespace>/<confname>/pid pidfile = /run/uwsgi/%(deb-confnamespace)/%n/pid # bind to UNIX socket at /run/uwsgi/<confnamespace>/<confname>/socket socket = /run/uwsgi/%(deb-confnamespace)/%n/socket # set mode of created UNIX socket chmod-socket = 660 # place timestamps into log log-date = true # user identifier of uWSGI processes uid = www-data # group identifier of uWSGI processes gid = www-data
В обвязках к uWSGI в Debian введено понятие конфигурационного пространства имен. В default.ini оно представлено с помощью переменной %(deb-confnamespace) со значением по умолчанию app. Имя конфигурационного пространства имен определяется следующим образом: стартовый скрипт /etc/init.d/uwsgi ищет в каталоге /etc/uwsgi все подкаталоги, заканчивающиеся на s-enabled, и часть имени подкаталога, предшествующая s-enabled становится именем конфигурационного пространства для файлов в этом подкаталоге. В нашем случае можно было бы создать в /etc/uwsgi более привычные подкаталоги sites-available и sites-enabled, в которые поместить файл конфигурации example.ini и символическую ссылку на него соответственно; pidfile и socket для этой конфигурации находились бы в /run/uwsgi/site/example/pid и /run/uwsgi/site/example/socket, а управление демоном uWSGI для этой конфигурации осуществлялось бы с помощью команд /etc/init.d/uwsgi start|stop|restart site/example. При отсутствии префикса подразумевается пространство имен app.
