django

Django на production. uWSGI + nginx. Подробное руководство

  • вторник, 17 июня 2014 г. в 03:10:45
http://habrahabr.ru/post/226419/

Перед вами руководство по настройке production окружения для Django. Здесь будут описаны необходимые шаги по настройке Django, uWSGI и nginx. Руководство охватывает все три компонента — полный стек серверного ПО для веб-приложений.

Подразумевается, что вы используете Unix-подобную операционную систему и менеджер пакетов, эквивалентный aptitude. Найти эквивалент aptitude почти для любой операционной системы, в том числе и для Mac OS X, для вас не составит никакого труда.

Руководство написно для версий Django 1.4 или выше. Если вы используете более раннюю версию, то вам придется самостоятельно найти wsgi модуль для нее. Также вы заметите, что файловая структура проекта будет немного отличаться от представленной здесь.

Общая идея


Веб-сервер может по запросу отдавать пользователям файлы из своей файловой системы, однако он не может напрямую работать с Djangо приложениями. Веб-серверу нужен интерфейс, который будет запускать Django приложение, передавать ему запрос от пользователя и возвращать ответ.

Для выполнения этих задач был разработан Web Server Gateway Interface — WSGI — стандарт взаимодействия Python программ и веб-сервра.

uWSGI — одна из реализаций WSGI. В этом руководстве мы установим и настроим uWSGI для создания Unix сокета и взаимодействия с веб-сервером по протоколу WSGI.

Полный стек компонентов будет выглядеть следующим образом:
Пользователь <-> Веб-сервер <-> Сокет <-> uwsgi <-> Django

Перед установкой uWSGI


virtualenv


Создадаем и активируем виртуальное окружение для софта, который нам будет необходим (ниже я расскажу, как установить uwsgi глобально):
virtualenv uwsgi-tutorial
cd uwsgi-tutorial
source bin/activate

Django


Устонавливаем Django в наше виртуальное окружение:
pip install Django

Создаем новый проект и переходим в его корневую папку:
django-admin.py startproject mysite
cd mysite

Домен и порт


В этом руководстве мы будем использовать для нашего учебного проекта домен yourserver.com. Вам нужно будет заменить его на собственное доменное имя или IP адрес вашего сервера.

Для получения запросов от пользователей мы будем использовать порт 8000. Вы можете использовать любой другой порт. Я выбрал именно 8000, потому что его использование не приведет к конфликтам с другими задачами, выполняемыми сервером.

Установка и базовая настройка uWSGI


Установка uWSGI в виртуальное окружение


Один из хороших способов установить uWSGI:
pip install uwsgi

Нам понадобятся Python development пакеты. Если вы используете Debian или основнную на Debian операционную систему (например, Ubuntu или Mint), вам нужно установить пакет 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

Запускаем uWSGI:
uwsgi --http :8000 --wsgi-file test.py

Опции:
  • http: 8000: используется протокол http и порт 8000
  • wsgi-file test.py: uwsgi загрузит определенный файл (в нашем случае test.py)

В браузере переходим по адресу http://yourserver.com:8000.
Видим: «Hello, world», значит, мы все сделали правильно и следующие компоненты работают:
Пользователь <-> uWSGI <-> test.py

Проверка работы Django приложения


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

Запускаем только что созданный проект mysite:
python manage.py runserver 0.0.0.0:8000

Запускаем uWSGI следующим образом:
uwsgi --http :8000 --module mysite.wsgi

  • module mysite.wsgi: uwsgi загрузит модуль mysite.wsgi

В браузере переходим по адресу http://yourserver.com:8000.
Видим стартовую страницу Djangо, значит, мы все сделали правильно и следующие компоненты работают:
Пользователь <-> uWSGI <-> Django


Это нехорошо, что комьютер пользователя на прямую обращается к uWSGI. Между пользователем и uWSGI должен находиться веб-сервер.

Устновка и базовая настройка nginx


Установка и запуск nginx


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

Чтобы проверить, что nginx установлен и запущен, перейдите по адресу http://yourserver.com:80. Если вы видите сообщение “Welcome to nginx!”, значит, все окей и следующие компоненты работают:
Пользователь <-> Веб-сервер

Если у вас занят восьмидесятый порт, измените конфигурацию nginx так, чтобы он использовал какой-нибудь другой (в этом руководстве nginx будет использовать порт 8000).

Конфигурация nginx для работы с Django


Нам понадобится файл uwsgi_params, который можно взять здесь: github.com/nginx/nginx/blob/master/conf/uwsgi_params.
Скачиваем его в корневую папку нашего проекта.

Создаем файл mysite_nginx.conf:
# mysite_nginx.conf

upstream django {
    # server unix:///path/to/your/mysite/mysite.sock; # взаимодействие с uwsgi через Unix-сокет (мы воспользуемся этим вариантом позже) 
    server 127.0.0.1:8001; # взаимодействие с uwsgi через веб-порт 
}

# конфигурация веб-сервера
server {
    # порт, который будет слушать веб-сервер в ожидании запросов от пользователй
    listen      8000;
    # доменное имя
    server_name     yourserver.com; # замените на собственный домен или IP адрес
    charset     utf-8;

    # максимальный размер загружаемых на сервер данных
    client_max_body_size 75M;  

    # обслуживание медиа файлов и статики
    location /media  {
        alias /path/to/your/mysite/media;  # расположение медиафайлов (при необходимости измените)
    }

    location /static {
        alias /path/to/your/mysite/static;  # расположение статики (при необходимости измените)

    }

    # Остальные запросы перенаправляются в Django приложение
    location / {
        uwsgi_pass  django;
        include     /path/to/your/mysite/uwsgi_params; # файл uwsgi_params, который мы только что взяли с github
    }
}

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

В папке /etc/nginx/sites-enabled создаем ссылку на файл mysite_nginx.conf, чтобы nginx увидел его:
sudo ln -s ~/path/to/your/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/

Статика в одном месте


Перед запуском nginx поместим всю статику в папку static. Для этого добавляем в файл mysite/settings.py следующую строку:
STATIC_ROOT = os.path.join(BASE_DIR, "static/")

И выполняем команду:
python manage.py collectstatic

Проверка осблуживания статики и медиа


Перезапускаем nginx:
sudo /etc/init.d/nginx restart

Помещаем файл с именем, например, media.png в папку /path/to/your/project/project/media.

В браузере переходим по адресу http://yourserver.com:8000/media/media.png и, если видим наш файл, значит мы все сделали правильно.

nginx + uWSGI + test.py


Настраиваем взаимодействие nginx и test.py через uSWGI.
uwsgi --socket :8001 --wsgi-file test.py

Почти то же самое, что мы сделали недавано, за исключением одной опции:
  • socket :8001: используем протокол uWSGI, порт 8001

Как вы помните, мы сконфигурировали nginx(файл mysite_nginx.conf) для работы с uWSGI через порт 8001.

Если перейти по адресу http://yourserver.com:8001, то мы ничего не увидим, поскольку браузер использует протокол http, а не uWSGI, однако uWSGI выведет сообщение о попытке соединения в терминал.

Unix сокеты вместо веб-портов


До этого мометна мы использовали сокет, привязанный к TCP порту (я называл его веб-порт), потому что так было проще, но на деле рекомендуется использовать Unix-сокет из-за преимущества в производительности.

Редактируем mysite_nginx.conf следующим образом:
server unix:///path/to/your/mysite/mysite.sock; # взаимодействие с uwsgi через Unix-сокет
# server 127.0.0.1:8001; # взаимодействие с uwsgi через веб-порт 

И перезапускаем nginx:
sudo /etc/init.d/nginx restart

Запускаем uWSGI:
uwsgi --socket mysite.sock --wsgi-file test.py

На этот раз опция socket указывает на файл.
Открываем в браузере http://yourserver.com:8000/

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


Проверьте лог ошибок nginx, скорее всего он находится в файле var/log/nginx/error.log

Если найдете там что-то похожее на
connect() to unix:///path/to/your/mysite/mysite.sock failed (13: Permission denied)

значит есть проблема с правами доступа к файлу mysite.sock. Необходимо сделать так, чтобы nginx имел разрешение на использование этого файла.

Попробуйте запустить uWSGI так:
uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=666 #много полномочий

Или так:
uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=664 #более разумно


Чтобы проблем с доступом в будущем не было, добавьте вашего пользователя в группу www-data.

Информация, которую uWSGI выводит в терминал, полезна при поиске и исправлении возможных ошибок или неисправностей.

nginx + uWSGI + Django


Запускаем:
uwsgi --socket mysite.sock --module mysite.wsgi --chmod-socket=664

В браузере переходим на http://yourserver.com:8000/ и видим стартовую страницу Django.
Пользователь <-> Веб-сервер <-> Сокет <-> uwsgi <-> Django

Мы собрали всю цепочку, но настройка еще не закончена, идем дальше.

Конфигурация uWSGI через ini файл


Очень удобно все опции, с которыми мы запускаем uWSGI, указать в ini файле, а при запуске передавать только путь к этому файлу.

Создаем файл mysite_uwsgi.ini:
#mysite_uwsgi.ini 
[uwsgi]

# Настройки, связанные с Django
# Корневая папка проекта (полный путь)
chdir           = /path/to/your/project
# Django wsgi файл
module          = project.wsgi
# полный путь к виртуальному окружению
home            = /path/to/virtualenv

# общие настройки
# master
master          = true
# максимальное количество процессов
processes       = 10
# полный путь к файлу сокета
socket          = /path/to/your/project/mysite.sock
# права доступа к файлу сокета
# chmod-socket    = 664
# очищать окружение от служебных файлов uwsgi по завершению
vacuum          = true

Запускаем uWSGI:
uwsgi --ini mysite_uwsgi.ini

Проверяем. Все работает? Дальше.

Устанавливаем uWSGI глобально


До сих пор uWSGI был установлен в виртуальном окружении. Чтобы была возможность автоматически запускать uWSGI при старте операционной системы, мы установим его глобально.

Деактивируем виртуальное окружение:
deactivate

Устанавливаем uwsgi:
sudo pip install uwsgi
# Или можно установить LTS (с долговременной поддержкой) версию
pip install http://projects.unbit.it/downloads/uwsgi-lts.tar.gz

На вики странице uWSGI описано несколько вариантов установки. Перед тем, как установить uWSGI глобально, вам не помешает определиться с выбором версии и методом установки.

Запусить uWSGI можно той же командой, что и раньше:
uwsgi --ini mysite_uwsgi.ini

Режим Emperor


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

Если один из конфигурационных файлов будет изменен, uWSGI перезапустит соответствующего вассала.

Создаем папку для конфигурационных файлов:
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals

Создаем в ней ссылку на mysite_uwsgi.ini:
sudo ln -s /path/to/your/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/

Запускаем uWSGI в режиме Emperor:
sudo uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

Опции:
  • emperor: папка с конфигурациолнными файлами
  • uid: id пользователя, от имени которого будет запущен процесс
  • gid: id группы, от имени которой будет запущен процесс

Проверяем. http://yourserver.com:8000/

Автоматичесеий запуск uWSGI после загрузки операционной системы


В файл /etc/rc.local, перед строкой “exit 0” добавляем:
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

Дело сделано.