So richten Sie uWSGI und Nginx für die Bereitstellung von Python-Apps unter CentOS 7 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 CentOS 7-Server installieren und konfigurieren.

Definitionen und Konzepte

Klärung einiger Begriffe

Bevor wir einsteigen, sollten wir uns mit verwirrenden Begriffen befassen, die mit den verwandten Konzepten zusammenhängen, mit denen wir uns befassen werden. Diese drei Begriffe sind austauschbar, haben jedoch unterschiedliche Bedeutungen:

  • * WSGI *: Eine Python spec, die 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 umfassenderen Webserver zu kommunizieren. Dies ist ein wire-Protokoll, 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 er ein definiertes "aufrufbares" Element 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 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 CentOS 7-Server installieren. Wir können das hauptsächlich mit + yum + und + pip + machen.

Zunächst müssen wir das EPEL-Repository installieren, damit wir auf eine größere Auswahl von Paketen zugreifen können. Wir können das einfach mit einem einzigen "+ yum +" - Befehl tun, indem wir Folgendes eingeben:

sudo yum install epel-release

Jetzt können wir unsere Komponenten installieren. Wir benötigen die Python-Entwicklungsbibliotheken und -Header, den Python-Paketmanager + pip + sowie den Nginx-Webserver und den Reverse-Proxy. Wir werden auch einen Compiler brauchen, um die uWSGI-Binärdatei momentan zu erstellen:

sudo yum install python-pip python-devel nginx gcc

Sobald die Paketinstallation abgeschlossen ist, haben Sie Zugriff auf den Python-Paketmanager + pip +. Damit können wir das Paket "+ virtualenv +" 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 Befehl "+ virtualenv ". Wir werden dies der Einfachheit halber " myappenv +" nennen:

virtualenv

Eine neue Python-Umgebung wird unter einem Verzeichnis namens "+ myappenv +" eingerichtet. Wir können diese Umgebung aktivieren, indem wir Folgendes eingeben:

source /bin/activate

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

()@:~/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 mit + pip + in unserer Umgebung 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 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 schreiben unsere Anwendung in eine Datei mit dem Namen "+ wsgi.py +" in unserem Anwendungsverzeichnis:

nano ~//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 ["<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 mit dem Namen "+ application ", weshalb wir unsere Funktion " application +" aufgerufen haben. Wie Sie sehen, sind zwei Parameter erforderlich.

Das erste haben wir "+ environ " genannt, da es sich um ein Schlüsselwert-Wörterbuch handelt, das einer Umgebungsvariablen ähnelt. Die zweite heißt " start_response +" und ist der Name, den die App intern verwendet, um auf den Webserver (uWSGI) zu verweisen, der abrufbar ist und gesendet wird. Diese beiden Parameternamen wurden einfach aufgrund ihrer Verwendung in den Beispielen in der Spezifikation PEP 333 ausgewählt, in der WSGI-Interaktionen definiert sind.

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 "200 OK" -Antwort und setzen den "+ Content-Type" -Header auf "+ text / 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 auch 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. Zum Beispiel enthalten Django-Projekte standardmäßig eine + wsgi.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 es anweisen, vorerst HTTP zu verwenden und den Port "+ 8080 +" abzuhören. 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 Domain-Namen Ihres Servers in Ihrem Webbrowser aufrufen, gefolgt von ": 8080 +", sollten Sie den Header-Text der ersten Ebene, den wir als Textkörper übergeben haben, in unserer Datei " wsgi.py +" sehen:

image: https: //assets.digitalocean.com/articles/nginx_uwsgi_wsgi_1404/test_app.png [Beispiel für eine wsgi-Anwendung]

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 einer Vielzahl von Formaten lesen, wir werden jedoch der Einfachheit halber das Format "+ .ini +" verwenden.

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

nano ~/myapp/myapp.ini

Im Inneren müssen wir einen Abschnitt namens "+ [uwsgi] +" erstellen. 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 wollen den anfänglichen "+ uwsgi +" - 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 anzeigen können. Da wir Nginx als Reverse-Proxy vor uWSGI konfigurieren, können wir dies ändern. Nginx implementiert einen " uwsgi " - Proxy-Mechanismus, bei dem es sich um ein schnelles Binärprotokoll handelt, mit dem uWSGI mit anderen Servern kommunizieren kann. Das " uwsgi " - Protokoll ist eigentlich das Standardprotokoll von uWSGI. Wenn Sie also eine Protokollspezifikation weglassen, wird auf " uwsgi +" 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.

Wir geben unseren eigenen Benutzernamen an, um den "+ uwsgi " - Server auszuführen und die Socket-Datei zu besitzen. Wir erstellen ein Verzeichnis unter " / run ", um die Socket-Datei abzulegen, damit sowohl uWSGI als auch Nginx darauf zugreifen können. Wir nennen den Socket selbst " myapp.sock ". Wir werden die Berechtigungen auf "664" ändern, damit Nginx darauf schreiben kann (wir werden uWSGI mit der von Nginx verwendeten Gruppe " www-data " starten. Wir werden auch die Option " vacuum +" hinzufügen, die den Socket entfernt, wenn der Prozess stoppt:

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid =
socket = /run/uwsgi/myapp.sock
chown-socket = :nginx
chmod-socket = 660
vacuum = true

Wir benötigen eine letzte Option, da wir eine systemd-Datei erstellen, um unsere Anwendung beim Booten zu starten. Systemd 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 Systemd wie erwartet verarbeitet werden können, müssen wir lediglich eine Option mit dem Namen "+ die-on-term +" hinzufügen, damit uWSGI den Prozess abbricht, anstatt ihn neu zu laden:

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid =
socket = /run/uwsgi/myapp.sock
chown-socket = :nginx
chmod-socket = 660
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 Systemd Unit-Datei zum Verwalten der App

Wir können beim Booten eine uWSGI-Instanz starten, damit unsere Anwendung immer verfügbar ist. Zu diesem Zweck können wir eine systemd-Unit-Datei erstellen. Wir werden dies im Verzeichnis "+ / etc / systemd / system" ablegen, das der beste Ort für vom Benutzer erstellte Unit-Dateien ist. Wir rufen die Unit-Datei "+ uwsgi.service" auf:

sudo nano /etc/systemd/system/uwsgi.service

Zunächst beginnen wir mit dem Abschnitt "+ [Unit] +", in dem wir unsere Metadaten anpassen können. Das einzige, was wir hier einfügen werden, ist eine Beschreibung unseres Service:

[Unit]
Description=uWSGI instance to serve myapp

Als nächstes werden wir den Abschnitt "+ [Service] " öffnen. Da wir eine virtuelle Umgebung verwenden, sind unsere Befehle zum Starten des Dienstes komplexer als dies traditionell der Fall ist. Wir werden den Befehl " ExecStartPre " verwenden, um sicherzustellen, dass unser Socket-Verzeichnis erstellt wird und den richtigen Parteien gehört. Dies kann fehlschlagen (indem Sie ein " - " nach dem Gleichheitszeichen setzen), falls diese bereits eingerichtet sind. Dies wird in einem einzigen Aufruf an " bash +" übergeben.

Für den eigentlichen Befehl "+ ExecStart ", mit dem uWSGI gestartet wird, übergeben wir die eigentlichen Befehle auch an " bash ". Dadurch können wir einige verschiedene Befehle ausführen, da nur ein einziger Befehl (in diesem Fall ` bash `) von dieser Direktive ausgeführt werden kann. Wir werden dies verwenden, um in unser Anwendungsverzeichnis zu wechseln, die virtuelle Umgebung zu aktivieren und uWSGI mit der von uns erstellten " .ini +" - Datei zu starten:

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown :nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home//myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

Nun müssen Sie nur noch den Abschnitt + [Install] + formulieren. Dies bestimmt, was passiert, wenn wir die Einheit aktivieren. Grundsätzlich wird festgelegt, welche Zustände das Gerät automatisch starten soll. Wir möchten festlegen, dass dieses Gerät bei Aktivierung gestartet wird, wenn sich der Server im Mehrbenutzermodus befindet:

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown :nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home//myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

[Install]
WantedBy=multi-user.target

Speichern und schließen Sie die Datei, sobald Sie die obige Konfiguration ausgeschrieben haben.

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

sudo systemctl start uwsgi

Überprüfen Sie, ob es ohne Probleme gestartet wurde, indem Sie Folgendes eingeben:

systemctl status uwsgi

Wenn keine Fehler aufgetreten sind, aktivieren Sie den Dienst, damit er beim Booten startet, indem Sie Folgendes eingeben:

sudo systemctl enable uwsgi

Sie können den Dienst jederzeit beenden, indem Sie Folgendes eingeben:

sudo systemctl stop uwsgi

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 eine Systemd-Einheitendatei erstellt. Unser uWSGI-Prozess überwacht einen Socket und kommuniziert mit dem Protokoll "+ uwsgi +".

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

Die Nginx-Konfiguration, die wir einrichten werden, ist äußerst einfach. Wir werden die vorhandene Datei + nginx.conf + modifizieren und einen neuen Serverblock hinzufügen. Öffne die Datei mit + sudo + zum Bearbeiten:

sudo nano /etc/nginx/nginx.conf

Vor dem Standard-Serverblock fügen wir Ihren eigenen Serverblock hinzu:

http {

   . . .

   include /etc/nginx/conf.d/*.conf;




   server {
       listen 80 default_server;
       server_name localhost;

       . . .

Der von uns erstellte Block enthält die Konfiguration für unseren uWSGI-Proxy. Die restlichen Konfigurationselemente unten befinden sich in diesem Block. Der Serverblock sollte Port 80 überwachen und auf den Domänennamen oder die IP-Adresse Ihres Servers antworten:

server {
   listen 80;
   server_name ;
}

Danach können wir einen einzigen Standortblock öffnen, der alle Anfragen bearbeitet. In diesem Block werden die in der Datei "+ / etc / nginx / uwsgi_params " enthaltenen " uwsgi +" -Parameter eingeschlossen und der Datenverkehr an den Socket übergeben, an dem uWSGI empfangsbereit ist:

server {
   listen 80;
   server_name ;

   location / {
       include uwsgi_params;
       uwsgi_pass unix:/run/uwsgi/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.

Sie können testen, ob Ihre Nginx-Konfiguration gültig ist, indem Sie Folgendes eingeben:

sudo nginx -t

Wenn dies ohne Fehler zurückgegeben wird, starten Sie den Dienst, indem Sie Folgendes eingeben:

sudo systemctl start nginx

Starten Sie Nginx beim Booten, indem Sie den Dienst aktivieren:

sudo systemctl enable nginx

Sie sollten in der Lage sein, den Domainnamen oder die IP-Adresse Ihres Servers (ohne eine Portnummer) aufzurufen und die von Ihnen konfigurierte Anwendung anzuzeigen:

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 eine Systemd-Unit-Datei erstellt, um diesen Prozess zu automatisieren. Vor dem uWSGI-Server haben wir einen Nginx-Reverse-Proxy eingerichtet, der über das Wire-Protokoll "+ uwsgi +" mit dem uWSGI-Prozess sprechen 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.