Wdrażanie Django za pomocą gunicorn i nginx

81

To szerokie pytanie, ale chciałbym uzyskać odpowiedź kanoniczną. Próbowałem wdrożyć witrynę za pomocą gunicorn i nginx w Django . Po przeczytaniu mnóstwa samouczków odniosłem sukces, ale nie jestem pewien, czy kroki, które wykonałem, są wystarczająco dobre, aby uruchomić witrynę bez problemów, a może są na to lepsze sposoby. Ta niepewność jest irytująca.

Dlatego szukam bardzo szczegółowej i dobrze wyjaśnionej odpowiedzi dla początkujących. Nie chcę zbytnio wyjaśniać tego, co wiem, a czego nie, ponieważ może to nieco wypaczyć odpowiedzi, a inne osoby mogą w mniejszym stopniu skorzystać z Twoich odpowiedzi. Jednak niektóre rzeczy, o których chciałbym wspomnieć, to:

  • Która „konfiguracja” działa najlepiej? Użyłem virtualenv i przeniosłem projekt Django do tego środowiska, ale widziałem inne konfiguracje, w których jest folder dla środowisk wirtualnych i inny dla projektów.

  • Jak mogę skonfigurować rzeczy w sposób, który pozwala na hostowanie kilku witryn na jednym serwerze?

  • Dlaczego niektórzy sugerują używanie, gunicorn_django -b 0.0.0.0:8000a inni sugerują gunicorn_django -b 127.0.0.1:8000? Testowałem to drugie w instancji Amazon EC2, ale nie działało, podczas gdy pierwszy działał bez problemu.

  • Jaka jest logika pliku konfiguracyjnego nginx? Jest tak wiele samouczków wykorzystujących drastycznie różne pliki konfiguracyjne, że nie wiem, który z nich jest lepszy. Na przykład niektórzy używają, alias /path/to/static/foldera inni root /path/to/static/folder. Może możesz udostępnić swój preferowany plik konfiguracyjny.

  • Dlaczego tworzymy dowiązanie symboliczne między site-availablei sites-enabledw /etc/nginx?

  • Jak zwykle mile widziane są sprawdzone metody :-)

Dzięki

Robert Smith
źródło
Czy możesz opublikować na git przykład dotyczący tych nginx i gunicorn / uwsgi, który będzie bardziej przydatny dla nowych uczniów, takich jak ja.
Shiva,
@Shiva Właściwie odpowiedź miki725 zawiera bardzo kompletną próbkę pliku konfiguracyjnego. Jeśli chcesz bardzo dokładnego wprowadzenia na temat tego, co dzieje się z nginx, polecam <a href=" amazon.com/Nginx-HTTP-Server-Cl%C3%A9ment-Nedelcu/dp/… book</a>. integracja gunicorn jest bardzo prosta jest opisane <a href=" docs.djangoproject.com/en/dev/howto/deployment/wsgi/gunicorn/...>.
Robert Smith

Odpowiedzi:

106

Która „konfiguracja” działa najlepiej? Użyłem virtualenv i przeniosłem projekt django do tego środowiska, jednak widziałem inne konfiguracje, w których jest folder dla środowisk wirtualnych i inny dla projektów.

virtualenv to sposób na izolowanie środowisk Pythona; jako taka nie ma dużej roli do odegrania podczas wdrażania - jednak podczas programowania i testowania jest to wymóg, jeśli nie jest wysoce zalecany.

Wartość, jaką można uzyskać od virtualenv, polega na tym, że pozwala upewnić się, że zainstalowano poprawne wersje bibliotek dla aplikacji. Więc nie ma znaczenia, gdzie umieścisz samo wirtualne środowisko. Tylko upewnij się, że nie dołączasz go jako części systemu wersjonowania kodu źródłowego.

Układ systemu plików nie jest krytyczny. Zobaczysz wiele artykułów wychwalających zalety układów katalogów, a nawet szkieletowych projektów, które możesz sklonować jako punkt wyjścia. Czuję, że to bardziej osobiste preferencje niż trudne wymagania. Na pewno miło jest mieć; ale jeśli nie wiesz dlaczego , nie dodaje to żadnej wartości do procesu wdrażania - więc nie rób tego, ponieważ niektóre blogi to zalecają, chyba że ma to sens w Twoim scenariuszu. Na przykład - nie ma potrzeby tworzenia setup.pypliku, jeśli nie masz prywatnego serwera PyPi, który jest częścią przepływu pracy podczas wdrażania.

Jak mogę skonfigurować rzeczy w sposób, który pozwala na hostowanie kilku witryn na jednym serwerze?

Aby skonfigurować wiele witryn, musisz wykonać dwie czynności:

  1. Serwer, który nasłuchuje na publicznym adresie IP na porcie 80 i / lub porcie 443, jeśli masz SSL.
  2. Kilka "procesów", które wykonują rzeczywisty kod źródłowy django.

Ludzie używają nginx jako nr 1, ponieważ jest to bardzo szybki serwer proxy i nie wiąże się z kosztami kompleksowego serwera, takiego jak Apache. Możesz używać Apache, jeśli czujesz się z nim swobodnie. Nie ma wymogu, aby „w przypadku witryn wielopunktowych używać nginx”; potrzebujesz tylko usługi, która nasłuchuje na tym porcie, wie, jak przekierować (proxy) do procesów, w których działa rzeczywisty kod django.

W przypadku # 2 istnieje kilka sposobów rozpoczęcia tych procesów. gevent / uwsgi to najpopularniejsze. Jedyne, o czym należy pamiętać, to nie używać serwera uruchomieniowego w produkcji .

To są absolutnie minimalne wymagania. Zazwyczaj ludzie dodają pewnego rodzaju menedżera procesów, który kontroluje wszystkie działające "serwery django" (# 2). Tutaj zobaczysz upstarti supervisorwspomnisz. Wolę nadzorcę, ponieważ nie musi on przejmować całego systemu (w przeciwieństwie do upstartu). Jednak znowu - nie jest to trudny wymóg . Możesz doskonale uruchomić kilka screensesji i je wyłączyć. Wadą jest to, że jeśli serwer się zrestartuje, będziesz musiał ponownie uruchomić sesje ekranu.

Osobiście polecam:

  1. Nginx dla # 1
  2. Wybierz między uwsgi i gunicorn - ja używam uwsgi.
  3. kierownik ds. zarządzania procesami backendu.
  4. Indywidualne konta systemowe (użytkownicy) dla każdej hostowanej aplikacji.

Powodem, dla którego zalecam # 4, jest izolowanie uprawnień; znowu nie jest to wymóg.

Dlaczego niektórzy sugerują użycie gunicorn_django -b 0.0.0.0:8000, a inni sugerują gunicorn_django -b 127.0.0.1:8000? Testowałem to drugie w instancji Amazon EC2, ale nie działało, podczas gdy pierwszy działał bez problemu.

0.0.0.0oznacza „wszystkie adresy IP” - jest to adres meta (czyli adres zastępczy). 127.0.0.1to zarezerwowany adres, który zawsze wskazuje na komputer lokalny. Dlatego nazywa się to „localhost”. Jest osiągalny tylko dla procesów działających w tym samym systemie.

Zwykle serwer frontonu (nr 1 na powyższej liście) nasłuchuje na publicznym adresie IP. Państwo powinno wyraźnie wiążą serwera do jednego adresu IP .

Jeśli jednak z jakiegoś powodu korzystasz z DHCP lub nie wiesz, jaki będzie adres IP (na przykład jest to nowo zainicjowany system), możesz powiedzieć nginx / apache / jakiemukolwiek innemu procesowi, z którym ma się powiązać 0.0.0.0. Powinien to być tymczasowy środek zapobiegawczy .

W przypadku serwerów produkcyjnych będziesz mieć statyczny adres IP. Jeśli masz dynamiczny adres IP (DHCP), możesz go zostawić 0.0.0.0. Jednak bardzo rzadko będziesz mieć DHCP na swoich maszynach produkcyjnych.

Powiązanie gunicorn / uwsgi z tym adresem nie jest zalecane w produkcji. Jeśli powiążesz swój proces backendu (gunicorn / uwsgi) z 0.0.0.0, może on stać się dostępny „bezpośrednio”, z pominięciem frontendowego proxy (nginx / apache / etc); ktoś mógłby po prostu zażądać http://your.public.ip.address:9000/i uzyskać bezpośredni dostęp do Twojej aplikacji, zwłaszcza jeśli Twój serwer frontonu (nginx) i proces zaplecza (django / uwsgi / gevent) działają na tej samej maszynie .

Możesz to zrobić, jeśli nie chcesz mieć kłopotów z uruchamianiem frontowego serwera proxy.

Jaka jest logika pliku konfiguracyjnego nginx? Jest tak wiele samouczków wykorzystujących drastycznie różne pliki konfiguracyjne, że nie wiem, który z nich jest lepszy. Na przykład niektórzy używają „alias / ścieżka / do / statyczny / folder”, a inni „katalog główny / ścieżka / do / statyczny / folder”. Może możesz udostępnić swój preferowany plik konfiguracyjny.

Pierwszą rzeczą, którą powinieneś wiedzieć o nginx, jest to, że nie jest to serwer WWW, taki jak Apache lub IIS. To jest proxy. Zobaczysz więc różne terminy, takie jak „upstream” / „downstream” i definiowanych jest wiele „serwerów”. Poświęć trochę czasu i zapoznaj się najpierw z instrukcją nginx.

Istnieje wiele różnych sposobów konfiguracji nginx; ale tutaj jest jedna odpowiedź na swoje pytanie na aliaswersetach root. rootjest jawną dyrektywą, która wiąże katalog główny („katalog domowy”) nginx. To jest katalog, na który będzie patrzeć, gdy podasz żądanie bez ścieżki takiej jakhttp://www.example.com/

aliasoznacza „zamapuj nazwę na katalog”. Katalogi z aliasami mogą nie być podkatalogami katalogu głównego dokumentu.

Dlaczego w / etc / nginx tworzymy dowiązanie symboliczne między dostępnymi dla witryn a witrynami włączonymi?

Jest to coś unikalnego dla Debiana (i systemów podobnych do Debiana, takich jak ubuntu). sites-availablezawiera listę plików konfiguracyjnych dla wszystkich wirtualnych hostów / witryn w systemie. Dowiązanie symboliczne od sites-enableddo sites-available„aktywuje” tę witrynę lub hosta wirtualnego. Jest to sposób na oddzielenie plików konfiguracyjnych i łatwe włączanie / wyłączanie hostów.

Burhan Khalid
źródło
1
Świetna odpowiedź! Wiele pytań zostało wyjaśnionych. Czy możesz rozwinąć trochę więcej (lub dodać przykład) na temat tego, co masz na myśli, mówiąc wyraźnie o powiązaniu serwera z adresem IP, a powiązanie gunicorn / uwsgi powinno być przypisane do 0.0.0.0? Niestety myślę, że właśnie to robiłem. Dzięki!
Robert Smith
7
Typowy komputer będzie miał co najmniej dwa adresy IP: 127.0.0.1i ten, który jest mu przypisany przez sieć; to jest minimum - twój komputer może mieć wiele interfejsów i wiele adresów IP. Powinieneś skonfigurować swój serwer WWW (lub jakikolwiek inny proces); nasłuchiwać na jednym adresie IP - to właśnie mam na myśli mówiąc wprost. Kiedy łączysz się z 0.0.0.0, mówisz programowi, aby nasłuchiwał na wszystkich adresach IP, w tym na nowych, które mogą być przypisane do twojej maszyny . Nie jest to dobra praktyka z różnych powodów (jednym z nich jest bezpieczeństwo).
Burhan Khalid
Rozumiem. Skonfigurowałem już poprawnie Gunicorn. Dziękuję Ci bardzo!
Robert Smith
nginx może obsługiwać zawartość statyczną.
Marcin
skąd serwer miałby wiedzieć, w którym pliku skonfigurowaliśmy adres serwera w/etc/nginx/sites-enabled
Shiva
11

Nie jestem guru wdrażania, ale podzielę się kilkoma moimi praktykami dotyczącymi wdrażania Django z gevent (chociaż powinno być podobne do gunicorn).

virtualenvjest świetny z powodów, w które nie będę wchodził. Jednak virtualenv-wrapper( dokumentacja ) okazała się bardzo przydatna, zwłaszcza gdy pracujesz nad wieloma projektami, ponieważ umożliwia łatwe przełączanie się między różnymi virtualenvami. Nie dotyczy to tak naprawdę środowiska wdrożeniowego, jednak gdy muszę rozwiązywać problemy na serwerze za pomocą SSH, okazało się to bardzo przydatne. Kolejną zaletą korzystania z niego jest to, że zarządza katalogiem virtualenv, więc mniej pracy ręcznej dla Ciebie. Wirtualne env mają być jednorazowe, więc w przypadku problemów z wersją lub innymi problemami z instalacją możesz po prostu zrzucić środowisko i utworzyć nowy. W rezultacie najlepiej jest nie umieszczać żadnego kodu projektu w pliku virtualenv. Powinien być trzymany oddzielnie.

Jeśli chodzi o konfigurowanie wielu witryn, virtualenvjest prawie odpowiedzią. Powinieneś mieć oddzielny virutalenv dla każdego projektu. Samo to może rozwiązać wiele problemów. Następnie podczas wdrażania inny proces Pythona będzie uruchamiał różne witryny, co pozwala uniknąć ewentualnych konfliktów między wdrożeniami. Jednym z narzędzi, które szczególnie uważam za bardzo przydatne do zarządzania wieloma witrynami na tym samym serwerze, jest supervisor( docs). Zapewnia łatwy interfejs do uruchamiania, zatrzymywania i restartowania różnych instancji Django. Jest również zdolny do automatycznego ponownego uruchamiania procesu, gdy zakończy się niepowodzeniem lub podczas uruchamiania komputera. Na przykład, jeśli zostanie zgłoszony wyjątek i nic go nie złapie, cała witryna internetowa może ulec awarii. Nadzorca wykryje to i automatycznie zrestartuje instancję Django. Poniżej znajduje się przykładowa konfiguracja programu nadzorczego (pojedynczego procesu):

[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

W przypadku Nginx wiem, że na początku może to być przytłaczające. Znalazłem NginxKsiążka bardzo przydatna. Wyjaśnia wszystkie główne dyrektywy nginx.

W mojej instalacji nginx stwierdziłem, że najlepszą praktyką jest ustawienie tylko podstawowych konfiguracji w nginx.confpliku, a następnie mam oddzielny folder, w sitesktórym przechowuję konfiguracje nginx dla każdej hostowanej witryny. Następnie po prostu dołączam wszystkie pliki z tego folderu do podstawowego pliku konfiguracyjnego. Korzystam z dyrektywy include sites/+*.conf;. W ten sposób zawiera tylko pliki zaczynające się od+ symbolu w sitesfolderze. W ten sposób po nazwie pliku mogę kontrolować, które pliki konfiguracyjne mają zostać załadowane. Więc jeśli chcę wyłączyć określoną witrynę, muszę po prostu zmienić nazwę pliku konfiguracyjnego i ponownie uruchomić nginx. Nie bardzo wiem, co masz na myśli przez „dowiązanie symboliczne między dostępnymi witrynami a witrynami włączonymi w / etc / nginx” w pytaniu, ponieważ są to foldery o nazwie Apache, ale spełniają one podobne zadanie jak includedyrektywa.

Jeśli chodzi o dyrektywy rooti alias, są one prawie takie same, z wyjątkiem sytuacji, gdy obliczany jest ich pierwiastek. W alias, cokolwiek wlocation spadku spadło, podczas gdy w korzeniu nie. Obraz, na którym masz następującą konfigurację nginx:

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

Jeśli użytkownik przejdzie pod te adresy URL, nginx spróbuje wyszukać pliki w następujących miejscach w systemie:

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

To jest prosta konfiguracja dla witryny 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;
    }
}

Mam nadzieję, że to ci trochę pomoże.

miki725
źródło
Właściwie twoja odpowiedź bardzo pomaga! Superwizor brzmi świetnie i jest to jedna z niewielu rzeczy, w których blogerzy wydają się być zgodni. Świetna rada dotycząca środowisk wirtualnych i ich opakowania. Kusiło mnie, aby dodać do miksu virtualenv-wrapper, ale nie chciałem niepotrzebnie zwiększać złożoności tego pytania. Jeśli chodzi o dostępność i obsługę witryn, nginx zawiera te katalogi. Gdzie tworzysz plik konfiguracyjny dla nginx? Wewnątrz twojego projektu Django?
Robert Smith
Osobiście mam je w folderze konfiguracyjnym Nginx. W moim przypadku tak /usr/local/nginx/config/sites. Nie jestem jednak pewien, czy jest to właściwa, czy lepsza metoda. Powodem, dla którego je tam trzymam, jest to, że jeśli je usunę, to w jakiś sposób muszę dołączyć to do nginx, albo ręcznie włączając includedyrektywę, albo tworząc dowiązania symboliczne. W każdym przypadku jest to praca ręczna, więc po prostu trzymam ją w głównym miejscu konfiguracji.
miki725,
Czytam książkę, którą poleciłeś :-) Jest świetna i jak być może pamiętasz, /sites/*.conf to jeden z sugerowanych sposobów. W każdym razie dziękuję za odpowiedź.
Robert Smith
Proszę bardzo. Jedna sekcja o książce, która moim zdaniem nie była zbyt przydatna, dotyczy używania Django z nginx. Book zaleca używanie fastcgi, co nie jest fajne jak używanie proxy pass. Możesz więc pominąć rozdział 6.
miki725
Właśnie skończyłem czytać książkę. Wspaniale. Właściwie przeczytałem rozdział 6, ponieważ chciałem wiedzieć, jak działa hoy fastcgi, ale masz rację ... to nie było zbyt przydatne. Dzięki!
Robert Smith
2

Cóż, jeśli chodzi o najlepsze praktyki, które zadałeś w swoim pytaniu, nie mogę pomóc w udostępnieniu narzędzia, które zdziałało dla mnie cuda, dosłownie! Sam byłem zdezorientowany w kilku plikach konfiguracyjnych gunicorn, nginx, supervisorD dla kilku witryn! Chciałem jednak jakoś zautomatyzować cały proces, aby móc wprowadzić zmiany w mojej aplikacji / witrynie i natychmiast je wdrożyć. Nazywa się django-fagungis. Możesz znaleźć szczegóły mojego doświadczenia z automatyzacją Django Deployment tutaj . Właśnie skonfigurowałem fabfile.py RAZ (django-fagungis używa fabric do automatyzacji całego procesu i tworzy virtualenv na twoim zdalnym serwerze, który jest BARDZO przydatnedo zarządzania zależnościami kilku witryn na jednym serwerze. Używa nginx, gunicorn i supervisorD do obsługi wdrożenia projektu / witryny Django), a django-fagungis klonuje mój najnowszy projekt z bitbucket (którego używam do subversioning) i wdraża go na moim zdalnym serwerze i muszę tylko wprowadzić trzy polecenia w powłoce mojej lokalnej maszyny i to wszystko !! Dla mnie okazało się to najlepszą i bezproblemową praktyką wdrażania Django.

Ali Raza Bhayani
źródło
Dzięki!. Przyjrzę się temu.
Robert Smith