Einsatz von Django mit Gunicorn und Nginx

81

Dies ist eine breite Frage, aber ich möchte eine kanonische Antwort erhalten. Ich habe versucht , eine Website mit zu implementieren gunicorn und nginx in Django . Nachdem ich unzählige Tutorials gelesen habe, war ich erfolgreich, aber ich kann nicht sicher sein, ob die Schritte, die ich befolgt habe, gut genug sind, um eine Site ohne Probleme zu betreiben, oder vielleicht gibt es bessere Möglichkeiten, dies zu tun. Diese Unsicherheit ist ärgerlich.

Deshalb suche ich nach einer sehr detaillierten und gut erklärten Antwort für Neulinge. Ich möchte nicht zu viel erklären, was ich weiß und was ich nicht weiß, da dies die Antworten ein wenig verzerren könnte und andere Menschen in geringerem Maße von Ihren Antworten profitieren könnten. Einige Dinge, die ich gerne erwähnt sehen würde, sind:

  • Welches "Setup" hat am besten funktioniert? Ich habe virtualenv verwendet und mein Django- Projekt in diese Umgebung verschoben. Ich habe jedoch andere Setups gesehen, in denen sich ein Ordner für virtuelle Umgebungen und andere für Projekte befindet.

  • Wie kann ich Dinge so einrichten, dass mehrere Sites auf einem einzigen Server gehostet werden können?

  • Warum schlagen einige Leute vor, gunicorn_django -b 0.0.0.0:8000andere zu verwenden gunicorn_django -b 127.0.0.1:8000? Ich habe Letzteres in einer Amazon EC2-Instanz getestet, aber es hat nicht funktioniert, während Ersteres ohne Probleme funktioniert hat.

  • Welche Logik steckt hinter der Konfigurationsdatei von nginx? Es gibt so viele Tutorials mit drastisch unterschiedlichen Konfigurationsdateien, dass ich mir nicht sicher bin, welche besser ist. Zum Beispiel verwenden einige Leute alias /path/to/static/folderund andere root /path/to/static/folder. Möglicherweise können Sie Ihre bevorzugte Konfigurationsdatei freigeben.

  • Warum erstellen wir eine Symlink zwischen site-availableund sites-enabledin /etc/nginx?

  • Einige Best Practices sind wie immer willkommen :-)

Vielen Dank

Robert Smith
quelle
Kannst du bitte ein Beispiel auf Git bezüglich dieser Nginx und Gunicorn / Uwsgi posten? Es wird für neue Lernende wie mich nützlicher sein.
Shiva
@Shiva Tatsächlich enthält die Antwort von miki725 ein sehr vollständiges Beispiel einer Konfigurationsdatei. Wenn Sie eine sehr gründliche Einführung in die Vorgänge mit nginx wünschen, empfehle ich Ihnen <a href=" amazon.com/Nginx-HTTP-Server-Cl%C3%A9ment-Nedelcu/dp/… book</a>. die gunicorn Integration ist sehr einfach Es wird skizziert <a href=" docs.djangoproject.com/en/dev/howto/deployment/wsgi/gunicorn/...>.
Robert Smith

Antworten:

106

Welches "Setup" hat am besten funktioniert? Ich habe virtualenv verwendet und mein Django-Projekt in diese Umgebung verschoben. Ich habe jedoch andere Setups gesehen, in denen sich ein Ordner für virtuelle Umgebungen und andere für Projekte befindet.

virtualenv ist eine Möglichkeit, Python-Umgebungen zu isolieren. Als solches spielt es bei der Bereitstellung keine große Rolle - während der Entwicklung und des Testens ist es jedoch eine Anforderung, wenn es nicht dringend empfohlen wird.

Der Wert, den Sie von virtualenv erhalten würden, besteht darin, dass Sie sicherstellen können, dass die richtigen Versionen von Bibliotheken für die Anwendung installiert sind. Es spielt also keine Rolle, wo Sie die virtuelle Umgebung selbst anbringen. Stellen Sie nur sicher, dass Sie es nicht in das Versionsverwaltungssystem des Quellcodes aufnehmen.

Das Dateisystemlayout ist nicht kritisch. Sie werden viele Artikel sehen, die die Vorzüge von Verzeichnislayouts und sogar Skelettprojekten preisen, die Sie als Ausgangspunkt klonen können. Ich denke, dies ist eher eine persönliche Präferenz als eine harte Anforderung. Sicher ist es schön zu haben; Wenn Sie jedoch nicht wissen, warum , wird Ihr Bereitstellungsprozess keinen Mehrwert erhalten. Tun Sie dies also nicht, da einige Blogs dies empfehlen, es sei denn, dies ist für Ihr Szenario sinnvoll. Beispiel: setup.pySie müssen keine Datei erstellen , wenn Sie keinen privaten PyPi-Server haben, der Teil Ihres Bereitstellungsworkflows ist.

Wie kann ich Dinge so einrichten, dass mehrere Sites auf einem einzigen Server gehostet werden können?

Es gibt zwei Dinge, die Sie für mehrere Site-Setups benötigen:

  1. Ein Server, der die öffentliche IP an Port 80 und / oder Port 443 überwacht, wenn Sie über SSL verfügen.
  2. Eine Reihe von "Prozessen", auf denen der eigentliche Django-Quellcode ausgeführt wird.

Die Leute verwenden Nginx für # 1, weil es ein sehr schneller Proxy ist und nicht mit dem Overhead eines umfassenden Servers wie Apache verbunden ist. Sie können Apache verwenden, wenn Sie damit vertraut sind. Es gibt keine Anforderung, dass "für mehrere Websites Nginx verwendet wird"; Sie benötigen lediglich einen Dienst, der diesen Port überwacht und weiß, wie Sie zu Ihren Prozessen umleiten (Proxy), auf denen der eigentliche Django-Code ausgeführt wird.

Für # 2 gibt es einige Möglichkeiten, diese Prozesse zu starten. gevent / uwsgi sind die beliebtesten. Das einzige, woran Sie sich erinnern sollten, ist , keinen Runserver in der Produktion zu verwenden .

Das sind die absoluten Mindestanforderungen. Normalerweise fügen Leute eine Art Prozessmanager hinzu, um alle laufenden "Django-Server" (# 2) zu steuern. Hier sehen upstartund supervisorerwähnt. Ich bevorzuge Supervisor, da er nicht das gesamte System übernehmen muss (im Gegensatz zu Upstart). Dies ist jedoch wiederum keine schwierige Anforderung . Sie könnten eine Reihe von screenSitzungen perfekt ausführen und sie erneut abrufen. Der Nachteil ist, dass Sie bei einem Neustart Ihres Servers die Bildschirmsitzungen neu starten müssen.

Persönlich würde ich empfehlen:

  1. Nginx für # 1
  2. Treffen Sie Ihre Wahl zwischen Uwsgi und Gunicorn - ich benutze Uwsgi.
  3. Supervisor für die Verwaltung der Backend-Prozesse.
  4. Individuelle Systemkonten (Benutzer) für jede Anwendung, die Sie hosten.

Der Grund, warum ich # 4 empfehle, besteht darin, Berechtigungen zu isolieren. wieder keine Voraussetzung.

Warum schlagen einige Leute vor, gunicorn_django -b 0.0.0.0:8000 zu verwenden, und andere schlagen gunicorn_django -b 127.0.0.1:8000 vor? Ich habe Letzteres in einer Amazon EC2-Instanz getestet, aber es hat nicht funktioniert, während Ersteres ohne Probleme funktioniert hat.

0.0.0.0bedeutet "alle IP-Adressen" - es ist eine Meta-Adresse (dh eine Platzhalter-Adresse). 127.0.0.1ist eine reservierte Adresse, die immer auf den lokalen Computer verweist. Deshalb heißt es "localhost". Es ist nur für Prozesse erreichbar, die auf demselben System ausgeführt werden.

In der Regel überwacht der Front-End-Server (Nr. 1 in der obigen Liste) die öffentliche IP-Adresse. Sie sollten den Server explizit an eine IP-Adresse binden .

Wenn Sie jedoch aus irgendeinem Grund DHCP verwenden oder die IP-Adresse nicht kennen (z. B. ein neu bereitgestelltes System), können Sie nginx / apache / jedem anderen Prozess mitteilen, an den gebunden werden soll 0.0.0.0. Dies sollte eine vorübergehende Stop-Gap-Maßnahme sein .

Für Produktionsserver haben Sie eine statische IP. Wenn Sie eine dynamische IP (DHCP) haben, können Sie in verlassen 0.0.0.0. Es ist jedoch sehr selten, dass Sie DHCP für Ihre Produktionsmaschinen haben.

Das Binden von Gunicorn / Uwsgi an diese Adresse wird in der Produktion nicht empfohlen . Wenn Sie Ihren Backend-Prozess (gunicorn / uwsgi) an binden 0.0.0.0, kann er "direkt" unter Umgehung Ihres Front-End-Proxys (nginx / apache / etc) zugänglich werden. Jemand könnte http://your.public.ip.address:9000/Ihre Anwendung einfach direkt anfordern und darauf zugreifen, insbesondere wenn Ihr Front-End-Server (nginx) und Ihr Back-End-Prozess (django / uwsgi / gevent) auf demselben Computer ausgeführt werden .

Sie können dies tun, wenn Sie nicht die Mühe haben möchten, einen Front-End-Proxyserver auszuführen.

Welche Logik steckt hinter der Konfigurationsdatei von nginx? Es gibt so viele Tutorials mit drastisch unterschiedlichen Konfigurationsdateien, dass ich mir nicht sicher bin, welche besser ist. Einige Benutzer verwenden beispielsweise "alias / path / to / static / folder" und andere "root / path / to / static / folder". Möglicherweise können Sie Ihre bevorzugte Konfigurationsdatei freigeben.

Das erste, was Sie über Nginx wissen sollten, ist, dass es sich nicht um einen Webserver wie Apache oder IIS handelt. Es ist ein Proxy. Es werden also verschiedene Begriffe wie "Upstream" / "Downstream" und mehrere "Server" definiert. Nehmen Sie sich etwas Zeit und lesen Sie zuerst das Nginx-Handbuch durch.

Es gibt viele verschiedene Möglichkeiten, Nginx einzurichten. aber hier ist eine Antwort auf Ihre Frage auf aliasvs. root. rootist eine explizite Anweisung, die das Dokumentstammverzeichnis (das "Home-Verzeichnis") von nginx bindet. Dies ist das Verzeichnis, in dem angezeigt wird, wenn Sie eine Anfrage ohne Pfad wie gebenhttp://www.example.com/

aliasbedeutet "einem Verzeichnis einen Namen zuordnen". Alias-Verzeichnisse sind möglicherweise kein Unterverzeichnis des Dokumentstamms.

Warum erstellen wir in / etc / nginx einen Symlink zwischen Site-verfügbar und Site-aktiviert?

Dies ist etwas Einzigartiges für Debian (und Debian-ähnliche Systeme wie Ubuntu). sites-availablelistet Konfigurationsdateien für alle virtuellen Hosts / Sites auf dem System auf. Ein Symlink von sites-enabledzu sites-available"aktiviert" diese Site oder diesen virtuellen Host. Auf diese Weise können Sie Konfigurationsdateien trennen und Hosts einfach aktivieren / deaktivieren.

Burhan Khalid
quelle
1
Gute Antwort! Viele Fragen geklärt. Können Sie etwas näher erläutern (oder ein Beispiel hinzufügen), was Sie damit meinen, dass Sie den Server explizit an eine IP-Adresse binden und dass die Bindung von gunicorn / uwsgi an 0.0.0.0 gebunden sein sollte? Leider denke ich, dass ich das getan habe. Vielen Dank!
Robert Smith
7
Ein typischer Computer hat mindestens zwei IP-Adressen: 127.0.0.1und die, die ihm vom Netzwerk zugewiesen wird; Dies ist das Minimum. Ihr Computer verfügt möglicherweise über mehrere Schnittstellen und mehrere IP-Adressen. Sie sollten Ihren Webserver (oder wirklich jeden Prozess) konfigurieren. eine IP-Adresse abhören - das meine ich mit explizit. Wenn Sie eine Bindung herstellen 0.0.0.0, weisen Sie das Programm an, alle IP-Adressen abzuhören, einschließlich aller neuen, die Ihrem Computer möglicherweise zugewiesen wurden . Dies ist aus verschiedenen Gründen keine gute Praxis (Sicherheit ist einer davon).
Burhan Khalid
Verstanden. Ich habe Gunicorn bereits richtig konfiguriert. Vielen Dank!
Robert Smith
nginx kann statischen Inhalt liefern.
Marcin
Wie der Server wissen würde, in welcher Datei wir die Serveradresse konfiguriert haben/etc/nginx/sites-enabled
Shiva
11

Ich bin kein Einsatzguru, werde aber einige meiner Praktiken für den Einsatz von Django mit gevent teilen (sollte jedoch ähnlich wie Gunicorn sein).

virtualenvist großartig aus Gründen, auf die ich nicht eingehen werde. Ich fand jedoch virtualenv-wrapper( docs ) jedoch sehr nützlich, insbesondere wenn Sie an vielen Projekten arbeiten, da es einen einfachen Wechsel zwischen den verschiedenen virtuellen Umgebungen ermöglicht. Dies gilt nicht wirklich für die Bereitstellungsumgebung. Wenn ich jedoch mit SSH eine Fehlerbehebung auf dem Server durchführen muss, fand ich dies sehr nützlich. Ein weiterer Vorteil der Verwendung besteht darin, dass das Verzeichnis virtualenv verwaltet wird, sodass Sie weniger manuell arbeiten müssen. Virtualenvs sollen verfügbar sein, sodass Sie bei Versionsproblemen oder anderen Installationsproblemen einfach die Umgebung sichern und eine neue erstellen können. Daher wird empfohlen, keinen Ihrer Projektcodes in die virtuelle Umgebung aufzunehmen. Es sollte getrennt gehalten werden.

Das Einrichten mehrerer Websites virtualenvist so ziemlich die Antwort. Sie sollten für jedes Projekt eine eigene Virutalev haben. Nur das allein kann viele Probleme lösen. Wenn Sie dann bereitstellen, führt ein anderer Python-Prozess verschiedene Sites aus, wodurch mögliche Konflikte zwischen den Bereitstellungen vermieden werden. Ein Tool, das ich besonders beim Verwalten mehrerer Sites auf demselben Server als sehr nützlich empfand, ist supervisor( docs). Es bietet eine einfache Oberfläche zum Starten, Stoppen und Neustarten verschiedener Django-Instanzen. Es ist auch in der Lage, einen Prozess automatisch neu zu starten, wenn er fehlschlägt oder wenn der Computer gestartet wird. Wenn zum Beispiel eine Ausnahme ausgelöst wird und nichts sie abfängt, kann die gesamte Website ausfallen. Der Supervisor erkennt dies und startet die Django-Instanz automatisch neu. Das Folgende ist eine Beispielkonfiguration für ein Supervisor-Programm (ein einzelner Prozess):

[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

Für Nginx weiß ich, dass es zunächst überwältigend sein kann. Ich fand das Nginx- Buch sehr nützlich. Es werden alle wichtigen Nginx-Richtlinien erläutert.

Bei meiner Nginx-Installation habe ich festgestellt, dass es die beste Vorgehensweise ist, nur die Kernkonfigurationen in der nginx.confDatei einzurichten. Dann habe ich einen separaten Ordner, sitesin dem ich die Nginx-Konfigurationen für jede der von mir gehosteten Sites aufbewahre. Dann füge ich einfach alle Dateien aus diesem Ordner in die Kernkonfigurationsdatei ein. Ich benutze die Richtlinie include sites/+*.conf;. Auf diese Weise werden nur die Dateien eingeschlossen, die mit dem +Symbol im sitesOrdner beginnen. Auf diese Weise kann ich anhand des Dateinamens steuern, welche Konfigurationsdateien geladen werden sollen. Wenn ich also eine bestimmte Site deaktivieren möchte, muss ich nur die Konfigurationsdatei umbenennen und nginx neu starten. Ich bin mir nicht sicher, was Sie in Ihrer Frage unter "Symlink zwischen Site-verfügbar und Sites-fähig in / etc / nginx" verstanden haben, da es sich um Ordner mit Apache-Namen handelt, aber sie erfüllen eine ähnliche Aufgabe wie die includeDirektive.

Die Anweisungen rootund aliasAnweisungen sind ziemlich gleich, außer wenn ihre Wurzel berechnet wird. In alias, was auch immer in der locationin fallen gelassen wurde, während in der Wurzel darin nicht. Bild, dass Sie die folgende Nginx-Konfiguration haben:

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

Wenn der Benutzer zu diesen URLs wechselt, versucht nginx, die Dateien an den folgenden Stellen im System zu suchen:

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

Dies ist eine einfache Konfiguration für die Nginx-Site:

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;
    }
}

Hoffentlich hilft dir das ein bisschen.

miki725
quelle
Eigentlich hilft Ihre Antwort sehr! Supervisor klingt großartig und das ist eines der wenigen Dinge, bei denen es unter Bloggern Konsens zu geben scheint. Großartige Ratschläge zu virtuellen Umgebungen und ihrem Wrapper. Ich war versucht, dem Mix einen Virtualenv-Wrapper hinzuzufügen, aber ich wollte die Komplexität dieser Frage nicht unnötig erhöhen. Nginx enthält diese Verzeichnisse für Site-verfügbare und Site-fähige. Wo erstellen Sie Ihre Konfigurationsdatei für Nginx? In Ihrem Django-Projekt?
Robert Smith
Ich persönlich habe sie im Nginx-Konfigurationsordner. In meinem Fall ist es /usr/local/nginx/config/sites. Ich bin mir jedoch nicht sicher, ob es die richtige oder bessere Methode ist. Der Grund, warum ich sie dort behalte, ist, dass ich sie irgendwie in Nginx aufnehmen muss, wenn ich sie herausnehme, entweder durch manuelles Einfügen der includeDirektive oder durch Erstellen von Symlinks. In beiden Fällen handelt es sich um Handarbeit, daher behalte ich sie einfach an der Hauptkonfigurationsstelle.
miki725
Ich lese das Buch, das Sie empfohlen haben :-) Es ist großartig und wie Sie sich vielleicht erinnern, ist /sites/*.conf ein empfohlener Weg, dies zu tun. Wie auch immer, danke für deine Antwort.
Robert Smith
Gern geschehen. Ein Abschnitt über das Buch, den ich allerdings nicht sehr nützlich fand, ist die Verwendung von Django mit Nginx. Book empfiehlt die Verwendung von fastcgi, was nicht so gut ist wie die Verwendung eines Proxy-Passes. So können Sie Kapitel 6 überspringen
miki725
Ich habe gerade das Buch gelesen. Es ist toll. Ich habe tatsächlich Kapitel 6 gelesen, weil ich wissen wollte, dass hoy fastcgi funktioniert, aber Sie haben Recht ... es war nicht sehr nützlich. Vielen Dank!
Robert Smith
2

Nun, was Best Practices betrifft, die Sie in Ihrer Frage gestellt haben, kann ich nicht anders, als ein Tool zu teilen, das buchstäblich Wunder für mich gewirkt hat! Ich selbst war in mehreren Konfigurationsdateien von Gunicorn, Nginx, SupervisorD für mehrere Websites verwirrt! Aber ich wollte den gesamten Prozess irgendwie automatisieren, damit ich Änderungen an meiner App / Site vornehmen und sie sofort bereitstellen konnte. Sein Name ist django-fagungis. Details zu meinen Erfahrungen mit der Django Deployment-Automatisierung finden Sie hier . Ich habe gerade EINMAL eine fabfile.py konfiguriert (django-fagungis verwendet Fabric, um den gesamten Prozess zu automatisieren, und erstellt eine virtuelle Umgebung auf Ihrem Remote-Server, was SEHR praktisch istVerwalten von Abhängigkeiten mehrerer Sites, die auf einem einzelnen Server gehostet werden. Es verwendet Nginx, Gunicorn und SupervisorD, um die Django-Projekt- / Site-Bereitstellung abzuwickeln. Django-fagungis klont mein aktuelles Projekt von Bitbucket (das ich für die Subversionierung verwende) und stellt es auf meinem Remote-Server bereit. Ich muss nur drei Befehle auf der Shell eingeben von meiner lokalen Maschine und dass es !! Für mich hat sich herausgestellt, dass dies das beste und problemloseste Training für den Django-Einsatz ist.

Ali Raza Bhayani
quelle
Vielen Dank!. Ich werde es mir ansehen.
Robert Smith