So richten Sie uWSGI und Nginx für die Bereitstellung von Python-Apps unter Ubuntu 14.04 ein

Einführung

In diesem Handbuch richten wir eine einfache WSGI-Anwendung ein, die von uWSGI bereitgestellt wird. Wir werden den Nginx-Webserver als Reverse-Proxy für den Anwendungsserver verwenden, um eine robustere Verbindungsverarbeitung 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 einsteigen, sollten wir uns mit verwirrenden Begriffen auseinandersetzen, die mit den verwandten Konzepten zusammenhängen, mit denen wir uns befassen werden. Diese drei Begriffe sind austauschbar, haben jedoch unterschiedliche Bedeutungen:

  • WSGI: APython spec, das eine Standardschnittstelle für die Kommunikation zwischen einer Anwendung oder einem Framework und einer Anwendung / einem Webserver definiert. Dies wurde geschaffen, 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 einen vollständigen Stapel für die Entwicklung und Bereitstellung von Webanwendungen und -diensten bereitstellen soll. Die Hauptkomponente ist ein Anwendungsserver, der Apps in verschiedenen Sprachen verarbeiten kann. Es kommuniziert mit der Anwendung unter Verwendung der in der WSGI-Spezifikation definierten Methoden und mit anderen Webservern über eine Vielzahl anderer Protokolle. Dies ist der Teil, der Anforderungen von einem herkömmlichen Webserver in ein Format übersetzt, das von der Anwendung verarbeitet werden kann.

  • uwsgi: Ein schnelles binäres Protokoll, das vom uWSGI-Server implementiert wird, um mit einem Webserver mit allen Funktionen zu kommunizieren. Dies ist einwire protocol, kein Transportprotokoll. Dies 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 Anwendungsbereichen des Stapels. In diesem Zusammenhang bezieht sich „Webserver“ auf den uWSGI-Server, der für die Übersetzung von Clientanforderungen in die Anwendung mithilfe der WSGI-Spezifikation verantwortlich ist. Dies vereinfacht die Kommunikation und schafft lose gekoppelte Komponenten, so dass Sie problemlos beide Seiten austauschen können.

Der Webserver (uWSGI) muss in der Lage sein, Anforderungen an die Anwendung zu senden, indem ein definiertes "Callable" ausgelöst wird. 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 Wörterbuch mit Umgebungsvariablen und eine vom Webserver (uWSGI) bereitgestellte aufrufbare Komponente.

Als Antwort gibt die Anwendung eine Iterationsdatei zurück, die zum Generieren des Hauptteils der Clientantwort verwendet wird. Sie ruft auch die Webserverkomponente auf, die als Parameter abrufbar ist. Der erste Parameter beim Auslösen des aufrufbaren Webservers ist der HTTP-Statuscode, und der zweite ist eine Liste von Tupeln, von denen jeder einen Antwortheader und einen Wert zum Zurücksenden an den Client definiert.

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 Eigenschaften aufweisen. Wir werden Nginx auch so einrichten, dass es aktuelle Client-Anfragen bearbeitet und sie an den uWSGI-Server weiterleitet.

Installieren Sie die Komponenten

Zu Beginn müssen wir die erforderlichen Komponenten auf unserem Ubuntu 14.04-Server installieren. Wir können dies hauptsächlich mitapt undpip tun.

Aktualisieren Sie zuerst den Paketindex vonaptund installieren Sie dann die Python-Entwicklungsbibliotheken und -Header, den Python-Paketmanager vonpipowie den Nginx-Webserver und den Reverse-Proxy:

sudo apt-get update
sudo apt-get install python-dev python-pip nginx

Nach Abschluss der Paketinstallation haben Sie Zugriff auf den Python-Paketmanager vonpip. Wir können dies verwenden, um das Paketvirtualenvzu installieren, mit dem wir die Python-Umgebung unserer Anwendung von allen anderen auf dem System vorhandenen isolieren:

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 beschriebene virtuelle Umgebung erstellen und den uWSGI-Anwendungsserver in dieser Umgebung installieren.

Richten Sie ein App-Verzeichnis und ein Virtualenv ein

Zunächst erstellen wir einen Ordner für unsere App. Dies kann einen verschachtelten Ordner enthalten, der den eigentlichen Anwendungscode einer vollständigeren Anwendung enthält. Für unsere Zwecke enthält dieses Verzeichnis einfach unsere virtuelle Umgebung und unseren WSGI-Einstiegspunkt:

mkdir ~/myapp/

Wechseln Sie als Nächstes in das Verzeichnis, damit wir die Umgebung für unsere Anwendung einrichten können:

cd ~/myapp

Erstellen Sie eine virtuelle Umgebung mit dem Befehlvirtualenv. Der Einfachheit halber werden wir diesemyappenv nennen:

virtualenv myappenv

Eine neue Python-Umgebung wird in einem Verzeichnis namensmyappenv eingerichtet. Wir können diese Umgebung aktivieren, indem wir Folgendes eingeben:

source myappenv/bin/activate

Ihre Eingabeaufforderung sollte sich ändern, um anzuzeigen, dass Sie jetzt in 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 der Anleitung fortzufahren.

In dieser Umgebung sind alle installierten Python-Pakete in dieser Verzeichnishierarchie enthalten. Sie beeinträchtigen die Python-Umgebung des Systems nicht. In diesem Sinne können wir den uWSGI-Server jetzt mitpip in unserer Umgebung installieren. Das Paket hierfür heißtuwsgi (dies ist immer noch der uWSGI-Server und nicht dasuwsgi-Protokoll):

pip install uwsgi

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

uwsgi --version

Wenn eine Versionsnummer zurückgegeben wird, kann der uWSGI-Server verwendet werden.

Erstellen Sie eine WSGI-Anwendung

Als Nächstes erstellen wir eine unglaublich einfache WSGI-Anwendung unter Verwendung der WSGI-Spezifikationsanforderungen, die wir zuvor besprochen haben. Um es noch einmal zu wiederholen, sollte die Anwendungskomponente, die wir bereitstellen müssen, die folgenden Eigenschaften haben:

  • Es muss eine Schnittstelle über eine aufrufbare Funktion oder ein anderes aufrufbares Sprachkonstrukt bereitstellen.

  • Die aufrufbare Datei muss als Parameter ein Wörterbuch enthalten, das Schlüssel-Wert-Paare wie Umgebungsvariablen enthält, und eine aufrufbare Datei, auf die auf dem Server zugegriffen werden kann (uWSGI).

  • Die aufrufbare Anwendung sollte eine Iteration zurückgeben, die den Text zum Senden des Clients erzeugt.

  • Die Anwendung sollte den aufrufbaren Webserver mit dem HTTP-Status aufrufen und Header anfordern.

Wir werden unsere Anwendung in eine Datei namenswsgi.py in unserem Anwendungsverzeichnis schreiben:

nano ~/myapp/wsgi.py

In dieser Datei erstellen wir die einfachste WSGI-kompatible Anwendung, die wir können. Achten Sie wie bei jedem Python-Code auf den Einzug:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ["

Hello There!

"]

Der obige Code stellt eine vollständige WSGI-Anwendung dar. Standardmäßig sucht uWSGI nach einem aufrufbaren Element namensapplication, weshalb wir unsere Funktionapplication aufgerufen haben. Wie Sie sehen, sind zwei Parameter erforderlich.

Das erste haben wirenviron genannt, weil es ein Umgebungsvariablen-ähnliches Schlüsselwertwörterbuch sein wird. Der zweite Name heißtstart_response und ist der Name, den die App intern verwendet, um auf den aufrufbaren Webserver (uWSGI) zu verweisen, der gesendet wird. Diese beiden Parameternamen wurden einfach aufgrund ihrer Verwendung in den Beispielen in derPEP 333-Spezifikation ausgewählt, die WSGI-Interaktionen definiert.

Unsere Anwendung muss diese Informationen aufnehmen und zwei Dinge tun. Zunächst muss es den empfangenen Callable mit einem HTTP-Statuscode und allen Headern aufrufen, die es zurücksenden möchte. In diesem Fall senden wir eine Antwort „200 OK“ und setzen den HeaderContent-Type auftext/html.

Zweitens muss es mit einem iterablen Code zurückkehren, der als Antworttext verwendet werden kann. Hier haben wir nur eine Liste verwendet, die eine einzelne HTML-Zeichenfolge enthält. Zeichenfolgen können ebenfalls iteriert werden, aber innerhalb einer Liste kann uWSGI die gesamte Zeichenfolge mit einer Iteration verarbeiten.

In einem realen Szenario wird diese Datei wahrscheinlich als Verknüpfung zum restlichen Anwendungscode verwendet. Beispielsweise enthalten Django-Projekte standardmäßig einewsgi.py-Datei, die Anforderungen vom Webserver (uWSGI) in die Anwendung (Django) übersetzt. Die vereinfachte WSGI-Oberfläche bleibt gleich, unabhängig davon, wie komplex der tatsächliche Anwendungscode ist. Dies ist eine der Stärken der Schnittstelle.

Speichern und schließen Sie die Datei, wenn Sie fertig sind.

Um den Code zu testen, können wir uWSGI starten. Wir werden ihm sagen, dass er vorerst HTTP verwenden und Port8080 abhören soll. Wir übergeben ihm den Namen des Skripts (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 gefolgt von:8080 besuchen, sollte der Headertext der ersten Ebene, den wir als Text übergeben haben, in unsererwsgi.py-Datei angezeigt werden:

wsgi application example

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

Wir sind an dieser Stelle mit dem Entwerfen unserer tatsächlichen Anwendung fertig. Sie können unsere virtuelle Umgebung deaktivieren, wenn Sie dies wünschen:

deactivate

Konfigurieren Sie eine uWSGI-Konfigurationsdatei

Im obigen Beispiel haben wir den uWSGI-Server manuell gestartet und ihm einige Parameter in der Befehlszeile übergeben. Wir können dies vermeiden, indem wir eine Konfigurationsdatei erstellen. Der uWSGI-Server kann Konfigurationen in verschiedenen Formaten lesen. Der Einfachheit halber wird jedoch das Format.iniverwendet.

Um mit der bisher verwendeten Benennung fortzufahren, rufen wir die Dateimyapp.ini auf und legen sie in unserem Anwendungsordner ab:

nano ~/myapp/myapp.ini

Im Inneren müssen wir einen Abschnitt namens[uwsgi] einrichten. In diesem Abschnitt werden alle unsere Konfigurationselemente gespeichert. Zunächst identifizieren wir unsere Anwendung. Der uWSGI-Server muss wissen, wo sich die aufrufbare Anwendung befindet. Wir können die Datei und die Funktion innerhalb von geben:

[uwsgi]
module = wsgi:application

Wir möchten den anfänglichenuwsgi-Prozess als Master markieren und dann eine Reihe von Worker-Prozessen erzeugen. Wir werden mit fünf Arbeitern beginnen:

[uwsgi]
module = wsgi:application

master = true
processes = 5

Wir werden das Protokoll ändern, mit dem uWSGI mit der Außenwelt spricht. Beim Testen unserer Anwendung haben wir--protocol=http angegeben, damit wir sie in einem Webbrowser sehen können. Da wir Nginx als Reverse-Proxy vor uWSGI konfigurieren, können wir dies ändern. Nginx implementiert einenuwsgi-Proxy-Mechanismus, ein schnelles Binärprotokoll, mit dem uWSGI mit anderen Servern kommunizieren kann. Dasuwsgi-Protokoll ist eigentlich das Standardprotokoll von uWSGI. Wenn Sie also einfach eine Protokollspezifikation weglassen, wird aufuwsgi zurückgegriffen.

Da wir diese Konfiguration für die Verwendung mit Nginx entwerfen, werden wir auch die Verwendung eines Netzwerkports und stattdessen einen Unix-Socket ändern. Dies ist sicherer und schneller. Der Socket wird im aktuellen Verzeichnis erstellt, wenn wir einen relativen Pfad verwenden. Wir nennen esmyapp.sock. Wir werden die Berechtigungen in "664" ändern, damit Nginx darauf schreiben kann (wir werden uWSGI mit der von Nginx verwendeten Gruppewww-datatarten. Wir werden auch die Optionvacuumhinzufügen, mit der der Socket entfernt wird, 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, um unsere Anwendung beim Booten zu starten. Upstart und uWSGI haben unterschiedliche Vorstellungen darüber, was das SIGTERM-Signal für eine Anwendung tun soll. Um diese Diskrepanz zu beseitigen, damit die Prozesse mit Upstart wie erwartet behandelt werden können, müssen wir nur eine Option namensdie-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 kann jetzt mit einem Upstart-Skript verwendet werden.

Erstellen Sie eine Upstart-Datei zum Verwalten der App

Wir können beim Booten eine uWSGI-Instanz starten, damit unsere Anwendung immer verfügbar ist. Wir werden dies in das von Upstart überprüfte Verzeichnis/etc/initlegen. Wir nennen diesmyapp.conf:

sudo nano /etc/init/myapp.conf

Zunächst können wir mit einer Beschreibung des Dienstes beginnen und die Runlevel des Systems auswählen, auf denen er automatisch ausgeführt werden soll. Die Standard-Runlevel für Benutzer sind 2 bis 5. Wir werden Upstart anweisen, den Dienst zu stoppen, wenn er sich auf einem Runlevel außerhalb dieser Gruppe befindet (z. B. beim Neustart des Systems oder im Einzelbenutzermodus):

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

Als Nächstes teilt Upstart mit, unter welchen Benutzern und Gruppen der Prozess ausgeführt werden soll. Wir möchten die Anwendung unter unserem eigenen Konto ausführen (wir verwendendemo in diesem Handbuch, aber Sie sollten Ihren eigenen Benutzer ersetzen). Wir möchten die Gruppe auf den Benutzer vonwww-dataetzen, den Nginx jedoch verwendet. Dies ist erforderlich, da der Webserver in der Lage sein muss, in den Socket zu lesen und zu schreiben, den unsere.ini-Datei erstellt:

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

setuid demo
setgid www-data

Als Nächstes führen wir die eigentlichen Befehle aus, um uWSGI zu starten. Da wir uWSGI in einer virtuellen Umgebung installiert haben, müssen wir einige zusätzliche Arbeiten ausführen. Wir könnten nur den gesamten Pfad zur ausführbaren uWSGI-Datei bereitstellen, aber stattdessen werden wir die virtuelle Umgebung aktivieren. Dies würde es einfacher machen, wenn wir uns auf zusätzliche in der Umgebung installierte Software verlassen würden.

Dazu verwenden wir einenscript-Block. Im Inneren wechseln wir in unser Anwendungsverzeichnis, aktivieren die virtuelle Umgebung (wir müssen. in Skripten anstelle vonsource verwenden) und starten die uWSGI-Instanz, die auf unsere.ini-Datei zeigt:

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 abgeschlossen. Speichern und schließen Sie die Datei, wenn Sie fertig sind.

Jetzt können wir den Dienst starten, indem wir Folgendes eingeben:

sudo start myapp

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

sudo stop myapp

Konfigurieren Sie Nginx zu Proxy zu 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 überwacht einen Socket und kommuniziert über das Protokolluwsgi.

Wir sind jetzt an dem Punkt angelangt, an dem wir daran arbeiten können, Nginx als Reverse-Proxy zu konfigurieren. Nginx kann mithilfe des Protokollsuwsgifür die Kommunikation mit uWSGI einen Proxy erstellen. Dies ist ein schnelleres Protokoll als HTTP und bietet eine bessere Leistung.

Die Nginx-Konfiguration, die wir einrichten werden, ist äußerst einfach. Erstellen Sie eine neue Datei im Verzeichnissites-availableinnerhalb der Konfigurationshierarchie von Nginx. Wir werden unsere Dateimyapp aufrufen, um dem von uns verwendeten App-Namen zu entsprechen:

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

In dieser Datei können Sie die Portnummer und den Domänennamen angeben, auf die dieser Serverblock antworten soll. In unserem Fall verwenden wir den Standardport 80:

server {
    listen 80;
    server_name server_domain_or_IP;
}

Da wir alle Anforderungen an diese Domäne oder IP-Adresse an unsere WSGI-Anwendung senden möchten, erstellen wir einen einzelnen Standortblock für Anforderungen, die mit/ beginnen und mit allem übereinstimmen sollten. Im Inneren verwenden wir die Direktiveinclude, um eine Reihe von Parametern mit angemessenen Standardeinstellungen aus einer Datei in unser Nginx-Konfigurationsverzeichnis aufzunehmen. Die Datei, die diese enthält, heißtuwsgi_params. Anschließend leiten wir den Datenverkehr über dasuwsgi-Protokoll an unsere uWSGI-Instanz weiter. Wir werden den zuvor konfigurierten Unix-Socket verwenden:

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 brauchen. Es gibt einige Verbesserungen, die für eine vollständigere Anwendung vorgenommen werden könnten. Zum Beispiel könnten wir eine Anzahl von Upstream-uWSGI-Servern außerhalb dieses Blocks definieren und diese dann an diesen übergeben. Wir könnten einige weitere uWSGI-Parameter hinzufügen. Wir können auch statische Dateien von Nginx direkt verarbeiten und nur dynamische Anforderungen an die uWSGI-Instanz übergeben.

Wir benötigen jedoch keine dieser Funktionen in unserer dreizeiligen App, sodass wir die Datei speichern und schließen können.

Aktivieren Sie die soeben vorgenommene Serverkonfiguration, indem Sie sie mit dem Verzeichnissites-enabledverknü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

Nach dem Neustart von Nginx sollten Sie in der Lage sein, den Domänennamen oder die IP-Adresse Ihres Servers (ohne eine Portnummer) aufzurufen und die von Ihnen konfigurierte Anwendung anzuzeigen:

full WSGI app

Fazit

Wenn Sie es bis hierher geschafft haben, haben Sie eine einfache WSGI-Anwendung erstellt und erhalten einen Einblick, wie komplexere Anwendungen entworfen werden müssten. Wir haben den uWSGI-Anwendungscontainer / -Server in einer speziell für unsere Anwendung entwickelten virtuellen Umgebung installiert. 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 über dasuwsgi-Drahtprotokoll mit dem uWSGI-Prozess kommunizieren kann.

Sie können leicht erkennen, wie dies beim Einrichten einer tatsächlichen Produktionsumgebung erweitert werden kann. Zum Beispiel kann uWSGI mehrere Anwendungen mit dem so genannten "Kaisermodus" verwalten. Sie können die Nginx-Konfiguration erweitern, um einen Lastenausgleich zwischen uWSGI-Instanzen vorzunehmen oder statische Dateien für Ihre Anwendung zu verarbeiten. Wenn Sie mehrere Anwendungen bereitstellen, ist es möglicherweise in Ihrem Interesse, uWSGI global anstatt in einer virtuellen Umgebung zu installieren. Dies hängt von Ihren Anforderungen ab. Die Komponenten sind alle recht flexibel, daher sollten Sie in der Lage sein, ihre Konfiguration für viele verschiedene Szenarien anzupassen.