[PYTHON] Utilisation de Flask avec la configuration Nginx + gunicorn [Environnement local]

Résumé de cet article

Flask_Nginx_unicorn_diagramdrawio-Step1-Server (1).png

Tableau de référence rapide des articles

――Quand vous lisez un article similaire, pourquoi souvent? Que voulez-vous dire? Je me sens-> [Qu'est-ce que / qu'est-ce que ○○? ](Que signifie) --Je devrais bouger-> [Essayer de bouger](# Essayer de bouger) --Je veux en savoir plus sur le fichier de paramétrage de gunicorn et Nginx-> [Démêler le fichier de paramétrage et la commande start / end](#Unravel la commande start / end du fichier de paramétrage)

Essayez de bouger

Tout d'abord, fonctionnons avec la configuration ci-dessus. Installez les packages requis.

brew install nginx
pip install gunicorn

Structure du projet et contenu de chaque fichier

PROJECT
├── config
│   ├── gunicorn_settings.py #Fichier de configuration du serveur d'applications
│   └── nginx.conf           #Fichier de configuration du serveur Web
└── flask_app.py             #Application principale

--Fichier d'application
Cette fois, nous ne nous soucions pas du comportement de l'application, nous allons donc préparer seulement deux routes pour renvoyer la chaîne de caractères.

flask_app.py


from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Index Page!'

@app.route('/health')
def health():
    return 'Health Check OK!!'

--Fichier de configuration du serveur Web

gunicorn_settings.py


import os

bind = '127.0.0.1:' + str(os.getenv('PORT', 9876))
proc_name = 'Infrastructure-Practice-Flask'
workers = 1

--Fichier de configuration Nginx

nginx.conf


#Voir la section du fichier de configuration pour plus de détails
worker_processes  1;

events {
	worker_connections 512;
}

http {
    server {
    	listen  9123;
    	server_name INFRA-PRACTICE-NGINX;
		charset UTF-8;

		proxy_set_header    Host    $host;

    	location / {
        	proxy_pass http://127.0.0.1:9876;
    	}

	    location /health/ {
        	proxy_pass http://127.0.0.1:9876/health;
    	}
    }
}

Démarrez le processus

Terminal


#Démarrez le serveur Web
nginx -c ${PROJECT_PATH}/config/nginx.conf

#Démarrer le serveur d'applications
gunicorn flask_app:app -c config/gunicorn_settings.py

Confirmer la communication

Terminal


curl http://localhost:9123/
# -> Index Page!OK si ça revient
curl http://localhost:9123/health/
# -> Health Check OK!!OK si ça revient

Démêler le fichier de paramètres et les commandes de démarrage / fin

gunicorn

fichier de configuration

Dans les Documents officiels, il est décrit dans un format facultatif. Lors de l'utilisation d'un fichier de paramétrage, il est écrit au format key = value avec le nom de l'élément de paramétrage comme clé (* par exemple * loglevel = 'debug'). L'extension du fichier de paramètres est arbitraire. Certains des paramètres sont indiqués ci-dessous.

key sens Moule        Valeur par défaut
reload Relire et redémarrer automatiquement lorsque le code change bool False
accesslog Accéder à la destination de sortie du journal sur le serveur
Spécifiez le fichier, "-Signifie une sortie standard
e.g. accesslog = logs/gunicorn_access.log
string None
errorlog Destination de sortie du journal des erreurs
Spécifiez le fichier, "-Signifie une sortie standard
e.g. errorlog = logs/gunicorn_err.log
string '-'
proc_name Nom du processus affiché par la commande ps
Par défaut, sauf indication contraire_proc_Cela devient le nom "gunicorn"
string None
limit_request_line Taille maximale de la demande, spécifiée par les mesures DDos
Limiter aux articles similaires_request_fields
int 4094
bind Hôte et port de connexion
HOST:Spécifié au format PORT
e.g. bind = os.getenv('HOST') + ':' + os.getenv('PORT')
string 127.0.0.1:8000
daemon Démarrez le processus gunicorn en tant que démon bool False
workers Nombre de processus de travail traitant les demandes
Un processus parent est démarré et autant de processus enfants qu'il y a de processus sont configurés et gérés ici.
Spécifier 2 ou plus lorsque le parallélisme ne peut pas être pris en compte entraînera un problème.
int 1
worker_connections Nombre maximum de connexions int 1000

Commande de début / fin

【Commencez】

Terminal


gunicorn {Nom du fichier d'application Flask}:{Nom de la variable d'instance Flask dans le fichier} -c {Chemin du fichier de configuration}

[Fin] Ctrl + C dans le terminal où le processus est en cours d'exécution

Nginx

fichier de configuration

En regardant les Documents officiels, contrairement au format key = value de gunicorn, Vous pouvez voir que la directive (instruction) est décrite dans le format de contexte (* accolade: * bloc inclus dans {}) à l'intérieur du module.

Module

Nom du module Contenu à décrire
core Journal, contrôle de processus
C'est le contexte le plus extérieur
events Traitement des événements
http Traitement lié au serveur Web
Probablement le plus décrit ce module

Directive Syntax in http context Contexte du serveur dans le contexte http, contexte de localisation supplémentaire dans le contexte du serveur Et ainsi de suite, nous écrirons en contexte dans un format contextuel. Voici un exemple de configuration du bloc http. En regardant l'exemple, vous pouvez comprendre ce que signifie le fichier de paramètres au début.

--Paramètres de base

config


http {
    server {
        listen        80;                          #Attendez la connexion sur le port 80
        server_name   MY_SERVER;                   #Le nom du serveur est MY_SERVER
        charset       UTF-8;                       #Contenu de l'en-tête de la réponse-tapez en UTF-Désigné comme 8
        error_page    404  /404_not_found.html;    #404 lorsque le code d'état est 404_not_found.Redirection interne vers html
    }
}

config


http {
    server {
        # /Accès à l'index
        location /index {
            proxy_pass          http://127.0.0.1:8080;  # 127.0.0.Proxy inverse vers le port 1 8080
            proxy_set_header    Host    $host;          #Parmi les en-têtes de demande transmis au serveur proxy, l'hôte$Réinitialiser l'hôte
        proxy_read_timeout  60s;                    #Délai d'attente en l'absence de réponse du serveur mandaté pendant 60 secondes
        }
    }
}

config


config
http {
    server {
        location / {
            allow 192.168.0.1;    # 192.168.0.Autoriser l'accès à partir de 1
            deny  all;            #Refuser tout autre accès au réseau
        }
    }
}

--Certification BASIQUE

config


http {
    server {
        location / {
            auth_basic             "Basic Auth closed site";  #Précisez que l'authentification BASIC est requise
            auth_basic_user_file   conf/htpasswd;               # .htpasswd Spécifiez le chemin du fichier
        }
    }
}

--Contrôle par référence

config


http {
    server {
        #Il n'y a pas de référent dans l'en-tête de la demande(none), Dans l'en-tête mais http://Ou https://Ne commence pas par(blocked)、
        # mintak.Ne se termine pas par com(server_names)Jugé invalide lors de l'accès à partir de la racine->$invalid_Définir le référent sur 1
        valid_referers none blocked server_names *mintak.com
        if ($invalid_referer) {
           return 403;  #S'il est jugé invalide, il sera renvoyé avec 403 Interdit.
        }
    }
}

Embbed Variable Quelque chose comme une variable d'environnement sur un serveur Nginx. Pour plus d'informations, cliquez ici (https://nginx.org/en/docs/http/ngx_http_core_module.html#variables). Certains sont présentés ci-dessous.

variable Contenu
$host Hôte dans l'en-tête de la demande, nom du serveur sinon
$remote_addr Adresse du client de connexion
$remote_port Port du client de connexion
$status État de la réponse
$server_name Nom du serveur
$http_name Définissez le nom du champ d'en-tête dans le score le plus bas dans le champ d'en-tête de la requête HTTP et la partie du nom avec un trait de soulignement
e.g. http_host、http_referer

Commande de début / fin

【Commencez】

Terminal


nginx -c {Chemin du fichier de configuration}

[Fin]

Terminal


nginx -s stop

#Si ce qui précède échoue, identifiez le processus et tuez
ps ax | grep nginx
kill -9 ${PID}

[Confirmation de démarrage]

Terminal


ps aux | grep nginx    #Ici nginx:Si cela indique le processus maître, nginx est en cours d'exécution.

#Commande qui peut confirmer PORT
lsof -i -P | grep nginx
#=> nginx     41845 mintak    6u  IPv4 0x595e7f947462ada5      0t0  TCP *:9123 (LISTEN)

Qu'est-ce que ○○?

Vous pouvez atteindre l'objectif en préparant les fichiers jusqu'à ce point et en appuyant sur la commande. Cependant, il existe de nombreux mots et concepts difficiles pour les débutants comme moi. À partir de là, je décrirai ma propre interprétation de ces mots-clés.

Pourquoi est-ce une telle configuration

Selon un expert, le serveur Web et le serveur d'applications n'étaient pas séparés dans le passé. Cette configuration est devenue problématique face au fait qu'avec la diffusion d'Internet, le nombre d'accès aux services ouverts au public a augmenté, ce qui a augmenté la charge sur le serveur et réduit les performances globales. fait. Par conséquent, en visant un fonctionnement stable en répartissant la charge, le flux consiste à diviser le serveur selon le rôle décrit plus loin. Cette idée est courante dans les temps modernes, et il semble que les services Web sont généralement constitués d'une structure à trois couches de serveur Web <-> serveur d'application <-> serveur de base de données. Je pense que l'idée de base de ** séparer les processus (serveurs) pour chaque rôle ** a quelque chose en commun avec le concept de conception pour le codage (un rôle clair pour chaque classe / fonction).

Mais cela fonctionne avec python flask_app.run

En effet, le framework appelé Flask est un framework qui peut être démarré tout en servant simultanément de serveur Web / serveur d'applications. Il est utile lorsqu'il est difficile de configurer séparément le serveur Web et le serveur d'applications, comme ** pour une simple vérification et un contrôle de fonctionnement pendant le développement **. Au démarrage de cette commande, le journal "AVERTISSEMENT: Ceci est un serveur de développement. Ne l'utilisez pas dans un développement de production .`" apparaît [^ 1], mais il est pour le développement uniquement, et avec cette configuration, l'accès en masse Cela signifie qu'il y a un gros risque de crevaison pendant le traitement, donc ** arrêter la production **.

Le rôle principal du serveur Web et du serveur d'applications

Je résumerai chacun en un mot. Voir la page de lien de référence pour plus de détails.

Pourquoi un proxy inverse est-il inversé?

S'il y a un inverse, il y a un avant **. Ce que nous appelons généralement un proxy est un proxy direct.

Quelle est la différence entre un proxy direct et un proxy inverse?

Ils sont toujours par procuration l'un de l'autre. Le traitement entre client-> Internet est un proxy direct (serveur), et le traitement entre Internet-> serveur Web cible est un proxy inverse (serveur). [^ 2]

Flask_Nginx_unicorn_diagramdrawio-Step1-Porxy.png

Il vous suffit de vous connecter directement au serveur cible! Vous pourriez penser, mais vous pouvez bénéficier de mordre le serveur proxy (voir ci-dessous).

Utilisation du proxy direct

Utilisation Détails
Économie du travail En mettant temporairement en cache les données du site auquel on a accédé une fois, il est possible de raccourcir le temps jusqu'à l'acquisition des données sous forme de flux pour acquérir des données du cache sans accéder au Web pour le deuxième accès et les suivants.
Filtrage du contenu Bloquez l'accès à des sites spécifiques ici.
~~C'est principalement à cause de ce type que vous ne pouvez pas voir ce site sur le PC de votre entreprise~~

Utilisation du proxy inverse

Utilisation Détails
Sécurité renforcée Méthode d'accès spécifique(http://、https://Tel)ではない場合や特定のIPアドレス以外からのアクセスを遮断するTelの機構を持たせることが出来る。
Répartition de la charge(Équilibreur de charge) Une fois amorti, il distribue avec succès l'accès à plusieurs serveurs d'applications.
Accélérant Exploitation statique. Il est possible de réduire la charge sur le serveur et de renvoyer une réponse plus rapide en conservant le contenu de référence tel que les images et les fichiers html dans le cache.

Qu'est-ce que WSGI?

Abréviation de Web Server Gateway Interface. ~~ Connu sous le nom d'Uesugi-kun. ~~ Django et Flask sont des frameworks compatibles WSGI, et gunicorn et uWEGI sont des serveurs compatibles WSGI, donc je pense qu'il n'y a pas de problème de reconnaissance. Le fond de son apparence est le suivant. [^ 3]

・ Framework A-chan> Je suis cool, donc je suis fou sauf α-kun, un serveur web sympa ・ Framework B> J'aime un β-kun solide ♡

Dans le passé, les serveurs Web pouvant être utilisés pour chaque framework Web Python étaient limités (et vice versa). En fait, je voulais que B-chan utilise α-kun, mais ici, la relation de mariage avec A-chan sera un frein. Uesugi-kun et WEGI semblaient résoudre ce problème. WEGI dit: "Choisissons librement le serveur et le framework ~~ love ~~ Connectons-nous", comment communiquer dans la relation du framework d'application <-> Serveur Web J'ai établi la règle. Grâce aux serveurs et frameworks compatibles WSGI et WSGI, nous sommes désormais libres de choisir la combinaison serveur et framework. Je suis heureux.

References

[^ 1]: Lorsque FLASK_ENV = development n'est pas défini. [^ 2]: Cette fois, Nginx est à la fois un serveur proxy et un serveur Web. [^ 3]: Je pense que c'est la seule façon d'expliquer cette chose stupide. .. ..

Recommended Posts

Utilisation de Flask avec la configuration Nginx + gunicorn [Environnement local]
[Avec diagramme d'image] Nginx + gunicorn + Flask converti en Docker [Partie 2]
[Avec diagramme d'image] Nginx + gunicorn + Flask converti en Docker [Partie 1]
Utilisation de Chainer avec CentOS7 [Construction de l'environnement]
Application Web réalisée avec Python + Flask (en utilisant VScode) # 1-Construction d'environnement virtuel-
Créez rapidement un environnement d'exécution d'application Web Python3.4 + Nginx + uWSGI + Flask en utilisant pyenv sur Ubuntu 12.04
Programmation de compétition avec les paramètres de l'environnement local python
code-server Environnement local (3) Essayez d'utiliser le plug-in de VSCode
Déployer l'application flask avec mod_wsgi (à l'aide de pipenv)
Vue.js + Mémorandum de construction de l'environnement Flask ~ avec Anaconda3 ~
Obtenez un environnement local pour DynamoDB avec Docker
Créer un environnement Python + uWSGI + Nginx avec Docker
Résumé des paramètres de Nginx (édition Flask + Docker + Gunicorn)
Construire un environnement de NGINX + NGINX Unit + MySQL avec Docker
Flacon + Gunicorn + Nginx + Supervisor jusqu'à ce que cela fonctionne
Créez rapidement un environnement d'exécution d'application Web Python3.4 + Nginx + uWSGI + Flask en utilisant venv sur Ubuntu 14.04 LTS
Modèle de construction d'environnement de développement local Python [Flask / Django / Jupyter avec Docker + VS Code]
Conversion de l'environnement Django en Docker (Docker + Django + Gunicorn + nginx) Partie 2
Essayez d'utiliser l'environnement virtuel conda avec Jupyter Notebook
Créer un environnement de Nginx + uWSGI + Python (Django) avec docker
Envoyer msgpack avec ajax à l'environnement flask (werkzeug)
Conversion de l'environnement Django en Docker (Docker + Django + Gunicorn + nginx) Partie 3
Construction d'environnement virtuel avec Docker + Flask (Python) + notebook Jupyter
Créer un serveur local GIF animé avec Python + Flask
Serveur à grande échelle réalisé avec Nginx + uWSGI + Flask + Ubuntu (installation)
Journal de sortie vers la console avec Flask + Nginx sur Docker
[Python] J'ai essayé d'exécuter un serveur local en utilisant flask
Serveur à grande échelle réalisé avec Nginx + uWSGI + Flask + Ubuntu (implémentation)
Créer un environnement django avec docker-compose (MariaDB + Nginx + uWSGI)