Ниже я расскажу о об одном из способов развернуть сайт на Django в боевом режиме, начиная от выбора хостинга, заканчивая развертыванием веб-сервера. Таким образом статья может быть полезна тем, кто освоил разработку на базе Django, но не имеет опыта развертывания серверов. Мой способ один из многих, но он достаточно прост, эффективен в работе и легок в поддержке. Используем VPS-хостинг, Ubuntu 10.04, nginx, gunicorn.
Оглавление
- Оглавление
- Структура проекта
- Хостинг
- Ubuntu server
- Развертывание проекта
- Настройка веб-сервера Nginx
- Настройка gunicorn и supervisor
- Устранение проблем
- Заключение
- Полезные ссылки
Структура проекта
Для дальнейшего повестования необходимо рассказать про структуру развертываемого проекта:
- myproject/ - корень проекта, обратите внимание, что это не корень исходников проекта; - env/ - вируальное окружение, создаваемое при помощи virtualenv; - src/ - папка с иходниками, ее удобно добавить в пути IDE, для того, чтобы обращаться к пакету myproject по имени; - myproject/ - корень исходников проекта, должна быть знакома Django-программистам; - __init__.py - settings.py - manage.py - urls.py - myapp1/ - myapp2/ ... - static_content/ - папка для файлов, которые раздает веб-сервер первого эшелона (у нас - nginx), будучи параноиком, я боюсь передавать веб-серверу папку, содержащую исходники проекта; - static/ - статические файлы проекта (то что храним в репозитории); - media/ - media-файлы, то что создается сайтом в ходе его функционирования; - docs/ - тут лежат полезные документы, комментарии, примеры конфигов; - logs/ - папка, куда складываю логи, касающиеся работы сайта; - pids/ - тут pid-файлы.
На первый взгляд глубина вложенности исходников может показаться избыточной. Однако мой опыт показывает, что издержки на работу при такой глубине невелики, а достоинства большей структурированности значительны.
Хостинг
Для себя я давно выяснил, что наиболее удобный хостинг для django — это VPS хостинг. Перепробовав несколько VPS-хостингов, я остановился на наиболее приемлемом в соотношении цена/качество — FirstVDS. Я пользуюсь тарифом за 400 рублей в месяц — 1500 MB RAM, 24000 MB HDD. Но сначала обходился тарифом за 150 рублей (в этом случае нужно будет научить некоторые приложения потреблять меньше ресурсов).
Итак, для того, чтобы начать нужно заказать и оплатить VPS, выбрав при этом тип виртуализации OpenVZ — неполная имитация физической машины, но для наших задач вполне достаточная, стоит заметить, что при такой виртуализации за те же деньги памяти дают больше, пригодится для memcached. В качестве операционной системы рекомендую выбирать Ubuntu Server 10.04 LTS#. Доступна также и Ubuntu Server 12.04 LTS, мне без особого труда удалось ввести ее в строй, однако шаблон на хостинге появился недавно, да и специалисты поддержки хостинг-провайдера не рекомендуют пока ее ставить на боевые сервера. Сейчас использую ее только на тестовом сервере.
После заказа и оплаты на почту приходит SSH-доступ, теперь можно приступать к настройке операционной системы.
Ubuntu server
Получив доступ, я, первым делом, обновляю систему, затем отключаю root-доступ по SSH.
Подключиться по SSH в Windows можно широкоизвестной программой Putty, но я использую ее более “накрученную” модификацию — kitty. В качестве IP-адреса сервера вводим высланный хостером адрес, подключаемся, вводим root в качестве user и пароль при запросе.
Для подключения в Линукс-подобных системах используем родной терминал (Terminal, Konsole, etc.), набрав в нем нехитрую команду:
ssh root@1.2.3.4
где 1.2.3.4 — IP-адрес, высланный хостером, при запросе вводим пароль, высланный хостинг-провайдером.
Первым делом сменим пароль рута, паранойи ради:
passwd
по запросу вводим новый пароль дважды, генерировать и хранить советую в KeePassX, не стесняйтесь сделать его посложнее (>20 символов), использовать его почти не придется.
Обновляем пакеты в системе:
apt-get update apt-get upgrade
Добавляем пользователя, от лица которого будем развертывать сервер:
adduser myuser
можно ничего не вводить кроме пароля, но лучше его придумать посложнее
Теперь понадобится редактор для правки конфигов, я предпочитаю nano:
apt-get install nano
Добавляем пользователю права исполнять команды от имени root (sudo):
nano /etc/sudoers # находим строку root ALL=(ALL:ALL) ALL # сразу после нее вставляем myuser ALL=(ALL:ALL) ALL
Теперь отключаем возможность пользователю root логиниться по SSH (делать необязательно, мера безопасности):
nano /etc/ssh/sshd_config # ищем PermitRootLogin yes # меняем на PermitRootLogin no
после этого я перезагружаю машину, чтобы убедиться, что все прошло как надо:
reboot
Спустя минуту можно логиниться как myuser (или можете предварительно проверить, что логин рутом больше не работает):
ssh myuser@1.2.3.4
Теперь я ставлю ряд системных пакетов, необходимых для работы Django-приложения и инфраструктуры:
sudo apt-get install gcc mysql-server python-mysqldb memcached mercurial python-profiler w3m python-setuptools libmysqlclient-dev git-core python-dev rabbitmq-server supervisor nginx
Давайте разберем, что есть что:
- gcc — компилятор C, C++, чего-то еще до кучи, определенно понадобится для сборки некоторых пакетов;
- python-setuptools — установка команды easy_install, понадобится только для установки virtualenv, дело в том, что из системных пакетов virtualenv устанавливается не последней версии, с чем возникает ряд раздражающих проблем;
- mysql-server — из названия ясно, что это MySQL-сервер, понадобится нам, раз мы собираемся поднимать сервер баз данных на хосте веб-приложения;
- libmysqlclient-dev — этот пакет понадобиться для того, чтобы собрать интерфейс доступа к MySQL для python;
- python-dev — API python’а, определенно понадобится для сборки некоторых пакетов;
- supervisor — это программа — контроллер демонов, понадобится для приручения веб-сервера и, возможно, ряда других программ;
- nginx — веб-сервер nginx, выражаю свою признательность Игорю Сысоеву;
- rabbitmq-server — необязательно, AMQP-сервер, пригодится, если потребуется использовать celery;
- memcached — необязательно, известная реализация кеша в оперативной памяти;
- git-core — необязательно, клиент для системы контроля версий git, потребуется, если нужные пакеты хранятся в git-репозитории;
- mercurial — необязательно, клиент для системы контроля версий mercurial (hg), потребуется, если нужные пакеты хранятся в mercurial-репозитории.
Развертывание проекта
Для развертывания воспользуемся виртуальным окружением, при помощи инструмента virtualenv.
В предыдущей главе мы установили полезную утилиту easy_install, с помощью которой установим теперь virtualenv последней версии:
sudo easy_install virtualenv
Примечание. Я намеренно не ставил pip глобально, чтобы не было случайных конфликтов с ним у pip’ов в виртуальных окружениях.
Теперь можно приступить к развертыванию проекта. Для начала нужно разместить его где-то в домашней директории, пусть это будет:
/home/myuser/web/myproject
Я пользуюсь системой контроля версий git. Но вы можете добиться этого простым копированием по SCP. В Windows можно использовать WinSCP, в линуксах файловые менеджеры поддерживают формат адреса sftp://myuser@1.2.3.4, как вы наверное догадались, в качестве аутентификационных используются данные для доступа по SSH.
В моем проекте в корне лежит файл для сборки виртуального окружения — build_env.sh:
#!/bin/bash echo $0: Creating virtual environment virtualenv --prompt="<myenv>" ./env mkdir ./logs mkdir ./pids mkdir ./db mkdir ./static_content mkdir ./static_content/media echo $0: Installing dependencies source ./env/bin/activate export PIP_REQUIRE_VIRTUALENV=true ./env/bin/pip install --requirement=./requirements.conf --log=./logs/build_pip_packages.log echo $0: Making virtual environment relocatable virtualenv --relocatable ./env echo $0: Creating virtual environment finished.
и файл requirements.conf, который содержит пакеты, необходимые для работы приложения:
django git+git://github.com/sehmaschine/django-grappelli.git#egg=django-grappelli git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt git+git://github.com/krvss/django-social-auth.git#django-social-auth git+git://github.com/gabrielhurley/django-wymeditor.git#django-wymeditor git+git://github.com/jtauber/django-mailer.git#django-mailer git+git://github.com/tweepy/tweepy.git#tweepy django-celery django-debug-toolbar django-pdb python-memcached MySQL-python xlrd unidecode anyjson gunicorn pillow south fabric requests xlwt
Это возможный набор пакетов, как-нибудь расскажу подробнее про некоторые из них, но мы не углубляемся в аспекты разработки в этой теме.
Итак, после запуска в папке проекта /home/myuser/web/myproject:
./build_env.sh
устанавливается виртуальное окружение для работы нашего сервера.
Теперь нужно позаботиться о создании базы данных. В наших проектах мы используем MySQL. Запускаем консоль MySQL:
mysql -uroot -pROOTPASSWORD
где создаем базу и пользователя:
CREATE DATABASE myproject CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE USER 'myproject'@'localhost' IDENTIFIED BY 'USERPASSWORD'; GRANT ALL PRIVILEGES ON myproject.* TO ‘myproject'@'localhost';
теперь настройки доступа можно внести в файл настроек проекта (settings.py или local_settings.py).
Если у вас есть дамп базы — вы знаете, что делать. Если нет, то создаем в ней схему и необходимые данные:
cd ~/web/myproject # возвращаемся в папку проекта source env/bin/activate # активируем виртуальное окружение python manage.py syncdb # синхронизируем модели с базой данных
теперь соберем статические файлы:
python manage.py collectstatic
На этом приложение готово к запуску.
Настройка веб-сервера Nginx
Для настройки веб-сервера Nginx нужно разместить конфиг myproject.conf (суффикс должен быть .conf) в папке /etc/nginx/sites-available/.
Создать и отредактировать файл можно в консоле SSH через nano:
sudo nano /etc/nginx/sites-available/myproject.conf
затем вставляем содержимое примера ниже (Shift+Insert), исправляем под свои нужды, сохраняем (Ctrl+O), выходим (Ctrl+X).
Пример содержания файла myproject.conf:
upstream myproject.ru { server localhost:12345 fail_timeout=0; } server { listen 80; server_name www.myproject.ru; rewrite ^/(.*) http://myproject.ru/$1 permanent; } server { listen 80; client_max_body_size 4G; server_name myproject.ru; access_log /home/myuser/web/myproject/logs/myproject.access.log; keepalive_timeout 5; root /home/myuser/web/myproject/static_content; location / { proxy_pass http://myproject.ru; } error_page 500 502 503 504 /500.html; location = /500.html { root /home/myuser/web/myproject/static_content/static/html; } location ~ ^/(static|media)/ { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; if (!-f $request_filename) { proxy_pass http://myproject.ru; break; } } }
Попробуем разобраться в общих словах, что здесь к чему.
В данном примере upstream — сокет localhost:12345, в который будем пересылать все запросы, которые не удовлетворяют следующим url:
/static/* — статические файлы сайта;
/media/* — медиа-файлы, файлы, которые создаются в процессе функционирования сайта;
На этом сокете мы повесим на прослушивание наш gunicorn в следующей части статьи. Имя апстрима, теоретически, выбирается произвольно, однако я сталкивался с проблемами, в случае, если имя апстрима отличалось от доменного имени сайта (не помню текста ошибок Django, чтобы описать подробнее).
Еще интересные части конфига:
редирект с поддомена www.myproject.ru на myproject.ru, можете сделать наоборот, если вам больше нравится;
обработка ошибок 5XX орагнизована выдачей статического файла 500.html. Получить такой файл довольно просто: заставить сайт показать страницу 404, сохранить в браузере как 500.html и отредактировать текст ошибки;
в случае, если статический файл не найден, запрос направляется gunicorn’у, чтобы тот мог выдать стандартную ошибку 404.
После того, как файл конфига размещен где следует (можно проверить командой cat /etc/nginx/sites-available/myproject.conf), нужно проставить на него симлинк:
sudo ln -s /etc/nginx/sites-available/myproject.conf /etc/nginx/sites-enabled/
и перезапустить nginx:
sudo service nginx restart
Настройка gunicorn и supervisor
При развертывании проекта мы установили пакет gunicorn, теперь мы используем его для формирования динамичеких HTTP-ответов (HTTP-response) Django-приложением. Сам gunicorn умеет принимать запросы и формировать ответы на них, однако нужно поддерживать сам gunicorn запущенным, например стартовать при перезапуске системы, это мы поручим специализирующейся в этом программе supervisor.
Заметьте, что разработчики gunicorn крайне не рекомендуют ставить его на линию фронта, а поручить прием запросов от пользователей специализированным серверам, например nginx, как это делаем мы.
Итак, создаем в папке /etc/supervisor/conf.d/ файл myproject.conf следующего содержания:
[program:myproject] command=/home/myuser/web/myproject/env/bin/python /home/myuser/web/myproject/src/myproject/manage.py run_gunicorn --bind=localhost:12345 --workers=3 --pid=/home/myuser/web/myproject/pids/gunicorn.pid --log-file /home/myuser/web/myproject/logs/gunicorn.log directory=/home/myuser/web/myproject/src/myproject umask=022 autostart=true autorestart=true startsecs=10 startretries=3 exitcodes=0,2 stopsignal=TERM stopwaitsecs=10 user=myuser
Заметьте, что в параметрах gunicorn’у мы передаем для прослушки тот же порт (в нашем примере 12345), что указывали в конфиге nginx’а. Количество рабочих процессов установлено в значение 3, подбирал этот параметр субъективно для одного из сайтов, исходя из своих нагрузок, и пока не могу порекомендовать какое-либо значение.
После того как конфиг размещен в нужной папке (можно проверить запуском cat /etc/supervisor/conf.d/myproject.conf) нужно перечитать файл либо просто перезапустить supervisor, я использую второй вариант для надежности:
sudo supervisorctl reload
проверить успешность запуска можно командой:
sudo supervisorctl status
в случае успеха статус процесса myproject через несколько секунд станет RUNNING.
Устранение проблем
perl: warning: Setting locale failed. perl: warning: Please check that your locale settings:
решается добавлением правильной локали:
locale-gen ru_RU.UTF8
по мотивам: http://askubuntu.com/questions/76013/how-do-i-add-locale-to-ubuntu-server
sudo: must be setuid root
решается например так:
chmod 4755 /usr/bin/sudo
libc6-dev : Depends: libc6 (= 2.15-0ubuntu10.2) but 2.15-0ubuntu10+openvz0 is to be installed E: Unable to correct problems, you have held broken packages.
Для ее решения достаточно модифицировать файл /etc/apt/preferences.d/99ovz-libc-pin:
заменив
libc-bin libc6
на
libc-bin libc6 libc6-dev libc-dev-bin
Couldn't open /dev/null: Permission denied
решал так:
sudo chmod 666 /dev/null
не знаю, насколько это корректно, но я опасностей не увидел.
Заключение
Отметим положительные моменты такого развертывания:
- Развертывание решения на VPS, виртуальная машина дает практически неограниченные возможности в администрировании.
- Независимость nginx от gunicorn, как это часто предлагается при использовании Apache и mod_python, например. В частности довольно легко подменить, например для отладки, gunicorn разработческим сервером:
sudo supervisorctl stop myproject python manage.py runserver localhost:12345 # из папки с исходниками
теперь nginx будет передавать запросы на сервер разработчика, даже не узнав про изменения.
- Nginx в качестве раздавальщика статических файлов признан одним из лучших, может даже лучшим.
- virtualenv позволяет легко и непринужденно изолировать виртуальные окружения разных проектов друг от друга. В наше время издержки дискового пространства несравнимо дешевле возни с конфликтами версий пакетов.
- gunicorn под контролем supervisor значительно удобнее и надежнее способов запуска gunicorn под контролем скриптов в /etc/init.d/ и некоторых других способов запуска, так как дает способ мониторинга запущенных программ, заботливо перезапускает программы в случае сбоев.
В сатье расмотрен лишь один из множества вариантов развертывания Django-приложения, я пришел к нему путем многих проб и ошибок. Мои рекомендации не претендуют на истину в последней инстанции. Более того, буду рад любой конструктивной критике.
Полезные ссылки
- FirstVDS — дешевый VPS-хостинг, по ссылке заказ на четверть дешевле.
- Putty и Kitty — SSH-клиенты под Windows.
- WinSCP — SCP-клиент под Windows, не нужно поднимать FTP-сервер, просто используйте имеющийся SSH-аккаунт.
- KeePassX — утилита хранения паролей, кроссплатформенная.
- Ubuntu LTS — политика выпусков релизов Ubuntu Long Term Support.
- Ubuntu Security — настройка для параноиков для десктопа, но что-то можно почерпнуть для сервера.
- Django Deployement — другие способы развертывания сайтов на Django.
- virtualenv — использование virtualenv.
- Nginx — много интересного о настройке nginx.
- Supervisor+gunicorn — об использовании gunicorn через nginx.
ссылка на оригинал статьи http://habrahabr.ru/post/159575/
Добавить комментарий