Деплой Django+uWSGI+Nginx
May 29, 2014 10:35 · 1059 words · 5 minute read
Несколькими статьями ранее я рассказывал как на одной странице вывести список объектов и форму для добавления нового. Пришло время запульнуть это приложение на сервер :) Для этого нам понадобится nginx (1.4.6), uwsgi (1.0.3), virtualenv (1.7.1.2), supervisor. Определимся, что файлы проекта будут лежать в /var/www/tyvik/markettyvik.
Установка виртуального окружения
Любое приложение на Django по-хорошему надо поместить в песочницу, чтобы пакеты, которые оно требует, не конфликтовали с системными. Для этих целей есть специальные пакеты virtualenv и virtualenvwrapper. Мне пока достаточно функционала первого, приступим:
$ sudo apt-get install python-virtualenv
$ cd /var/www/tyvik/markettyvik
$ mkdir venv
$ virtualenv --no-site-packages venv/
После этих манипуляций в каталоге /var/www/tyvik/markettyvik/venv/ появятся файлы, необходимые для работы python. Ключ –no-site-packages нужен для того, чтобы уже установленные системные пакеты не переносились в виртуальное окружение. Активируем его и установим зависимости:
$ source venv/bin/activate
$ pip install -r requirements.txt
Я не зря упомянул virtualenvwrapper, он позволяет держать несколько разных виртуальных окружений и переключаться между ними не через source, а командой workon. Это пригодится разработчикам, особенно когда они сопровождают множество разных python-проектов.
Установка зависимостей
Зачастую в проекте есть зависимости от модулей, которые компилируются при установке, например, MySQL-python. Для них нужны dev-пакеты с исходниками. Понять, что какого-то пакета нет в системе можно по сообщению об ошибке “Не найден файл *.h”. В таком случае рекомендую просто гуглить по строке с ошибкой. В частности, для MySQL-python нужны python-dev и libmysqlclient-dev. Установим их:
$ sudo apt-get install libmysqlclient-dev
$ sudo apt-get install python-dev
Установка приложения
С зависимостями разобрались, теперь нужно установить приложение. Сводится это к двум моментам: настройка базы и сбор статики. Моё приложение использует MySQL, следовательно нужно создать соответствующего пользователя, базу данных и распределить права. Также надо задать кодировку по умолчанию как utf8-general-ci, потому как в командах CREATE TABLE Django автоматически не добавляет эту настройку. После всего этого можно запустить миграцию:
$ ./manage.py syncdb
В результате будут созданы нужные таблицы и добавлены связи. Теперь перейдём к сбору статических ресурсов (CSS и JS). Для этого служит команда collectstatic:
$ ./manage.py collectstatic
Она просто копирует всю статику из каждого модуля в каталог со статикой главного приложения. Встроенный web-сервер Django умеет находить эти ресурсы самостоятельно, но для работы uwsgi+nginx необходимо, чтобы вся она лежала в одном каталоге. Настройки для этой операции находятся в settings.py головного модуля.
Настройка uWSGI
В комплекте с Django идёт простенький web-сервер, который предназначен для разработки. Его крайне не рекомендуется использовать в боевом окружении. Стандартом для этого стал uWSGI - шлюз между web-сервером (nginx) и приложением (Django). Эта штука запускается демоном и умеет сама запускать виртуальное окрудение и взаимодействовать со скриптами. В общем, ставим в систему:
$ sudo apt-get install uwsgi uwsgi-plugin-python
Теперь зададим конфигурацию приложения в файле deploy/uwsgi.conf.xml:
<uwsgi>
<socket>/var/www/tyvik/markettyvik/deploy/data/markettyvik.sock</socket>
<plugins>python27</plugins>
<pythonpath>/var/www/tyvik/markettyvik</pythonpath>
<virtualenv>/var/www/tyvik/markettyvik/venv</virtualenv>
<module>markettyvik.wsgi</module>
<master />
<workers>4</workers>
<processes>2</processes>
<uid>www-data</uid>
</uwsgi>
Разберём параметры:
- socket - сокет, через который будет идти взаимодействие nginx с django.
- plugins - тип приложения
- pythonpath - путь до приложения
- virtualenv - какое виртуальное окружение использовать
- module - точка входа
- workers - количество воркеров
- processes - количество процессов
- uid - от имени какого пользователя выполнять скрипты
Конфигурационные файлы можно писать не только в формате xml, но также ini, yaml и пр. Проверить работу можно командой
$ sudo uwsgi -x deploy/uwsgi.conf.xml
Не будем пока прерывать работу этой команды, она понадобится для настройки Nginx.
Настройка Nginx
Осталось последнее звено - настройка web-сервера. Его конфигурационные файлы находятся в каталоге /etc/nginx, а в подкаталоге sites-available - настройки для конкретных сайтов. Можно создать новый файл непосредственно там, но я предпочитаю всё, что касается проекта, держать в одном месте. Посему конфиг будет в каталоге приложения deploy/nginx.conf, а в sites-available всего лишь ссылка на него.
upstream markettyvik {
ip_hash;
server unix:///var/www/tyvik/markettyvik/deploy/data/markettyvik.sock;
}
server {
listen 80;
server_name django.tyvik.ru;
location / {
uwsgi_pass markettyvik;
include uwsgi_params;
}
location /static {
alias /var/www/tyvik/markettyvik/static;
}
}
Разберём подробнее… Т.к. взаимодействие с uwsgi будет идти через UNIX-сокет, то нужно создать upstream со ссылкой на него. Далее в блоке location мы даём на него ссылку (параметр uwsgi_pass) и указываем, что используется uwsgi (подключаем uwsgi_params). Отдельно указываем где находится статика, потому что к ней будет обращаться nginx, а не django. Именно из-за этого ранее мы и собрали всю её в одном месте командой collectstatic. Если у вас используются файлы, загруженные пользователем, то по аналогии со /static надо будет дописать ещё один раздел location со ссылкой на него. Также указан порт и имя сервера, которое нужно обслуживать. Этими действиями мы только уведомили nginx, что есть конфигурация для нашего сервере, осталось её активировать, то есть создать ссылку в sites-enabled; также обновим конфигурацию Nginx:
$ ln -s /etc/nginx/sites-available/django.conf /etc/nginx/sites-enabled/django.conf
$ sudo service nginx reload
После этого по адресу django.tyvik.ru можно увидеть работающее приложение.
Итак, при запросе ресурса с django.tyvik.ru происходит следующее:
- Запрос перехватывается nginx. Если он начинается со “/static”, то берётся непосредственно файл из каталога static.
- В противном случае запрос передаётся через UNIX-сокет markettyvik.sock в uWSGI.
- uWSGI, используя виртуальное окружение, передаёт в markettyvik/wsgi.py.
- Там создаётся wsgi_application, которое уже обрабатывает запрос и ответ передаёт в uWSGI, которое отдаёт nginx, который уже отдаёт пользователю :)
В принципе, всё работает и на этом можно было бы и остановиться, но рассказ не будет полным без описания supervisor'а.
Настройка supervisor
А что будет, если наше приложение упадёт? Всё остановится пока не придёт админ и не поднимет его. Это жутко неудобно, а значит есть средства для выполнения этой рутины. Назвается оно supervisor, ставится как-то так:
$ sudo apt-get install supervisor
Если вкратце, то оно регистрирует демона, который будет следить за другими процессами. В частности, определять жив ли как-нибудь процесс и в противном случае перезапускать его. Настроим, чтобы он следил за нашим приложением. Работа с ним должна вестись от имени root. Конфигурационный файл выглядит следующим образом:
[program:markettyvik]
user = www-data
directory = /var/www/tyvik/markettyvik
command = uwsgi -x /var/www/tyvik/markettyvik/deploy/uwsgi.conf.xml
autostart = true
autorestart = true
stderr_logfile = /var/www/tyvik/markettyvik/deploy/data/uwsgi-err.log
stdout_logfile = /var/www/tyvik/markettyvik/deploy/data/uwsgi-out.log
stopsignal = QUIT
Здесь говорится, что для программы markettyvik [program] надо перейти в каталог /var/www/tyvik/markettyvik [directory] и выполнить uwsgi -x /var/… [command] от имени www-data [user], причём вывод писать в /var/www/…/uwsgi-out.log [stdout_logfile], а ошибки в /var/www/…/uwsgi-err.log [stderr_logfile]. Все конфигурации для supervisor хранятся в /etc/supervisor/conf.d/. Сделаем туда ссылку и немного поиграемся :)
> sudo ln -s /var/www/tyvik/markettyvik/deploy/supervisor.conf /etc/supervisor/conf.d/markettyvik.conf
> sudo supervisorctl update
markettyvik: added process group
> sudo supervisorctl start markettyvik
markettyvik: started
> sudo supervisorctl status
markettyvik RUNNING pid 8988, uptime 0:00:32
Приложение работает и будет перезапущено в случае падения.
Вот теперь, пожалуй, всё готово :) Если что-то не работает, или я забыл указать какой-либо нюанс, просьба оставить комментарий. Готовый пример можно посмотреть у меня на github.