Развертывание Django с помощью gunicorn и nginx

81

Это широкий вопрос, но хотелось бы получить канонический ответ. Я пытался развернуть сайт с помощью gunicorn и nginx в Django . Прочитав тонны руководств, я добился успеха, но не могу быть уверен, что шаги, которые я выполнил, достаточно хороши для запуска сайта без проблем или, может быть, есть способы сделать это лучше. Эта неуверенность раздражает.

Вот почему я ищу очень подробный и хорошо объясненный ответ для новичков. Я не хочу слишком много объяснять, что я знаю и чего не знаю, поскольку это может немного исказить ответы, и другие люди могут в меньшей степени извлечь выгоду из ваших ответов. Однако я хотел бы упомянуть о некоторых вещах:

  • Какая «установка» работает лучше всего? Я использовал virtualenv и переместил свой проект Django в эту среду, однако я видел другие настройки, в которых есть папка для виртуальных сред и другие папки для проектов.

  • Как я могу настроить вещи таким образом, чтобы на одном сервере можно было разместить несколько сайтов?

  • Почему одни предлагают использовать, gunicorn_django -b 0.0.0.0:8000а другие - gunicorn_django -b 127.0.0.1:8000? Я тестировал последний на инстансе Amazon EC2, но он не работал, а первый работал без проблем.

  • Какова логика конфигурационного файла nginx? Существует так много руководств, в которых используются совершенно разные файлы конфигурации, что я не понимаю, какой из них лучше. Например, одни люди используют alias /path/to/static/folderи другие root /path/to/static/folder. Может быть, вы можете поделиться своим предпочтительным файлом конфигурации.

  • Почему мы создаем символическую ссылку между site-availableи sites-enabledвнутри /etc/nginx?

  • Как всегда, приветствуются некоторые передовые практики :-)

благодаря

Роберт Смит
источник
Не могли бы вы опубликовать пример на git относительно этих nginx и gunicorn / uwsgi. Он будет более полезен для новых учеников, таких как я.
Шива
@Shiva На самом деле ответ miki725 содержит очень полный образец файла конфигурации. Если вам нужно очень подробное представление о том, что происходит с nginx, я рекомендую вам <a href=" amazon.com/Nginx-HTTP-Server-Cl%C3%A9ment-Nedelcu/dp/… книгу</a>. интеграция gunicorn очень просто Он изложен <a href=" docs.djangoproject.com/en/dev/howto/deployment/wsgi/gunicorn/...>.
Роберт Смит

Ответы:

106

Какая «установка» работает лучше всего? Я использовал virtualenv и переместил свой проект django в эту среду, однако я видел другие настройки, в которых есть папка для виртуальных сред и другие для проектов.

virtualenv - это способ изолировать среды Python; как таковой, он не играет большой роли при развертывании, однако во время разработки и тестирования это требование, если не настоятельно рекомендуется.

Ценность virtualenv заключается в том, что он позволяет вам убедиться, что для приложения установлены правильные версии библиотек. Так что неважно, куда вы вставите саму виртуальную среду. Просто убедитесь, что вы не включаете его как часть системы управления версиями исходного кода.

Структура файловой системы не критична. Вы увидите множество статей, восхваляющих достоинства макетов каталогов и даже скелетных проектов, которые вы можете клонировать в качестве отправной точки. Я считаю, что это больше личное предпочтение, чем жесткое требование. Конечно, приятно иметь; но если вы не знаете почему , это не добавляет ценности вашему процессу развертывания - так что не делайте этого, потому что какой-то блог рекомендует это, если это не имеет смысла для вашего сценария. Например, нет необходимости создавать setup.pyфайл, если у вас нет частного сервера PyPi, который является частью вашего рабочего процесса развертывания.

Как я могу настроить вещи таким образом, чтобы на одном сервере можно было разместить несколько сайтов?

Чтобы настроить несколько сайтов, вам нужно сделать две вещи:

  1. Сервер, который прослушивает общедоступный IP-адрес через порт 80 и / или порт 443, если у вас есть SSL.
  2. Куча «процессов», которые запускают реальный исходный код django.

Люди используют nginx для №1, потому что это очень быстрый прокси и он не требует накладных расходов на такой комплексный сервер, как Apache. Вы можете использовать Apache, если вам это удобно. Нет требования, что «для нескольких сайтов используйте nginx»; вам просто нужна служба, которая прослушивает этот порт, знает, как перенаправить (прокси) на ваши процессы, на которых выполняется фактический код django.

Для №2 есть несколько способов запустить эти процессы. gevent / uwsgi - самые популярные. Единственное, что здесь следует помнить, это не использовать сервер запуска в продакшене .

Это абсолютный минимум требований. Обычно люди добавляют своего рода диспетчер процессов для управления всеми запущенными «серверами django» (№2). Здесь вы увидите upstartи supervisorупомянули. Я предпочитаю супервизора, так как ему не нужно брать на себя всю систему (в отличие от выскочки). Однако, повторюсь - это несложное требование . Вы можете отлично запустить несколько screenсеансов и отсоединить их. Обратной стороной является то, что при перезапуске сервера вам придется перезапустить сеансы экрана.

Лично я бы рекомендовал:

  1. Nginx для №1
  2. Сделайте выбор между uwsgi и gunicorn - я использую uwsgi.
  3. супервизор для управления внутренними процессами.
  4. Индивидуальные системные учетные записи (пользователи) для каждого приложения, которое вы размещаете.

Причина, по которой я рекомендую №4, - изолировать разрешения; опять же, не требование.

Почему некоторые люди предлагают использовать gunicorn_django -b 0.0.0.0:8000, а другие - gunicorn_django -b 127.0.0.1:8000? Я тестировал последний на инстансе Amazon EC2, но он не работал, а первый работал без проблем.

0.0.0.0означает «все IP-адреса» - это мета-адрес (то есть адрес-заполнитель). 127.0.0.1зарезервированный адрес, который всегда указывает на локальный компьютер. Вот почему он называется «localhost». Он доступен только для процессов, запущенных в одной системе.

Обычно у вас есть внешний сервер (№1 в списке выше), который прослушивает общедоступный IP-адрес. Вы должны явно привязать сервер к одному IP-адресу .

Однако, если по какой-то причине вы используете DHCP или не знаете, какой будет IP-адрес (например, это недавно подготовленная система), вы можете указать nginx / apache / любому другому процессу для привязки 0.0.0.0. Это должна быть временная временная мера .

Для производственных серверов у вас будет статический IP-адрес. Если у вас динамический IP (DHCP), то можете оставить 0.0.0.0. Однако очень редко у вас есть DHCP для ваших производственных машин.

Привязка gunicorn / uwsgi к этому адресу в производстве не рекомендуется . Если вы привяжете свой внутренний процесс (gunicorn / uwsgi) к нему 0.0.0.0, он может стать доступным «напрямую», минуя ваш внешний прокси (nginx / apache / etc); кто-то может просто запросить http://your.public.ip.address:9000/и получить доступ к вашему приложению напрямую, особенно если ваш интерфейсный сервер (nginx) и ваш внутренний процесс (django / uwsgi / gevent) работают на одном компьютере .

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

Какова логика конфигурационного файла nginx? Существует так много руководств, в которых используются совершенно разные файлы конфигурации, что я не понимаю, какой из них лучше. Например, некоторые люди используют «псевдоним / путь / к / статической / папке», а другие «корень / путь / к / статической / папке». Может быть, вы можете поделиться своим предпочтительным файлом конфигурации.

Первое, что вам следует знать о nginx, это то, что это не веб-сервер, такой как Apache или IIS. Это прокси. Таким образом, вы увидите разные термины, такие как «восходящий» / «нисходящий» и несколько «серверов». Найдите время и сначала просмотрите руководство по nginx.

Есть много разных способов настроить nginx; но вот один ответ на вопрос о aliasVS. root. root- явная директива, связывающая корень документа («домашний каталог») nginx. Это каталог, в который он будет смотреть, когда вы дадите запрос без пути, напримерhttp://www.example.com/

aliasозначает «сопоставить имя с каталогом». Каталоги с псевдонимами не могут быть подкаталогом корня документа.

Зачем мы создаем символическую ссылку между доступными и доступными сайтами в / etc / nginx?

Это что-то уникальное для debian (и подобных ему систем, таких как ubuntu). sites-availableперечисляет файлы конфигурации для всех виртуальных хостов / сайтов в системе. Символическая ссылка с sites-enabledна sites-available«активирует» этот сайт или виртуальный хост. Это способ разделения файлов конфигурации и простого включения / отключения хостов.

Бурхан Халид
источник
1
Отличный ответ! Уточнено много вопросов. Можете ли вы подробнее рассказать (или добавить пример), что вы имеете в виду, явно привязывая сервер к IP-адресу, и что привязка gunicorn / uwsgi должна быть привязана к 0.0.0.0? К сожалению, я так и делал. Благодаря!
Роберт Смит
7
Типичный компьютер будет иметь как минимум два IP-адреса: 127.0.0.1и тот, который назначен ему сетью; это минимум - ваша машина может иметь несколько интерфейсов и несколько IP-адресов. Вы должны настроить свой веб-сервер (или любой другой процесс); прослушивать один IP-адрес - это то, что я подразумеваю под явным. Когда вы привязываетесь к 0.0.0.0, вы говорите программе прослушивать все IP-адреса, включая любые новые, которые могут быть назначены вашей машине . Это не очень хорошая практика по разным причинам (одна из которых - безопасность).
Бурхан Халид
Понял. Я уже правильно настроил Gunicorn. Большое спасибо!
Роберт Смит
nginx может обслуживать статический контент.
Marcin
как сервер узнает, в каком файле мы настроили адрес сервера/etc/nginx/sites-enabled
Шива
11

Я не гуру по развертыванию, но поделюсь некоторыми из моих практик развертывания Django с gevent (хотя должен быть похож на gunicorn).

virtualenvотлично по причинам, в которые я не буду вдаваться. Однако я нашел virtualenv-wrapper( docs ) очень полезными, особенно когда вы работаете над многими проектами, поскольку они позволяют легко переключаться между различными виртуальными файлами. На самом деле это не относится к среде развертывания, однако, когда мне нужно устранить неполадки на сервере с помощью SSH, я нашел это очень полезным. Еще одним преимуществом его использования является то, что он управляет каталогом virtualenv, поэтому для вас меньше ручной работы. Virtualenvs предназначены для одноразового использования, поэтому в случае возникновения проблем с версией или любых других проблем с установкой вы можете просто сбросить env и создать новый. В результате рекомендуется не включать какой-либо код проекта в файл virtualenv. Его следует хранить отдельно.

Что касается настройки нескольких сайтов, virtualenvэто в значительной степени ответ. У вас должен быть отдельный вирус для каждого проекта. Одно только это может решить многие проблемы. Затем, когда вы развертываете, другой процесс Python будет запускать разные сайты, что позволяет избежать любых возможных конфликтов между развертываниями. Один инструмент, который я особенно считаю очень полезным для управления несколькими сайтами на одном сервере, - это supervisor( docs). Он предоставляет простой интерфейс для запуска, остановки и перезапуска различных экземпляров Django. Он также может автоматически перезапускать процесс в случае сбоя или при запуске компьютера. Так, например, если возникает какое-то исключение и его ничто не улавливает, весь веб-сайт может упасть. Supervisor поймет это и автоматически перезапустит экземпляр Django. Ниже приведен пример конфигурации программы супервизора (отдельного процесса):

[program:foo]
command=/path/toviertualenv/bin/python deploy.py
directory=/path/where/deploy.py/is/located/
autostart=true
autorestart=true
redirect_stderr=True
user=www

Что касается Nginx, я знаю, что поначалу это может быть ошеломляющим. Я нашел книгу Nginx очень полезной. В нем объясняются все основные директивы nginx.

В моей установке nginx я обнаружил, что лучше всего настраивать только основные конфигурации в nginx.confфайле, а затем у меня есть отдельная папка, в sitesкоторой я храню конфигурации nginx для каждого из сайтов, которые я размещаю. Затем я просто включаю все файлы из этой папки в основной файл конфигурации. Использую директиву include sites/+*.conf;. Таким образом, он включает только файлы, начинающиеся с +символа в sitesпапке. Таким образом, просто по имени файла я могу контролировать, какие файлы конфигурации должны быть загружены. Поэтому, если я хочу отключить определенный сайт, мне просто нужно переименовать файл конфигурации и перезапустить nginx. Не совсем уверен, что вы имели в виду под «символической ссылкой между доступными и доступными сайтами в / etc / nginx» в своем вопросе, поскольку это папки с именем Apache, но они выполняют аналогичную задачу, что и includeдиректива.

Что касается rootи aliasдиректив, они почти так же , за исключением того, где вычисляются корень их. In alias, что бы ни в locationin упало, а в root в нем нет. Изображение, что у вас есть следующая конфигурация nginx:

location /static {
    alias /some/path/;
}
location /static2 {
    root /some/other/path/;
}

Если пользователь перейдет по этим URL-адресам, то nginx попытается найти файлы в следующих местах системы:

/static/hello/world.pdf => /some/path/hello/world.pdf
/static2/hello/world.pdf => /some/other/path/static2/hello/world.pdf

Это простая конфигурация для сайта nginx:

server {
    server_name .foodomain.com;
    listen 80;

    access_log logs/foodomain.log;

    gzip                on;
    gzip_http_version   1.0;
    gzip_comp_level     2;
    gzip_proxied        any;
    gzip_min_length     1100;
    gzip_buffers        16 8k;
    gzip_types          text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    # Some version of IE 6 don't handle compression well on some mime-types, so just disable for them
    gzip_disable "MSIE [1-6].(?!.*SV1)";

    # Set a vary header so downstream proxies don't send cached gzipped content to IE6
    gzip_vary on;

    location / {
        proxy_read_timeout      30s;
        proxy_pass              http://localhost:8000;
        proxy_set_header        Host                 $host;
        proxy_set_header        User-Agent           $http_user_agent;
        proxy_set_header        X-Real-IP            $remote_addr;
    }

    location /media {
        alias   /path/to/media/;
        expires 1y;
    }

    location /static {
        autoindex on;
        expires   1y;
        alias     /path/to/static/;
    }

     location /favicon.ico {
        alias /path/to/favicon.ico;
    }
}

Надеюсь, это вам немного поможет.

miki725
источник
Собственно, ваш ответ очень помогает! Супервайзер звучит великолепно, и это одна из немногих вещей, по которым блоггеры, похоже, достигли консенсуса. Отличный совет по виртуальному окружению и его оболочке. У меня возникло искушение добавить к этому миксу virtualenv-wrapper, но я не хотел излишне усложнять этот вопрос. Что касается доступности и поддержки сайтов, nginx содержит эти каталоги. Где вы создаете файл конфигурации для nginx? Внутри вашего проекта Django?
Роберт Смит
Лично у меня они есть в папке config nginx. В моем случае это так /usr/local/nginx/config/sites. Однако не уверен, правильный это или лучший метод. Причина, по которой я сохраняю их там, заключается в том, что если я выношу его, то каким-то образом мне придется включить его в nginx, либо вручную включив includeдирективу, либо создав символические ссылки. В любом случае это ручной труд, поэтому я просто храню его в главном месте конфигурации.
miki725
Я читаю книгу, которую вы порекомендовали :-) Это здорово, и, как вы помните, /sites/*.conf - один из предлагаемых способов сделать это. В любом случае, спасибо за ответ.
Роберт Смит
Пожалуйста. Один раздел о книге, который мне не очень пригодился, - это то, как использовать Django с nginx. Книга рекомендует использовать fastcgi, что не так удобно, как использование прокси-доступа. Так что вы можете пропустить Главу 6.
miki725
Я только что дочитал книгу. Здорово. На самом деле я прочитал главу 6, потому что хотел узнать, как работает fastcgi, но вы правы ... это было не очень полезно. Благодаря!
Роберт Смит
2

Что касается передового опыта, который вы задали в своем вопросе, я не могу не поделиться инструментом, который в буквальном смысле творит чудеса для меня! Сам я запутался в нескольких конфигурационных файлах gunicorn, nginx, supervisorD для нескольких сайтов! Но мне очень хотелось как-то автоматизировать весь процесс, чтобы я мог внести изменения в свое приложение / сайт и мгновенно развернуть его. Имя ему - джанго-фагунги. Вы можете найти подробности моего опыта работы с автоматизации развертывания Django здесь . Я только что настроил fabfile.py ОДИН РАЗ (django-fagungis использует ткань для автоматизации всего процесса и делает virtualenv на вашем удаленном сервере, что ОЧЕНЬ удобноуправлять зависимостями нескольких сайтов, размещенных на одном сервере. Он использует nginx, gunicorn и supervisorD для обработки проекта / развертывания сайта Django), а django-fagungis клонирует мой последний проект из bitbucket (который я использую для подрывной деятельности) и развертывает его на моем удаленном сервере, и мне просто нужно ввести три команды в оболочке моей локальной машины и что это !! Для меня это оказалось лучшей практикой развертывания Django без лишних хлопот.

Али Раза Баяни
источник
Благодаря!. Я посмотрю на это.
Роберт Смит