Flask
Distribuzione dell'applicazione Flask usando il server web uWSGI con Nginx
Ricerca…
Usando uWSGI per eseguire un'applicazione flask
Il server werkzeug
integrato non è certamente adatto per l'esecuzione di server di produzione. La ragione più ovvia è il fatto che il server werkzeug
è a thread singolo e quindi può gestire solo una richiesta alla volta.
Per questo motivo, vogliamo utilizzare uWSGI Server per servire la nostra applicazione. In questo esempio installeremo uWSGI ed eseguiremo una semplice applicazione di test.
Installare uWSGI :
pip install uwsgi
È così semplice. Se non sei sicuro della versione python che usi, pip lo rende esplicito:
python3 -m pip install uwsgi # for python3
python2 -m pip install uwsgi # for python2
Ora creiamo una semplice applicazione di test:
app.py
from flask import Flask
from sys import version
app = Flask(__name__)
@app.route("/")
def index():
return "Hello uWSGI from python version: <br>" + version
application = app
In flask il nome convenzionale dell'applicazione è app
ma uWSGI cerca l' application
per impostazione predefinita. Ecco perché creiamo un alias per la nostra app nell'ultima riga.
Ora è il momento di eseguire l'app:
uwsgi --wsgi-file app.py --http :5000
Dovresti vedere il messaggio "Hello uWSGI ..." puntando il tuo browser su localhost:5000
Per non digitare il comando completo ogni volta che creeremo un file uwsgi.ini
per memorizzare quella configurazione:
uwsgi.ini
[uwsgi]
http = :9090
wsgi-file = app.py
single-interpreter = true
enable-threads = true
master = true
Le opzioni http
e wsgi-file
sono le stesse del comando manuale. Ma ci sono altre tre opzioni:
single-interpreter
: si consiglia di attivare questa opzione perché potrebbe interferire con l'opzione successivaenable-threads
: questo deve essere attivato se si stanno utilizzando thread aggiuntivi nell'applicazione. Non li usiamo in questo momento ma ora non dobbiamo preoccuparcene.master
: la modalità Master dovrebbe essere abilitata per vari motivi
Ora possiamo eseguire l'app con questo comando:
uwsgi --ini uwsgi.ini
Installare nginx e configurarlo per uWSGI
Ora vogliamo installare nginx per servire la nostra applicazione.
sudo apt-get install nginx # on debian/ubuntu
Quindi creiamo una configurazione per il nostro sito web
cd /etc/nginx/site-available # go to the configuration for available sites
# create a file flaskconfig with your favourite editor
flaskconfig
server {
listen 80;
server_name localhost;
location / {
include uwsgi_params;
uwsgi_pass unix:///tmp/flask.sock;
}
}
Questo dice a nginx di ascoltare sulla porta 80 (predefinita per http) e di servire qualcosa nel percorso root ( /
). Qui diciamo a nginx di agire come un proxy e passare ogni richiesta a un socket chiamato flask.sock
trova in /tmp/
.
Abilitiamo il sito:
cd /etc/nginx/sites-enabled
sudo ln -s ../sites-available/flaskconfig .
Potresti voler rimuovere la configurazione predefinita se è abilitata:
# inside /etc/sites-enabled
sudo rm default
Quindi riavvia nginx:
sudo service nginx restart
Indirizza il tuo browser su localhost
e vedrai un errore: 502 Bad Gateway
.
Ciò significa che nginx è attivo e funzionante, ma manca il socket. Quindi lasciamolo creare.
Torna al tuo file uwsgi.ini
e aprilo. Quindi aggiungi queste righe:
socket = /tmp/flask.sock
chmod-socket = 666
La prima riga dice a uwsgi di creare un socket nella posizione specificata. Il socket verrà utilizzato per ricevere richieste e inviare le risposte. Nell'ultima riga permettiamo ad altri utenti (incluso nginx) di essere in grado di leggere e scrivere da quel socket.
Avvia di nuovo uwsgi con uwsgi --ini uwsgi.ini
. Ora indirizza nuovamente il browser a localhost
e vedrai di nuovo il saluto "Hello uWSGI".
Si noti che è ancora possibile vedere la risposta su localhost:5000
perché uWSGI ora serve l'applicazione tramite http e il socket. Quindi disabilitiamo l'opzione http nel file ini
http = :5000 # <-- remove this line and restart uwsgi
Ora è possibile accedere all'app solo da nginx (o leggendo direttamente da tale socket :)).
Abilita lo streaming dal pallone
Flask ha quella caratteristica che ti permette di trasmettere i dati da una vista usando i generatori.
Cambiamo il file app.py
- aggiungere
from flask import Response
- aggiungi
from datetime import datetime
- aggiungere
from time import sleep
- crea una nuova vista:
@app.route("/time/")
def time():
def streamer():
while True:
yield "<p>{}</p>".format(datetime.now())
sleep(1)
return Response(streamer())
Ora apri il tuo browser su localhost/time/
. Il sito verrà caricato per sempre perché nginx attende fino al completamento della risposta. In questo caso la risposta non sarà mai completa perché invierà per sempre la data e l'ora correnti.
Per evitare l'attesa di nginx, è necessario aggiungere una nuova riga alla configurazione.
Modifica /etc/nginx/sites-available/flaskconfig
server {
listen 80;
server_name localhost;
location / {
include uwsgi_params;
uwsgi_pass unix:///tmp/flask.sock;
uwsgi_buffering off; # <-- this line is new
}
}
La linea uwsgi_buffering off;
dice a nginx di non aspettare fino al completamento di una risposta.
Riavvia nginx: il sudo service nginx restart
e guarda localhost/time/
again.
Ora vedrai che ogni secondo appare una nuova linea.
Configurazione di Flask Application, uWGSI, Nginx - Modello di configurazione delle configurazioni del server (predefinito, proxy e cache)
Questo è un porting di setup originato dal tutorial di DigitalOcean su How to Serve Flask Applications con uWSGI e Nginx su Ubuntu 14.04
e alcune utili risorse git per i server nginx.
Applicazione del matraccio
Questo tutorial presume che tu usi Ubuntu.
- locate
var/www/
folder. - Crea la tua cartella web app
mkdir myexample
-
cd myexample
facoltativo Si consiglia di configurare l'ambiente virtuale per la distribuzione di applicazioni Web sul server di produzione.
sudo pip install virtualenv
per installare l'ambiente virtuale.
virtualenv myexample
per configurare l'ambiente virtuale per la tua app.
source myprojectenv/bin/activate
per attivare il tuo ambiente. Qui installerai tutti i pacchetti python.
fine opzionale ma raccomandato
Configura flask e gateway uWSGI
Installa il pallone e il gateway uSWGI:
pip install uwsgi flask
Esempio di app per flask in myexample.py:
from flask import Flask
application = Flask(__name__)
@application.route("/")
def hello():
return "<h1>Hello World</h1>"
if __name__ == "__main__":
application.run(host='0.0.0.0')
Crea un file per comunicare tra la tua app Web e il server web: interfaccia gateway [ https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface]
nano wsgi.py
quindi importa il modulo webapp e fallo partire dal punto di ingresso del gateway.
from myexample import application
if __name__ == "__main__":
application.run()
Per testare uWSGI:
uwsgi --socket 0.0.0.0:8000 --protocol=http -w wsgi
Per configurare uWSGI:
Creare un file di configurazione
.ini
nano myexample.ini
Configurazione di base per gateway uWSGI
# include header for using uwsgi
[uwsgi]
# point it to your python module wsgi.py
module = wsgi
# tell uWSGI to start a master node to serve requests
master = true
# spawn number of processes handling requests
processes = 5
# use a Unix socket to communicate with Nginx. Nginx will pass connections to uWSGI through a socket, instead of using ports. This is preferable because Nginx and uWSGI stays on the same machine.
socket = myexample.sock
# ensure file permission on socket to be readable and writable
chmod-socket = 660
# clean the socket when processes stop
vacuum = true
# use die-on-term to communicate with Ubuntu versions using Upstart initialisations: see:
# http://uwsgi-docs.readthedocs.io/en/latest/Upstart.html?highlight=die%20on%20term
die-on-term = true
facoltativo se si utilizza l'ambiente virtuale È possibile deactivate
l'ambiente virtuale.
Configurazione di Nginx Useremo nginx come:
- server predefinito per passare la richiesta al socket, usando il protocollo uwsgi
- server proxy davanti al server predefinito
- cache server per memorizzare le richieste riuscite (ad esempio, potresti voler memorizzare nella cache richieste GET se la tua applicazione web)
Individua la directory dei sites-available
e crea un file di configurazione per la tua applicazione:
sudo nano /etc/nginx/sites-available/myexample
Aggiungi il seguente blocco, nei commenti cosa fa:
server {
# setting up default server listening to port 80
listen 8000 default_server;
server_name myexample.com; #you can also use your IP
# specify charset encoding, optional
charset utf-8;
# specify root of your folder directory
root /var/www/myexample;
# specify locations for your web apps.
# here using /api endpoint as example
location /api {
# include parameters of wsgi.py and pass them to socket
include uwsgi_params;
uwsgi_pass unix:/var/www/myexample/myexample.sock;
}
}
# Here you will specify caching zones that will be used by your virtual server
# Cache will be stored in /tmp/nginx folder
# ensure nginx have permissions to write and read there!
# See also:
# http://nginx.org/en/docs/http/ngx_http_proxy_module.html
proxy_cache_path /tmp/nginx levels=1:2 keys_zone=my_zone:10m inactive=60m;
proxy_cache_key "$scheme$request_method$host$request_uri";
# set up the virtual host!
server {
listen 80 default_server;
# Now www.example.com will listen to port 80 and pass request to http://example.com
server_name www.example.com;
# Why not caching responses
location /api {
# set up headers for caching
add_header X-Proxy-Cache $upstream_cache_status;
# use zone specified above
proxy_cache my_zone;
proxy_cache_use_stale updating;
proxy_cache_lock on;
# cache all responses ?
# proxy_cache_valid 30d;
# better cache only 200 responses :)
proxy_cache_valid 200 30d;
# ignore headers to make cache expire
proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
# pass requests to default server on port 8000
proxy_pass http://example.com:8000/api;
}
}
Infine, collega il file alla directory sites-enabled
ai sites-enabled
. Per una spiegazione dei siti disponibili e abilitati, vedi risposta: [ http://serverfault.com/a/527644]
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
Hai finito ora con nginx. Tuttavia, potresti voler controllare questo modello di caldaia molto prezioso: [ https://github.com/h5bp/server-configs-nginx]
Molto utile per la messa a punto.
Ora prova Nginx:
sudo nginx -t
Avvia Nginx:
sudo service nginx restart
Automatizzare Ubuntu per avviare uWSGI L'ultima cosa è fare in modo che Ubuntu avvii il gateway wsgi comunicando con l'applicazione, altrimenti dovresti farlo manualmente.
- Individua la directory per gli script di inizializzazione in Ubuntu e crea un nuovo script:
sudo nano /etc/init/myexample.conf
Aggiungi blocco successivo, commenti in linea per spiegare cosa fa
# description for the purpose of this script description "uWSGI server instance configured to serve myproject" # Tell to start on system runtime 2, 3, 4, 5. Stop at any other level (0,1,6). # Linux run levels: [http://www.debianadmin.com/debian-and-ubuntu-linux-run-levels.html] start on runlevel [2345] stop on runlevel [!2345] # Set up permissions! "User" will be the username of your user account on ubuntu. setuid user # Allow www-data group to read and write from the socket file. # www-data is normally the group Nginx and your web applications belong to. # you may have all web application projects under /var/www/ that belongs to www-data group setgid www-data # tell Ubunutu which environment to use. # This is the path of your virtual environment: python will be in this path if you installed virtualenv. Otherwise, use path of your python installation env PATH=/var/www/myexample/myexample/bin # then tell to Ubuntu to change and locate your web application directory chdir /var/www/myexample # finally execute initialisation script, that load your web app myexample.py exec uwsgi --ini myexample.ini
Ora puoi attivare il tuo script: sudo start myexample