Wie man uWSGI und Nginx einrichtet, um Python-Apps auf Ubuntu 14.04 bereitzustellen
Einführung
In diesem Leitfaden werden wir eine einfache WSGI-Anwendung einrichten, die von uWSGI bereitgestellt wird. Wir werden den Nginx-Webserver als Reverse-Proxy zum Anwendungsserver verwenden, um eine robustere Verbindungsbehandlung zu gewährleisten. Wir werden diese Komponenten auf einem Ubuntu 14.04-Server installieren und konfigurieren.
Definitionen und Konzepte
Einige Begriffe klären
Bevor wir einsteigen, sollten wir einige verwirrende Begriffe ansprechen, die mit den miteinander verbundenen Konzepten, mit denen wir uns befassen werden, verbunden sind. Diese drei separaten Begriffe erscheinen austauschbar, haben jedoch tatsächlich unterschiedliche Bedeutungen:
- WSGI: Eine Python-Spezifikation, die eine standardisierte Schnittstelle für die Kommunikation zwischen einer Anwendung oder einem Framework und einem Anwendungs-/Webserver definiert. Dies wurde erstellt, um die Kommunikation zwischen diesen Komponenten zu vereinfachen und zu standardisieren, um Konsistenz und Austauschbarkeit zu gewährleisten. Dies definiert im Grunde eine API-Schnittstelle, die über andere Protokolle verwendet werden kann.
- uWSGI: Ein Anwendungsserver-Container, der darauf abzielt, einen vollständigen Stack für die Entwicklung und Bereitstellung von Webanwendungen und -diensten bereitzustellen. Die Hauptkomponente ist ein Anwendungsserver, der Apps in verschiedenen Sprachen verarbeiten kann. Er kommuniziert mit der Anwendung über die von der WSGI-Spezifikation definierten Methoden und mit anderen Webservern über eine Vielzahl anderer Protokolle. Dies ist das Element, das Anfragen von einem herkömmlichen Webserver in ein Format übersetzt, das die Anwendung verarbeiten kann.
- uwsgi: Ein schnelles, binäres Protokoll, das vom uWSGI-Server implementiert wurde, um mit einem funktionsreicheren Webserver zu kommunizieren. Dies ist ein Drahtprotokoll, kein Transportprotokoll. Es ist die bevorzugte Methode, um mit Webservern zu sprechen, die Anfragen an uWSGI weiterleiten.
WSGI-Anwendungsanforderungen
Die WSGI-Spezifikation definiert die Schnittstelle zwischen dem Webserver und den Anwendungsanteilen des Stacks. In diesem Kontext bezieht sich "Webserver" auf den uWSGI-Server, der dafür verantwortlich ist, Client-Anfragen an die Anwendung mithilfe der WSGI-Spezifikation zu übersetzen. Dies vereinfacht die Kommunikation und schafft lose gekoppelte Komponenten, sodass Sie entweder Seite problemlos austauschen können.
Der Webserver (uWSGI) muss die Fähigkeit haben, Anfragen an die Anwendung zu senden, indem er ein definiertes "Callable" auslöst. Das Callable ist einfach ein Einstiegspunkt in die Anwendung, an dem der Webserver eine Funktion mit einigen Parametern aufrufen kann. Die erwarteten Parameter sind ein Dictionary von Umgebungsvariablen und ein vom Webserver (uWSGI) bereitgestelltes Callable.
Als Antwort gibt die Anwendung ein iterierbares Objekt zurück, das verwendet wird, um den Inhalt der Client-Antwort zu generieren. Sie wird auch die als Parameter erhaltene webserverkomponente aufrufen. Der erste Parameter beim Auslösen der webserverkomponente ist der HTTP-Statuscode und der zweite eine Liste von Tupeln, von denen jedes einen Antwortheader und den Wert definiert, der an den Client gesendet werden soll.
Mit dem “Webserver”-Element dieser Interaktion, das in diesem Fall von uWSGI bereitgestellt wird, müssen wir nur sicherstellen, dass unsere Anwendungen die oben beschriebenen Eigenschaften besitzen. Wir werden auch Nginx einrichten, um die tatsächlichen Clientanfragen zu bearbeiten und sie an den uWSGI-Server weiterzuleiten.
Installieren Sie die Komponenten
Um zu beginnen, müssen wir die erforderlichen Komponenten auf unserem Ubuntu 14.04-Server installieren. Wir können dies hauptsächlich mit apt und pip tun.
Zuerst aktualisieren Sie Ihr apt Paket-Index und installieren dann die Python-Entwicklungslibraries und Header, den pip Python-Paketmanager und den Nginx-Webserver und Reverse-Proxy:
sudo apt-get update
sudo apt-get install python-dev python-pip nginx
Sobald die Paketinstallation abgeschlossen ist, haben Sie Zugriff auf den pip Python-Paketmanager. Wir können dies verwenden, um das virtualenv Paket zu installieren, das wir verwenden werden, um die Python-Umgebung unserer Anwendung von anderen zu isolieren, die möglicherweise auf dem System existieren:
sudo pip install virtualenv
Sobald dies abgeschlossen ist, können wir beginnen, die allgemeine Struktur für unsere Anwendung zu erstellen. Wir werden die oben besprochene virtuelle Umgebung erstellen und innerhalb dieser Umgebung den uWSGI-Anwendungsserver installieren.
Richten Sie ein App-Verzeichnis und eine Virtuelle Umgebung ein
Wir werden damit beginnen, einen Ordner für unsere App zu erstellen. Dieser kann einen verschachtelten Ordner enthalten, der den tatsächlichen Anwendungs-Code in einer vollständigeren Anwendung hält. Für unsere Zwecke wird dieses Verzeichnis einfach unsere virtuelle Umgebung und unseren WSGI-Einstiegspunkt enthalten:
mkdir ~/myapp/
Als nächstes wechseln Sie in das Verzeichnis, damit wir die Umgebung für unsere Anwendung einrichten können:
cd ~/myapp
Erstellen Sie eine virtuelle Umgebung mit dem Befehl virtualenv. Wir werden dies der Einfachheit halber myappenv nennen:
virtualenv myappenv
Eine neue Python-Umgebung wird unter einem Verzeichnis namens myappenv eingerichtet. Wir können diese Umgebung aktivieren, indem wir Folgendes eingeben:
source myappenv/bin/activate
Ihre Eingabeaufforderung sollte sich ändern, um anzugeben, dass Sie sich jetzt in der virtuellen Umgebung befinden. Es wird ungefähr so aussehen:
(myappenv)username@host:~/my_app$
Wenn Sie diese Umgebung jederzeit verlassen möchten, können Sie einfach tippen:
deactivate
Wenn Sie Ihre Umgebung deaktiviert haben, aktivieren Sie sie erneut, um mit der Anleitung fortzufahren.
Mit dieser aktiven Umgebung werden alle installierten Python-Pakete innerhalb dieser Verzeichnisstruktur enthalten sein. Sie werden nicht mit der Python-Umgebung des Systems interferieren. Vor diesem Hintergrund können wir nun den uWSGI-Server in unsere Umgebung installieren, indem wir pip verwenden. Das Paket dafür heißt uwsgi (das ist immer noch der uWSGI-Server und nicht das uwsgi-Protokoll):
pip install uwsgi
Sie können überprüfen, dass es jetzt verfügbar ist, indem Sie Folgendes eingeben:
uwsgi --version
Wenn es eine Versionsnummer zurückgibt, ist der uWSGI-Server zur Nutzung verfügbar.
Erstellen Sie eine WSGI-Anwendung
Als nächstes werden wir eine unglaublich einfache WSGI-Anwendung erstellen, die die Anforderungen der WSGI-Spezifikation erfüllt, die wir zuvor besprochen haben. Um es zu wiederholen, sollte die Anwendungs-Komponente, die wir bereitstellen müssen, die folgenden Eigenschaften haben:
- Es muss eine Schnittstelle über ein aufrufbares Element (eine Funktion oder eine andere Programmiersprachekonstruktion, die aufgerufen werden kann) bereitstellen.
- Der aufrufbare Code muss als Parameter ein Dictionary enthalten, das umweltvariableähnliche Schlüssel-Wert-Paare und eine auf dem Server (uWSGI) zugängliche Funktion enthält.
- Die aufrufbare Methode der Anwendung sollte ein iterierbares Objekt zurückgeben, das den Body erzeugt, der an den Client gesendet werden soll.
- Die Anwendung sollte das aufrufbare des Webservers mit dem HTTP-Status und den Anfrage-Headern aufrufen.
Wir werden unsere Anwendung in einer Datei namens wsgi.py in unserem Anwendungsverzeichnis schreiben:
nano ~/myapp/wsgi.py
Innerhalb dieser Datei werden wir die einfachste WSGI-konforme Anwendung erstellen, die wir können. Wie bei allen Python-Codes sollten Sie auf die Einrückung achten:
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ["<h1 style='color:blue'>Hello There!</h1>"]
Der obige Code stellt eine vollständige WSGI-Anwendung dar. Standardmäßig sucht uWSGI nach einem aufrufbaren Objekt namens application, weshalb wir unsere Funktion application genannt haben. Wie Sie sehen können, nimmt sie zwei Parameter entgegen.
Das erste haben wir environ genannt, weil es ein umgebungsvariablenähnliches Schlüssel-Wert-Dictionary sein wird. Das zweite wird start_response genannt und ist der Name, den die Anwendung intern verwenden wird, um sich auf das Webserver (uWSGI) Aufrufbare zu beziehen, das geschickt wird. Beide Parameter-Namen wurden einfach aufgrund ihrer Verwendung in den Beispielen der PEP 333-Spezifikation ausgewählt, die die WSGI-Interaktionen definiert.
Unsere Anwendung muss diese Informationen aufnehmen und zwei Dinge tun. Zuerst muss sie das empfangene Callable mit einem HTTP-Statuscode und allen Headern, die sie zurücksenden möchte, aufrufen. In diesem Fall senden wir eine „200 OK“-Antwort und setzen den Content-Type-Header auf text/html.
Zweitens muss es mit einem iterierbaren Objekt zurückkehren, das als Antwortkörper verwendet werden kann. Hier haben wir einfach eine Liste verwendet, die einen einzigen HTML-String enthält. Strings sind ebenfalls iterierbar, aber innerhalb einer Liste kann uWSGI den gesamten String mit einer einzigen Iteration verarbeiten.
In einem realen Szenario würde diese Datei wahrscheinlich als Verknüpfung zu dem Rest Ihres Anwendungscodes verwendet werden. Zum Beispiel enthalten Django-Projekte standardmäßig eine wsgi.py-Datei, die Anfragen vom Webserver (uWSGI) an die Anwendung (Django) übersetzt. Die vereinfachte WSGI-Schnittstelle bleibt unabhängig von der Komplexität des tatsächlichen Anwendungscodes gleich. Dies ist eine der Stärken der Schnittstelle.
Speichern Sie die Datei und schließen Sie sie, wenn Sie fertig sind.
Um den Code zu testen, können wir uWSGI starten. Wir werden ihm vorübergehend sagen, dass es HTTP verwenden und auf Port 8080 hören soll. Wir werden ihm den Namen des Skripts übergeben (Suffix entfernt):
uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi
Wenn Sie jetzt die IP-Adresse oder den Domainnamen Ihres Servers in Ihrem Webbrowser gefolgt von :8080 aufrufen, sollten Sie den Text des ersten Headers sehen, den wir als Body in unserer wsgi.py-Datei übergeben haben:
Stoppen Sie den Server mit STRG-C, wenn Sie überprüft haben, dass dies funktioniert.
Wir sind an diesem Punkt mit dem Entwurf unserer eigentlichen Anwendung fertig. Sie können unsere virtuelle Umgebung deaktivieren, wenn Sie möchten:
deactivate
Konfigurieren Sie eine uWSGI-Konfigurationsdatei
Im obigen Beispiel haben wir den uWSGI-Server manuell gestartet und ihm einige Parameter über die Befehlszeile übergeben. Wir können dies vermeiden, indem wir eine Konfigurationsdatei erstellen. Der uWSGI-Server kann Konfigurationen in verschiedenen Formaten lesen, aber wir werden das .ini-Format aus Gründen der Einfachheit verwenden.
Um mit der Benennung fortzufahren, die wir bisher verwendet haben, nennen wir die Datei myapp.ini und legen sie in unseren Anwendungsordner:
nano ~/myapp/myapp.ini
Innerhalb müssen wir einen Abschnitt namens [uwsgi] einrichten. Dieser Abschnitt ist der Ort, an dem alle unsere Konfigurationselemente leben werden. Wir beginnen damit, unsere Anwendung zu identifizieren. Der uWSGI-Server muss wissen, wo die aufrufbare Funktion der Anwendung ist. Wir können die Datei und die Funktion darin angeben:
[uwsgi]
module = wsgi:application
Wir möchten den ursprünglichen uwsgi-Prozess als Master kennzeichnen und dann eine Anzahl von Arbeitsprozessen erzeugen. Wir beginnen mit fünf Arbeitern:
[uwsgi]
module = wsgi:application
master = true
processes = 5
Wir werden tatsächlich das Protokoll ändern, das uWSGI verwendet, um mit der Außenwelt zu kommunizieren. Als wir unsere Anwendung getestet haben, haben wir --protocol=http angegeben, damit wir sie von einem Webbrowser aus sehen konnten. Da wir Nginx als Reverse-Proxy vor uWSGI konfigurieren werden, können wir das ändern. Nginx implementiert einen uwsgi-Proxy-Mechanismus, der ein schnelles binäres Protokoll ist, das uWSGI verwenden kann, um mit anderen Servern zu kommunizieren. Das uwsgi-Protokoll ist tatsächlich das Standardprotokoll von uWSGI, sodass es einfach durch das Weglassen einer Protokollspezifikation auf uwsgi zurückfällt.
Da wir diese Konfiguration für die Verwendung mit Nginx entwerfen, werden wir auch von der Nutzung eines Netzwerkports auf einen Unix-Socket umsteigen. Das ist sicherer und schneller. Der Socket wird im aktuellen Verzeichnis erstellt, wenn wir einen relativen Pfad verwenden. Wir werden ihn myapp.sock nennen. Wir werden die Berechtigungen auf „664“ ändern, damit Nginx darauf schreiben kann (wir werden uWSGI mit der www-data-Gruppe starten, die Nginx verwendet). Außerdem fügen wir die Option vacuum hinzu, die den Socket entfernt, wenn der Prozess stoppt:
[uwsgi]
module = wsgi:application
master = true
processes = 5
socket = myapp.sock
chmod-socket = 664
vacuum = true
Wir benötigen eine letzte Option, da wir eine Upstart-Datei erstellen werden, um unsere Anwendung beim Booten zu starten. Upstart und uWSGI haben unterschiedliche Vorstellungen davon, was das SIGTERM-Signal mit einer Anwendung bewirken sollte. Um diese Diskrepanz zu klären, damit die Prozesse wie erwartet mit Upstart behandelt werden können, müssen wir einfach eine Option hinzufügen, die die-on-term heißt, damit uWSGI den Prozess tötet, anstatt ihn neu zu laden:
[uwsgi]
module = wsgi:application
master = true
processes = 5
socket = myapp.sock
chmod-socket = 664
vacuum = true
die-on-term = true
Speichern Sie die Datei und schließen Sie sie, wenn Sie fertig sind. Diese Konfigurationsdatei ist jetzt so eingestellt, dass sie mit einem Upstart-Skript verwendet wird.
Erstellen Sie eine Upstart-Datei zur Verwaltung der App
Wir können eine uWSGI-Instanz beim Booten starten, sodass unsere Anwendung immer verfügbar ist. Wir werden dies im /etc/init-Verzeichnis ablegen, das Upstart überprüft. Wir werden dies myapp.conf nennen:
sudo nano /etc/init/myapp.conf
Zuerst können wir mit einer Beschreibung des Dienstes beginnen und die System-Betriebsstufen auswählen, in denen er automatisch ausgeführt werden soll. Die standardmäßigen Benutzer-Betriebsstufen sind 2 bis 5. Wir werden Upstart mitteilen, den Dienst zu stoppen, wenn er sich in einer der Betriebsstufen außerhalb dieser Gruppe befindet (wie beim Neustarten des Systems oder im Einzelbenutzermodus):
description "uWSGI instance to serve myapp"
start on runlevel [2345]
stop on runlevel [!2345]
Als Nächstes werden wir Upstart mitteilen, unter welchem Benutzer und welcher Gruppe der Prozess ausgeführt werden soll. Wir möchten die Anwendung unter unserem eigenen Konto ausführen (wir verwenden demo in diesem Leitfaden, aber Sie sollten Ihren eigenen Benutzer angeben). Wir möchten jedoch die Gruppe auf den www-data Benutzer einstellen, den Nginx verwendet. Dies ist notwendig, da der Webserver in der Lage sein muss, auf den Socket zuzugreifen, den unsere .ini Datei erstellen wird:
description "uWSGI instance to serve myapp"
start on runlevel [2345]
stop on runlevel [!2345]
setuid demo
setgid www-data
Als nächstes werden wir die eigentlichen Befehle zum Starten von uWSGI ausführen. Da wir uWSGI in einer virtuellen Umgebung installiert haben, haben wir etwas mehr Arbeit zu tun. Wir könnten einfach den gesamten Pfad zur uWSGI ausführbaren Datei angeben, aber stattdessen werden wir die virtuelle Umgebung aktivieren. Das würde es einfacher machen, wenn wir auf zusätzliche Software angewiesen sind, die in der Umgebung installiert ist.
Um dies zu tun, verwenden wir einen script-Block. Darin wechseln wir in unser Anwendungsverzeichnis, aktivieren die virtuelle Umgebung (wir müssen . in Skripten anstelle von source verwenden) und starten die uWSGI-Instanz, die auf unsere .ini-Datei verweist:
description "uWSGI instance to serve myapp"
start on runlevel [2345]
stop on runlevel [!2345]
setuid demo
setgid www-data
script
cd /home/demo/myapp
. myappenv/bin/activate
uwsgi --ini myapp.ini
end script
Damit ist unser Upstart-Skript vollständig. Speichern Sie die Datei und schließen Sie sie, wenn Sie fertig sind.
Jetzt können wir den Dienst starten, indem wir folgendes eintippen:
sudo start myapp
Wir können überprüfen, dass es gestartet wurde, indem wir folgendes eingeben:
ps aux | grep myapp
demo 14618 0.0 0.5 35868 5996 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14619 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14620 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14621 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14622 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14623 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 15520 0.0 0.0 11740 936 pts/0 S+ 15:53 0:00 grep --color=auto myapp
Dies wird beim Start automatisch gestartet. Sie können den Dienst jederzeit stoppen, indem Sie eintippen:
sudo stop myapp
Konfigurieren Sie Nginx, um an uWSGI weiterzuleiten
An diesem Punkt haben wir eine WSGI-App und haben verifiziert, dass uWSGI sie lesen und bereitstellen kann. Wir haben eine Konfigurationsdatei und ein Upstart-Skript erstellt. Unser uWSGI-Prozess wird auf einem Socket hören und mit dem uwsgi-Protokoll kommunizieren.
Wir sind jetzt an dem Punkt, an dem wir Nginx als Reverse-Proxy konfigurieren können. Nginx hat die Fähigkeit, das uwsgi-Protokoll zu verwenden, um mit uWSGI zu kommunizieren. Dies ist ein schnelleres Protokoll als HTTP und wird besser funktionieren.
Die Nginx-Konfiguration, die wir einrichten werden, ist äußerst einfach. Erstellen Sie eine neue Datei im Verzeichnis sites-available innerhalb der Konfigurationshierarchie von Nginx. Wir werden unsere Datei myapp nennen, um mit dem App-Namen übereinzustimmen, den wir verwendet haben:
sudo nano /etc/nginx/sites-available/myapp
In dieser Datei können wir die Portnummer und den Domainnamen angeben, auf den dieser Serverblock reagieren soll. In unserem Fall verwenden wir den Standardport 80:
server {
listen 80;
server_name server_domain_or_IP;
}
Da wir alle Anfragen an diese Domain oder IP-Adresse an unsere WSGI-Anwendung senden möchten, werden wir einen einzigen Standortblock für Anfragen erstellen, die mit / beginnen, was alles erfassen sollte. Dort werden wir die include-Direktive verwenden, um eine Reihe von Parametern mit angemessenen Standardwerten aus einer Datei in unserem Nginx-Konfigurationsverzeichnis einzuschließen. Die Datei, die diese enthält, heißt uwsgi_params. Anschließend leiten wir den Datenverkehr über das uwsgi-Protokoll an unsere uWSGI-Instanz weiter. Wir werden den unix socket verwenden, den wir zuvor konfiguriert haben:
server {
listen 80;
server_name server_domain_or_IP;
location / {
include uwsgi_params;
uwsgi_pass unix:/home/demo/myapp/myapp.sock;
}
}
Das ist eigentlich alles, was wir für eine einfache Anwendung benötigen. Es gibt einige Verbesserungen, die für eine umfassendere Anwendung vorgenommen werden könnten. Zum Beispiel könnten wir eine Anzahl von upstream uWSGI-Servern außerhalb dieses Blocks definieren und sie dann übergeben. Wir könnten einige weitere uWSGI-Parameter einfügen. Wir könnten auch alle statischen Dateien direkt von Nginx behandeln und nur dynamische Anfragen an die uWSGI-Instanz weiterleiten.
Wir benötigen jedoch keine dieser Funktionen in unserer Drei-Zeilen-App, sodass wir die Datei speichern und schließen können.
Aktivieren Sie die Serverkonfiguration, die wir gerade erstellt haben, indem Sie sie mit dem sites-enabled Verzeichnis verknüpfen:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled
Überprüfen Sie die Konfigurationsdatei auf Syntaxfehler:
sudo service nginx configtest
Wenn es zurückmeldet, dass keine Probleme festgestellt wurden, starten Sie den Server neu, um Ihre Änderungen zu implementieren:
sudo service nginx restart
Sobald Nginx neu gestartet wurde, sollten Sie in der Lage sein, zur Domain Ihres Servers oder zur IP-Adresse (ohne Portnummer) zu gehen und die konfigurierte Anwendung zu sehen:
Schlussfolgerung
Wenn Sie es bis hierher geschafft haben, haben Sie eine einfache WSGI-Anwendung erstellt und einige Einblicke gewonnen, wie komplexere Anwendungen entworfen werden müssen. Wir haben den uWSGI-Anwendungscontainer/-server in einer eigens dafür erstellten virtuellen Umgebung installiert, um unsere Anwendung bereitzustellen. Wir haben eine Konfigurationsdatei und ein Upstart-Skript erstellt, um diesen Prozess zu automatisieren. Vor dem uWSGI-Server haben wir einen Nginx-Reverse-Proxy eingerichtet, der mit dem uWSGI-Prozess über das uwsgi Drahtprotokoll kommunizieren kann.
Sie können leicht erkennen, wie dies ausgeweitet werden kann, wenn Sie eine tatsächliche Produktionsumgebung einrichten. Zum Beispiel hat uWSGI die Fähigkeit, mehrere Anwendungen über etwas, das “Kaiser-Modus” genannt wird, zu verwalten. Sie können die Nginx-Konfiguration erweitern, um die Last zwischen uWSGI-Instanzen auszugleichen oder statische Dateien für Ihre Anwendung zu verarbeiten. Beim Bereitstellen mehrerer Anwendungen kann es in Ihrem besten Interesse sein, uWSGI global anstelle in einer virtuellen Umgebung zu installieren, abhängig von Ihren Bedürfnissen. Die Komponenten sind alle recht flexibel, sodass Sie ihre Konfiguration an viele verschiedene Szenarien anpassen können.


