So richten Sie uWSGI und Nginx ein, um Python-Apps unter Ubuntu 14.04 zu bedienen

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 für den Anwendungsserver verwenden, um eine robustere Verbindungshandhabung zu ermöglichen. Wir werden diese Komponenten auf einem Ubuntu 14.04 Server installieren und konfigurieren.

Definitionen und Konzepte

Klärung einiger Begriffe

Bevor wir beginnen, sollten wir uns mit einigen verwirrenden Begriffen befassen, die mit den zusammenhängenden Konzepten verbunden sind, mit denen wir arbeiten werden. Diese drei separaten Begriffe scheinen austauschbar zu sein, haben aber tatsächlich unterschiedliche Bedeutungen:

  • WSGI: Eine Python-Spezifikation, die eine Standard-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 zur Vereinfachung und Standardisierung für Konsistenz und Austauschbarkeit zu vereinfachen. Dies definiert im Wesentlichen eine API-Schnittstelle, die über andere Protokolle verwendet werden kann.
  • : Ein Anwendungscontainer, der darauf abzielt, einen vollständigen Stapel für die Entwicklung und Bereitstellung von Webanwendungen und -diensten bereitzustellen. Die Hauptkomponente ist ein Anwendungsserver, der Apps unterschiedlicher Sprachen verarbeiten kann. Er kommuniziert mit der Anwendung mithilfe der Methoden, die durch die WSGI-Spezifikation definiert sind, 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 umfangreicheren Webserver zu kommunizieren. Dies ist ein Drahtprotokoll, kein Transportprotokoll. Es ist der bevorzugte Weg, um mit Webservern zu kommunizieren, die Anfragen an uWSGI weiterleiten.

WSGI-Anwendungsanforderungen

Die WSGI-Spezifikation definiert die Schnittstelle zwischen dem Webserver und den Anwendungsteilen des Stapels. In diesem Kontext bezieht sich „Webserver“ auf den uWSGI-Server, der für die Übersetzung von Clientanfragen zur Anwendung unter Verwendung der WSGI-Spezifikation verantwortlich ist. Dies vereinfacht die Kommunikation und schafft lose gekoppelte Komponenten, sodass Sie beide Seiten leicht austauschen können, ohne große Schwierigkeiten zu haben.

Der Webserver (uWSGI) muss die Fähigkeit haben, Anfragen an die Anwendung zu senden, indem er einen definierten „callable“ auslöst. Der Aufrufbare ist einfach ein Einstiegspunkt in die Anwendung, an dem der Webserver eine Funktion mit einigen Parametern aufrufen kann. Die erwarteten Parameter sind ein Wörterbuch von Umgebungsvariablen und ein vom Webserver (uWSGI) bereitgestelltes Callable.

Als Antwort gibt die Anwendung eine Iteration zurück, die verwendet wird, um den Body der Client-Antwort zu generieren. Sie ruft auch das vom Webserver-Komponenten-Callable auf, das sie als Parameter erhalten hat. Der erste Parameter beim Auslösen des Webserver-Callables wird der HTTP-Statuscode sein und der zweite wird eine Liste von Tupeln sein, von denen jedes einen Antwortheader und -wert definiert, der an den Client zurückgesendet werden soll.

Mit der „Webserver“-Komponente dieser Interaktion, die in diesem Fall von uWSGI bereitgestellt wird, müssen wir nur sicherstellen, dass unsere Anwendungen die oben beschriebenen Qualitäten haben. Wir werden auch Nginx einrichten, um tatsächliche Client-Anfragen zu bearbeiten und sie an den uWSGI-Server weiterzuleiten.

Komponenten installieren

Um loszulegen, müssen wir die erforderlichen Komponenten auf unserem Ubuntu 14.04 Server installieren. Dies können wir hauptsächlich mit apt und pip tun.

Zuerst aktualisieren Sie Ihren apt-Paketindex und installieren dann die Python-Entwicklungs-Bibliotheken und -Headers, 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 Python-Paketmanager pip. Wir können dies verwenden, um das Paket virtualenv zu installieren, das wir verwenden werden, um die Python-Umgebung unserer Anwendung von anderen isolieren, die möglicherweise auf dem System vorhanden sind:

sudo pip install virtualenv

Nach Abschluss dessen können wir beginnen, die allgemeine Struktur für unsere Anwendung zu erstellen. Wir werden die oben diskutierte virtuelle Umgebung erstellen und den uWSGI-Anwendungsserver innerhalb dieser Umgebung installieren.

Richten Sie ein App-Verzeichnis und eine Virtualenv ein

Wir beginnen damit, einen Ordner für unsere App zu erstellen. Dieser kann einen verschachtelten Ordner enthalten, der den eigentlichen Anwendungscode in einer umfassenderen Anwendung enthä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

A new Python environment will be set up under a directory called myappenv. We can activate this environment by typing:

source myappenv/bin/activate

Ihre Eingabeaufforderung sollte sich ändern, um anzuzeigen, dass Sie nun innerhalb der virtuellen Umgebung arbeiten. Es wird ungefähr so aussehen:

(myappenv)username@host:~/my_app$

Wenn Sie diese Umgebung jederzeit verlassen möchten, können Sie einfach Folgendes eingeben:

deactivate

Wenn Sie Ihre Umgebung deaktiviert haben, aktivieren Sie sie erneut, um mit dem Leitfaden fortzufahren.

Mit dieser Umgebung aktiviert, werden alle installierten Python-Pakete innerhalb dieser Verzeichnishierarchie enthalten sein. Sie werden nicht mit der Python-Umgebung des Systems interferieren. Mit diesem Wissen können wir nun den uWSGI-Server in unsere Umgebung mit pip installieren. Das Paket dafür heißt uwsgi (dies ist immer noch der uWSGI-Server und nicht das uwsgi-Protokoll):

pip install uwsgi

Sie können überprüfen, ob es jetzt verfügbar ist, indem Sie eingeben:

uwsgi --version

Wenn es eine Versionsnummer zurückgibt, steht der uWSGI-Server zur Verfügung.

Erstellen Sie eine WSGI-Anwendung

Als nächstes werden wir eine unglaublich einfache WSGI-Anwendung gemäß den zuvor diskutierten Anforderungen der WSGI-Spezifikation erstellen. Um es zu wiederholen, die Anwendungskomponente, die wir bereitstellen müssen, sollte folgende Eigenschaften haben:

  • Es muss eine Schnittstelle über einen Aufruf bereitstellen (eine Funktion oder ein anderes Sprachkonstrukt, das aufgerufen werden kann)
  • Der Aufruf muss als Parameter ein Wörterbuch enthalten, das schlüsselwertähnliche Umgebungsvariablen und einen aufrufbaren Wert enthält, der auf dem Server (uWSGI) zugänglich ist.
  • Der Aufruf der Anwendung sollte ein Iterierbares zurückgeben, das den Body erzeugt, der an den Client gesendet werden soll.
  • Die Anwendung sollte den aufrufbaren Wert des Webservers mit dem HTTP-Status und den Anforderungsheadern aufrufen.

Wir werden unsere Anwendung in einer Datei namens wsgi.py in unserem Anwendungsverzeichnis schreiben:

nano ~/myapp/wsgi.py

Innerhalb dieser Datei erstellen wir die einfachste WSGI-konforme Anwendung, die wir können. Wie bei allem Python-Code 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 einer aufrufbaren Funktion namens application, weshalb wir unsere Funktion application genannt haben. Wie Sie sehen können, nimmt sie zwei Parameter an.

Den ersten haben wir environ genannt, weil es sich um ein Umgebungsvariablen-ähnliches Schlüssel-Wert-Wörterbuch handeln wird. Der zweite wird start_response genannt und ist der Name, den die App intern verwenden wird, um auf die vom Webserver (uWSGI) übergebene aufrufbare Funktion zu verweisen. Beide Parameterbezeichnungen wurden einfach aufgrund ihrer Verwendung in den Beispielen in der PEP 333-Spezifikation ausgewählt, die die WSGI-Interaktionen definiert.

Unsere Anwendung muss diese Informationen entgegennehmen und zwei Dinge tun. Erstens muss sie die erhaltene aufrufbare Funktion mit einem HTTP-Statuscode und allen Headern aufrufen, die sie zurücksenden möchte. In diesem Fall senden wir eine „200 OK“-Antwort und setzen den Content-Type-Header auf text/html.

Zweitens muss sie mit einem iterierbaren Objekt zurückkehren, das als Antwortkörper verwendet werden soll. 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 Iteration verarbeiten.

In einem realen Szenario würde diese Datei wahrscheinlich als Verknüpfung zu Ihrem Anwendungscode verwendet werden. Zum Beispiel enthalten Django-Projekte standardmäßig eine Datei namens wsgi.py, die Anfragen vom Webserver (uWSGI) in die Anwendung (Django) übersetzt. Die vereinfachte WSGI-Schnittstelle bleibt unabhängig davon, wie komplex der tatsächliche Anwendungscode ist, 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 vorerst sagen, HTTP zu verwenden und auf Port 8080 zu hören. Wir werden ihm den Namen des Skripts übergeben (Suffix entfernt):

uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi

Wenn Sie nun die IP-Adresse oder den Domainnamen Ihres Servers in Ihrem Webbrowser besuchen, gefolgt von :8080, sollten Sie den Text des ersten Headerlevels sehen, den wir als Inhalt in unsere wsgi.py-Datei übergeben haben:

Stoppen Sie den Server mit STRG-C, wenn Sie überprüft haben, dass dies funktioniert.

Wir haben das Design unserer eigentlichen Anwendung zu diesem Zeitpunkt abgeschlossen. Sie können unsere virtuelle Umgebung deaktivieren, wenn Sie möchten:

deactivate

Konfigurieren Sie eine uWSGI-Konfigurationsdatei

In obigem Beispiel haben wir den uWSGI-Server manuell gestartet und ihm einige Parameter über die Befehlszeile übergeben. Dies können wir vermeiden, indem wir eine Konfigurationsdatei erstellen. Der uWSGI-Server kann Konfigurationen in verschiedenen Formaten lesen, aber wir werden das .ini-Format für die Einfachheit verwenden.

Um mit der bisher verwendeten Benennung fortzufahren, nennen wir die Datei myapp.ini und platzieren sie in unserem Anwendungsordner:

nano ~/myapp/myapp.ini

Darin müssen wir einen Abschnitt namens [uwsgi] festlegen. In diesem Abschnitt werden alle unsere Konfigurationspunkte stehen. Wir werden damit beginnen, unsere Anwendung zu identifizieren. Der uWSGI-Server muss wissen, wo die aufrufbare Funktion der Anwendung liegt. Wir können die Datei und die Funktion innerhalb angeben:

[uwsgi]
module = wsgi:application

Wir möchten den ersten uwsgi-Prozess als Master kennzeichnen und dann eine Anzahl von Worker-Prozessen starten. Wir beginnen mit fünf Workern:

[uwsgi]
module = wsgi:application

master = true
processes = 5

Tatsächlich werden wir das Protokoll ändern, mit dem uWSGI mit der Außenwelt kommuniziert. Als wir unsere Anwendung getestet haben, haben wir --protocol=http angegeben, damit wir sie im Webbrowser sehen konnten. Da wir Nginx als Reverse-Proxy vor uWSGI konfigurieren werden, können wir dies ändern. Nginx implementiert einen uwsgi-Proxy-Mechanismus, der ein schnelles Binärprotokoll ist, das uWSGI verwenden kann, um mit anderen Servern zu kommunizieren. Das uwsgi-Protokoll ist tatsächlich das Standardprotokoll von uWSGI. Durch das Weglassen einer Protokollspezifikation fällt es automatisch auf uwsgi zurück.

Da wir diese Konfiguration für die Verwendung mit Nginx entwerfen, werden wir auch von der Verwendung eines Netzwerkports absehen und stattdessen einen Unix-Socket verwenden. Dies ist sicherer und schneller. Der Socket wird im aktuellen Verzeichnis erstellt, wenn wir einen relativen Pfad verwenden. Wir werden ihn myapp.sock nennen. Wir ändern die Berechtigungen auf „664“, damit Nginx darauf schreiben kann (wir werden uWSGI mit der www-data-Gruppe starten, die von Nginx verwendet wird). Außerdem fügen wir die Option vacuum hinzu, die den Socket entfernt, wenn der Prozess beendet wird:

[uwsgi]
module = wsgi:application

master = true
processes = 5

socket = myapp.sock
chmod-socket = 664
vacuum = true

Wir benötigen noch eine letzte Option, da wir eine Upstart-Datei erstellen werden, um unsere Anwendung beim Start zu starten. Upstart und uWSGI haben unterschiedliche Vorstellungen davon, was das SIGTERM-Signal mit einer Anwendung tun sollte. Um diese Diskrepanz zu klären, damit die Prozesse wie erwartet mit Upstart behandelt werden können, müssen wir lediglich eine Option namens die-on-term hinzufügen, damit uWSGI den Prozess beendet, 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 und schließen Sie die Datei, wenn Sie fertig sind. Diese Konfigurationsdatei ist nun bereit, mit einem Upstart-Skript verwendet zu werden.

Erstellen Sie eine Upstart-Datei zur Verwaltung der Anwendung

Wir können eine uWSGI-Instanz beim Booten starten, damit unsere Anwendung immer verfügbar ist. Wir werden dies im Verzeichnis /etc/init platzieren, 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 Systemausführungsstufen auswählen, in denen er automatisch gestartet werden soll. Die Standardbenutzer-Ausführungsstufen sind 2 bis 5. Wir werden Upstart mitteilen, den Dienst zu stoppen, wenn er sich in einer Ausführungsstufe außerhalb dieser Gruppe befindet (zum Beispiel beim Neustart 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 darüber informieren, unter welchem Benutzer und welcher Gruppe der Prozess ausgeführt werden soll. Wir möchten die Anwendung unter unserem eigenen Konto ausführen (in dieser Anleitung verwenden wir demo, aber Sie sollten Ihren eigenen Benutzer einsetzen). Die Gruppe möchten wir jedoch auf den Benutzer www-data setzen, den Nginx verwendet. Dies ist erforderlich, 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 tatsächlichen Befehle ausführen, um uWSGI zu starten. Da wir uWSGI in einer virtuellen Umgebung installiert haben, haben wir etwas zusätzliche Arbeit zu erledigen. Wir könnten einfach den gesamten Pfad zur uWSGI-Ausführbaren Datei angeben, aber stattdessen werden wir die virtuelle Umgebung aktivieren. Dies würde es einfacher machen, wenn wir zusätzliche Software installiert haben, die von der Umgebung abhängt.

Um dies zu tun, werden wir einen script-Block verwenden. Darin werden wir in unser Anwendungsverzeichnis wechseln, die virtuelle Umgebung aktivieren (in Skripten müssen wir . anstelle von source verwenden) und die uWSGI-Instanz starten, 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 eingeben:

sudo start myapp

Wir können überprüfen, ob er 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 automatisch beim Booten gestartet. Sie können den Dienst jederzeit stoppen, indem Sie Folgendes eingeben:

sudo stop myapp

Konfigurieren Sie Nginx zum Proxy für uWSGI

Zu diesem Zeitpunkt haben wir eine WSGI-App und haben überprüft, dass uWSGI sie lesen und bereitstellen kann. Wir haben eine Konfigurationsdatei und ein Upstart-Skript erstellt. Unser uWSGI-Prozess wird über einen Socket lauschen und mittels des uwsgi-Protokolls kommunizieren.

Wir sind nun an dem Punkt angelangt, an dem wir Nginx als Reverse-Proxy konfigurieren können. Nginx hat die Fähigkeit, über das uwsgi-Protokoll mit uWSGI zu kommunizieren. Dies ist ein schnelleres Protokoll als HTTP und wird besser performen.

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 dem von uns verwendeten App-Namen zu entsprechen:

sudo nano /etc/nginx/sites-available/myapp

In dieser Datei können wir die Portnummer und den Domänennamen angeben, auf die dieser Server-Block reagieren soll. In unserem Fall verwenden wir den Standardport 80:

server {
    listen 80;
    server_name server_domain_or_IP;
}

Da wir alle Anfragen auf dieser Domain oder IP-Adresse an unsere WSGI-Anwendung senden möchten, werden wir einen einzigen Location-Block für Anfragen erstellen, die mit / beginnen, was alles entsprechen sollte. Darin verwenden wir die include-Direktive, um eine Reihe von Parametern mit vernünftigen Standardwerten aus einer Datei in unserem Nginx-Konfigurationsverzeichnis einzubeziehen. Die Datei, die diese enthält, heißt uwsgi_params. Anschließend leiten wir den Traffic über das uwsgi-Protokoll an unsere uWSGI-Instanz weiter. Wir verwenden den Unix-Socket, 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 Reihe von Upstream-uWSGI-Servern außerhalb dieses Blocks definieren und sie dann dorthin weiterleiten. Wir könnten einige weitere uWSGI-Parameter einbeziehen. Wir könnten auch statische Dateien direkt von Nginx behandeln und nur dynamische Anfragen an die uWSGI-Instanz weiterleiten.

Diese Funktionen benötigen wir jedoch nicht in unserer Dreizeiler-Anwendung, daher können wir die Datei speichern und schließen.

Aktivieren Sie die Serverkonfiguration, die wir gerade erstellt haben, indem Sie sie mit dem Verzeichnis sites-enabled 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 keine Probleme festgestellt werden, starten Sie den Server neu, um Ihre Änderungen zu implementieren:

sudo service nginx restart

Nach dem Neustart von Nginx sollten Sie in der Lage sein, zur Domäne oder IP-Adresse Ihres Servers (ohne Portnummer) zu gehen und die konfigurierte Anwendung zu sehen:

Fazit

Wenn Sie es bis hierhin geschafft haben, haben Sie eine einfache WSGI-Anwendung erstellt und Einblick in die Gestaltung komplexerer Anwendungen erhalten. Wir haben den uWSGI-Anwendungscontainer/-server in eine speziell erstellte virtuelle Umgebung installiert, um unsere Anwendung zu bedienen. 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-Protokoll kommunizieren kann.

Sie können leicht erkennen, wie dies erweitert werden kann, wenn Sie eine tatsächliche Produktionsumgebung einrichten. Zum Beispiel hat uWSGI die Möglichkeit, mehrere Anwendungen mithilfe von etwas namens „Emperor-Modus“ zu verwalten. Sie können die Nginx-Konfiguration erweitern, um die Last zwischen uWSGI-Instanzen auszugleichen oder um statische Dateien für Ihre Anwendung zu verarbeiten. Wenn Sie mehrere Anwendungen bedienen, ist es möglicherweise in Ihrem besten Interesse, uWSGI global zu installieren, anstatt es in einer virtuellen Umgebung zu installieren, je nach Ihren Bedürfnissen. Die Komponenten sind alle ziemlich flexibel, sodass Sie ihre Konfiguration an viele verschiedene Szenarien anpassen können.

Source:
https://www.digitalocean.com/community/tutorials/how-to-set-up-uwsgi-and-nginx-to-serve-python-apps-on-ubuntu-14-04