L'auteur a sélectionné lesInternet Archive pour recevoir un don dans le cadre du programmeWrite for DOnations.
introduction
Le développement d'applications Web peut devenir complexe et prendre beaucoup de temps lors de la création et de la maintenance d'un certain nombre de technologies différentes. Si vous envisagez des options plus légères conçues pour réduire la complexité et le temps de production de votre application, vous obtiendrez une solution plus flexible et évolutive. En tant que micro-framework Web basé surPython,Flask offre aux développeurs un moyen extensible de développer leurs applications grâce à des extensions pouvant être intégrées dans des projets. Pour continuer l'évolutivité de la pile technologique d'un développeur,MongoDB est une base de données NoSQL conçue pour évoluer et fonctionner avec des changements fréquents. Les développeurs peuvent utiliserDocker pour simplifier le processus d'empaquetage et de déploiement de leurs applications.
Docker Compose a encore simplifié l'environnement de développement en vous permettant de définir votre infrastructure, y compris vos services d'application, vos volumes réseau et vos montages de liaison, dans un seul fichier. L'utilisation de Docker Compose facilite l'utilisation de l'exécution de plusieurs commandesdocker container run
. Il vous permet de définir tous vos services dans un seul fichier Compose. En une seule commande, vous créez et démarrez tous les services à partir de votre configuration. Cela garantit qu’il existe un contrôle de version dans l’ensemble de votre infrastructure de conteneur. Docker Compose utilise un nom de projet pour isoler les environnements les uns des autres, ce qui vous permet d'exécuter plusieurs environnements sur un seul hôte.
Dans ce didacticiel, vous allez créer, empaqueter et exécuter votre application Web à faire avec Flask, Nginx et MongoDB à l'intérieur de Dockercontainers. Vous définirez toute la configuration de la pile dans un fichierdocker-compose.yml
, ainsi que les fichiers de configuration pour Python, MongoDB et Nginx. Flask nécessite un serveur Web pour traiter les requêtes HTTP, vous utiliserez donc égalementGunicorn, qui est un serveur HTTP Python WSGI, pour servir l'application. Nginx agit comme un serveur proxy inverse qui transmet les demandes à Gunicorn pour traitement.
Conditions préalables
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants:
-
Un utilisateur non root avec les privilèges
sudo
configurés en suivant les étapes du didacticielInitial Server Setup. -
Docker installé avec les instructions des étapes 1 et 2 deHow To Install and Use Docker.
-
Docker Compose installé avec les instructions de l'étape 1 deHow To Install Docker Compose.
[[step-1 -—- writing-the-stack-configuration-in-docker-compose]] == Étape 1 - Ecriture de la configuration de la pile dans Docker Compose
Construire vos applications sur Docker vous permet de mettre à niveau l’infrastructure en fonction des modifications apportées à la configuration dans Docker Compose. L'infrastructure peut être définie dans un seul fichier et construite avec une seule commande. Dans cette étape, vous allez configurer le fichierdocker-compose.yml
pour exécuter votre application Flask.
Le fichierdocker-compose.yml
vous permet de définir votre infrastructure d'application en tant que services individuels. Les services peuvent être connectés les uns aux autres et chacun peut être associé à unvolume pour un stockage persistant. Les volumes sont stockés dans une partie du système de fichiers hôte géré par Docker (/var/lib/docker/volumes/
sous Linux).
Les volumes constituent le meilleur moyen de conserver des données dans Docker, car les données des volumes peuvent être exportées ou partagées avec d'autres applications. Pour plus d'informations sur le partage de données dans Docker, vous pouvez vous référer àHow To Share Data Between the Docker Container and the Host.
Pour commencer, créez un répertoire pour l'application dans le répertoire de base de votre serveur:
mkdir flaskapp
Déplacez-vous dans le répertoire nouvellement créé:
cd flaskapp
Ensuite, créez le fichierdocker-compose.yml
:
nano docker-compose.yml
Le fichierdocker-compose.yml
commence par un numéro de version qui identifie lesDocker Compose file version. La version du fichier Docker Compose3
cible la version1.13.0+
de Docker Engine, ce qui est une condition préalable à cette configuration. Vous ajouterez également la baliseservices
que vous définirez à l'étape suivante:
docker-compose.yml
version: '3'
services:
Vous allez maintenant définirflask
comme premier service dans votre fichierdocker-compose.yml
. Ajoutez le code suivant pour définir le service Flask:
docker-compose.yml
. . .
flask:
build:
context: app
dockerfile: Dockerfile
container_name: flask
image: digitalocean.com/flask-python:3.6
restart: unless-stopped
environment:
APP_ENV: "prod"
APP_DEBUG: "False"
APP_PORT: 5000
MONGODB_DATABASE: flaskdb
MONGODB_USERNAME: flaskuser
MONGODB_PASSWORD: your_mongodb_password
MONGODB_HOSTNAME: mongodb
volumes:
- appdata:/var/www
depends_on:
- mongodb
networks:
- frontend
- backend
La propriétébuild
définit lescontext
de la construction. Dans ce cas, le dossierapp
qui contiendra lesDockerfile
.
Vous utilisez la propriétécontainer_name
pour définir un nom pour chaque conteneur. La propriétéimage
spécifie le nom de l'image et ce que l'image Docker sera balisée. La propriétérestart
définit comment le conteneur doit être redémarré - dans votre cas, il s'agit deunless-stopped
. Cela signifie que vos conteneurs ne seront arrêtés que lorsque le moteur Docker est arrêté / redémarré ou lorsque vous arrêtez explicitement les conteneurs. L'avantage de l'utilisation de la propriétéunless-stopped
est que les conteneurs démarrent automatiquement une fois que le moteur Docker est redémarré ou qu'une erreur se produit.
La propriétéenvironment
contient les variables d'environnement qui sont transmises au conteneur. Vous devez fournir un mot de passe sécurisé pour la variable d'environnementMONGODB_PASSWORD
. La propriétévolumes
définit les volumes que le service utilise. Dans votre cas, le volumeappdata
est monté à l'intérieur du conteneur dans le répertoire/var/www
. La propriétédepends_on
définit un service dont Flask dépend pour fonctionner correctement. Dans ce cas, le serviceflask
dépendra demongodb
puisque le servicemongodb
sert de base de données pour votre application. depends_on
garantit que le serviceflask
ne s'exécute que si le servicemongodb
est en cours d'exécution.
La propriéténetworks
spécifiefrontend
etbackend
comme réseaux auxquels le serviceflask
aura accès.
Une fois le serviceflask
défini, vous êtes prêt à ajouter la configuration MongoDB au fichier. Dans cet exemple, vous utiliserez l'image officielle de4.0.8
versionmongo
. Ajoutez le code suivant à votre fichierdocker-compose.yml
en suivant lesflask service
:
docker-compose.yml
. . .
mongodb:
image: mongo:4.0.8
container_name: mongodb
restart: unless-stopped
command: mongod --auth
environment:
MONGO_INITDB_ROOT_USERNAME: mongodbuser
MONGO_INITDB_ROOT_PASSWORD: your_mongodb_root_password
MONGO_INITDB_DATABASE: flaskdb
MONGODB_DATA_DIR: /data/db
MONDODB_LOG_DIR: /dev/null
volumes:
- mongodbdata:/data/db
networks:
- backend
Lecontainer_name
pour ce service estmongodb
avec une politique de redémarrage deunless-stopped
. Vous utilisez la propriétécommand
pour définir la commande qui sera exécutée au démarrage du conteneur. La commandemongod --auth
désactivera la connexion au shell MongoDB sans informations d'identification, ce qui sécurisera MongoDB en exigeant une authentification.
Les variables d'environnementMONGO_INITDB_ROOT_USERNAME
etMONGO_INITDB_ROOT_PASSWORD
créent un utilisateur root avec les informations d'identification données, assurez-vous donc de remplacer l'espace réservé par un mot de passe fort.
MongoDB stocke ses données dans/data/db
par défaut, donc les données dans le dossier/data/db
seront écrites dans le volume nommémongodbdata
pour la persistance. Ainsi, vous ne perdrez pas vos bases de données en cas de redémarrage. Le servicemongoDB
n'expose aucun port, donc le service ne sera accessible que via le réseaubackend
.
Ensuite, vous allez définir le serveur Web pour votre application. Ajoutez le code suivant à votre fichierdocker-compose.yml
pour configurer Nginx:
docker-compose.yml
. . .
webserver:
build:
context: nginx
dockerfile: Dockerfile
image: digitalocean.com/webserver:latest
container_name: webserver
restart: unless-stopped
environment:
APP_ENV: "prod"
APP_NAME: "webserver"
APP_DEBUG: "false"
SERVICE_NAME: "webserver"
ports:
- "80:80"
- "443:443"
volumes:
- nginxdata:/var/log/nginx
depends_on:
- flask
networks:
- frontend
Ici, vous avez défini lescontext
dubuild
, qui est le dossiernginx
contenant lesDockerfile
. Avec la propriétéimage
, vous spécifiez l'image utilisée pour baliser et exécuter le conteneur. La propriétéports
configurera le service Nginx pour qu'il soit accessible au public via:80
et:443
etvolumes
monte le volumenginxdata
à l'intérieur du conteneur à/var/log/nginx
répertoire.
Vous avez défini le service sur lequel le service de serveur Webdepends_on
estflask
. Enfin, la propriéténetworks
définit le service de serveur Web des réseaux qui aura accès auxfrontend
.
Ensuite, vous allez créerbridge networks pour permettre aux conteneurs de communiquer entre eux. Ajoutez les lignes suivantes à la fin de votre fichier:
docker-compose.yml
. . .
networks:
frontend:
driver: bridge
backend:
driver: bridge
Vous avez défini deux réseaux -frontend
etbackend
- pour les services auxquels se connecter. Les services frontaux, tels que Nginx, se connecteront au réseaufrontend
car il doit être accessible au public. Les services back-end, tels que MongoDB, se connecteront au réseau debackend
pour empêcher tout accès non autorisé au service.
Vous utiliserez ensuite des volumes pour conserver la base de données, l'application et les fichiers de configuration. Puisque votre application utilisera les bases de données et les fichiers, il est impératif de conserver les modifications qui y ont été apportées. Les volumes sont gérés par Docker et stockés sur le système de fichiers. Ajoutez ce code au fichierdocker-compose.yml
pour configurer les volumes:
docker-compose.yml
. . .
volumes:
mongodbdata:
driver: local
appdata:
driver: local
nginxdata:
driver: local
La sectionvolumes
déclare les volumes que l'application utilisera pour conserver les données. Ici, vous avez défini les volumesmongodbdata
,appdata
etnginxdata
pour la persistance de vos bases de données MongoDB, des données d'application Flask et des journaux du serveur Web Nginx, respectivement. Tous ces volumes utilisent un pilotelocal
pour stocker les données localement. Les volumes sont utilisés pour conserver ces données afin que des données telles que vos bases de données MongoDB et les journaux du serveur Web Nginx puissent être perdus au redémarrage des conteneurs.
Votre fichierdocker-compose.yml
complet ressemblera à ceci:
docker-compose.yml
version: '3'
services:
flask:
build:
context: app
dockerfile: Dockerfile
container_name: flask
image: digitalocean.com/flask-python:3.6
restart: unless-stopped
environment:
APP_ENV: "prod"
APP_DEBUG: "False"
APP_PORT: 5000
MONGODB_DATABASE: flaskdb
MONGODB_USERNAME: flaskuser
MONGODB_PASSWORD: your_mongodb_password
MONGODB_HOSTNAME: mongodb
volumes:
- appdata:/var/www
depends_on:
- mongodb
networks:
- frontend
- backend
mongodb:
image: mongo:4.0.8
container_name: mongodb
restart: unless-stopped
command: mongod --auth
environment:
MONGO_INITDB_ROOT_USERNAME: mongodbuser
MONGO_INITDB_ROOT_PASSWORD: your_mongodb_root_password
MONGO_INITDB_DATABASE: flaskdb
MONGODB_DATA_DIR: /data/db
MONDODB_LOG_DIR: /dev/null
volumes:
- mongodbdata:/data/db
networks:
- backend
webserver:
build:
context: nginx
dockerfile: Dockerfile
image: digitalocean.com/webserver:latest
container_name: webserver
restart: unless-stopped
environment:
APP_ENV: "prod"
APP_NAME: "webserver"
APP_DEBUG: "true"
SERVICE_NAME: "webserver"
ports:
- "80:80"
- "443:443"
volumes:
- nginxdata:/var/log/nginx
depends_on:
- flask
networks:
- frontend
networks:
frontend:
driver: bridge
backend:
driver: bridge
volumes:
mongodbdata:
driver: local
appdata:
driver: local
nginxdata:
driver: local
Enregistrez le fichier et quittez l'éditeur après avoir vérifié votre configuration.
Vous avez défini la configuration Docker pour l'ensemble de votre pile d'applications dans le fichierdocker-compose.yml
. Vous allez maintenant écrire les fichiers Dockerfiles pour Flask et le serveur Web.
[[step-2 -—- writing-the-flask-and-web-server-dockerfiles]] == Étape 2 - Ecriture des Dockerfiles Flask et Web Server
Avec Docker, vous pouvez créer des conteneurs pour exécuter vos applications à partir d'un fichier appeléDockerfile. Dockerfile est un outil qui vous permet de créer des images personnalisées que vous pouvez utiliser pour installer le logiciel requis par votre application et configurer vos conteneurs en fonction de vos besoins. Vous pouvez pousser les images personnalisées que vous créez versDocker Hub ou n'importe quel registre privé.
Dans cette étape, vous écrivez les fichiers Docker pour les services Flask et Web Server. Pour commencer, créez le répertoireapp
pour votre application Flask:
mkdir app
Ensuite, créez lesDockerfile
pour votre application Flask dans le répertoireapp
:
nano app/Dockerfile
Ajoutez le code suivant au fichier pour personnaliser votre conteneur Flask:
app/Dockerfile
FROM python:3.6.8-alpine3.9
LABEL MAINTAINER="FirstName LastName "
ENV GROUP_ID=1000 \
USER_ID=1000
WORKDIR /var/www/
Dans ceDockerfile
, vous créez une image au-dessus des3.6.8-alpine3.9
image basée sur Alpine 3.9 avec Python 3.6.8 pré-installé.
La directiveENV
est utilisée pour définir les variables d'environnement pour notre groupe et notre ID utilisateur.
Linux Standard Base (LSB) spécifie queUIDs and GIDs 0-99 sont alloués statiquement par le système. LesUIDs 100-999 sont censés être alloués dynamiquement aux utilisateurs et groupes du système. LesUIDs 1000-59999 sont censés être alloués dynamiquement aux comptes utilisateurs. En gardant cela à l'esprit, vous pouvez attribuer en toute sécurité un UID et un GID de1000
, en outre, vous pouvez modifier l'UID / GID en mettant à jour lesGROUP_ID
etUSER_ID
pour répondre à vos besoins.
La directiveWORKDIR
définit le répertoire de travail du conteneur. Assurez-vous de remplacer le champLABEL MAINTAINER
par votre nom et votre adresse e-mail.
Ajoutez le bloc de code suivant pour copier l'application Flask dans le conteneur et installez les dépendances nécessaires:
app/Dockerfile
. . .
ADD ./requirements.txt /var/www/requirements.txt
RUN pip install -r requirements.txt
ADD . /var/www/
RUN pip install gunicorn
Le code suivant utilisera la directiveADD
pour copier les fichiers du répertoire localapp
vers le répertoire/var/www
du conteneur. Ensuite, le Dockerfile utilisera la directiveRUN
pour installer Gunicorn et les packages spécifiés dans le fichierrequirements.txt
, que vous créerez plus tard dans le didacticiel.
Le bloc de code suivant ajoute un nouvel utilisateur et un nouveau groupe et initialise l'application:
app/Dockerfile
. . .
RUN addgroup -g $GROUP_ID www
RUN adduser -D -u $USER_ID -G www www -s /bin/sh
USER www
EXPOSE 5000
CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"]
Par défaut, les conteneurs Docker s'exécutent en tant qu'utilisateurroot. L'utilisateur deroot a accès à tout dans le système, les implications d'une faille de sécurité peuvent donc être désastreuses. Pour atténuer ce risque de sécurité, cela créera un nouvel utilisateur et un groupe qui n'auront accès qu'au répertoire/var/www
.
Ce code utilisera d'abord la commandeaddgroup
pour créer un nouveau groupe nomméwww
. L'indicateur-g
définira l'ID de groupe sur la variableENV GROUP_ID=1000
définie précédemment dans lesDockerfile
.
Les lignesadduser -D -u $USER_ID -G www www -s /bin/sh
créent un utilisateurwww
avec un ID utilisateur de1000
, comme défini par la variableENV
. L'indicateur-s
crée le répertoire personnel de l'utilisateur s'il n'existe pas et définit le shell de connexion par défaut sur/bin/sh
. L'indicateur-G
est utilisé pour définir le groupe de connexion initial de l'utilisateur surwww
, qui a été créé par la commande précédente.
La commandeUSER
définit que les programmes exécutés dans le conteneur utiliseront l'utilisateurwww
. Gunicorn écoutera sur:5000
, vous ouvrirez donc ce port avec la commandeEXPOSE
.
Enfin, la ligneCMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"]
exécute la commande pour démarrer le serveur Gunicorn avec quatre workers écoutant sur le port5000
. Le nombre doit généralement être compris entre 2 et 4 nœuds de calcul par cœur dans le serveur, la documentation de Gunicorn recommande(2 x $num_cores) + 1
comme nombre de nœuds de calcul pour commencer.
VosDockerfile
complétés ressembleront à ceci:
app/Dockerfile
FROM python:3.6.8-alpine3.9
LABEL MAINTAINER="FirstName LastName "
ENV GROUP_ID=1000 \
USER_ID=1000
WORKDIR /var/www/
ADD . /var/www/
RUN pip install -r requirements.txt
RUN pip install gunicorn
RUN addgroup -g $GROUP_ID www
RUN adduser -D -u $USER_ID -G www www -s /bin/sh
USER www
EXPOSE 5000
CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"]
Enregistrez le fichier et quittez l'éditeur de texte.
Ensuite, créez un nouveau répertoire pour contenir votre configuration Nginx:
mkdir nginx
Ensuite, créez lesDockerfile
pour votre serveur Web Nginx dans le répertoirenginx
:
nano nginx/Dockerfile
Ajoutez le code suivant au fichier pour créer le fichier Dockerfile qui générera l'image pour votre conteneur Nginx:
nginx/Dockerfile
FROM digitalocean.com/alpine:latest
LABEL MAINTAINER="FirstName LastName "
RUN apk --update add nginx && \
ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log && \
mkdir /etc/nginx/sites-enabled/ && \
mkdir -p /run/nginx && \
rm -rf /etc/nginx/conf.d/default.conf && \
rm -rf /var/cache/apk/*
COPY conf.d/app.conf /etc/nginx/conf.d/app.conf
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
Ce NginxDockerfile
utilise une image de base dealpine
, qui est une petite distribution Linux avec une surface d'attaque minimale conçue pour la sécurité.
Dans la directiveRUN
, vous installeznginx
et créez des liens symboliques pour publier l'erreur et accéder aux journaux d'erreur standard (/dev/stderr
) et de sortie (/dev/stdout
). La publication des erreurs dans les erreurs et sorties standard est une pratique recommandée, car les conteneurs sont éphémères. Ainsi, les journaux sont expédiés vers les journaux du menu fixe et à partir de là, vous pouvez transférer vos journaux vers un service de journalisation tel que la pile Elastic pour la persistance. Une fois cela fait, des commandes sont exécutées pour supprimer lesdefault.conf
et/var/cache/apk/*
afin de réduire la taille de l'image résultante. L'exécution de toutes ces commandes en un seulRUN
diminue le nombre de calques dans l'image, ce qui réduit également la taille de l'image résultante.
La directiveCOPY
copie la configuration du serveur Webapp.conf
à l'intérieur du conteneur. La directiveEXPOSE
garantit que les conteneurs écoutent sur les ports:80
et:443
, car votre application fonctionnera sur:80
avec:443
comme port sécurisé.
Enfin, la directiveCMD
définit la commande pour démarrer le serveur Nginx.
Enregistrez le fichier et quittez l'éditeur de texte.
Maintenant que leDockerfile
est prêt, vous êtes prêt à configurer le proxy inverse Nginx pour acheminer le trafic vers l'application Flask.
[[step-3 -—- configuration-the-nginx-reverse-proxy]] == Étape 3 - Configuration du proxy inverse Nginx
Dans cette étape, vous allez configurer Nginx en tant que proxy inverse pour transmettre les requêtes à Gunicorn sur:5000
. Un serveur proxy inverse est utilisé pour diriger les demandes des clients vers le serveur principal approprié. Il fournit une couche supplémentaire d'abstraction et de contrôle pour assurer la fluidité du trafic réseau entre les clients et les serveurs.
Commencez par créer le répertoirenginx/conf.d
:
mkdir nginx/conf.d
Pour configurer Nginx, vous devez créer un fichierapp.conf
avec la configuration suivante dans le dossiernginx/conf.d/
. Le fichierapp.conf
contient la configuration dont le proxy inverse a besoin pour transmettre les requêtes à Gunicorn.
nano nginx/conf.d/app.conf
Placez le contenu suivant dans le fichierapp.conf
:
nginx/conf.d/app.conf
upstream app_server {
server flask:5000;
}
server {
listen 80;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
client_max_body_size 64M;
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
gzip_static on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_buffering off;
proxy_redirect off;
proxy_pass http://app_server;
}
}
Cela définira d'abord lesupstream server, qui sont couramment utilisés pour spécifier un serveur Web ou d'application pour le routage ou l'équilibrage de charge.
Votre serveur en amont,app_server
, définit l'adresse du serveur avec la directiveserver
, qui est identifiée par le nom de conteneurflask:5000
.
La configuration du serveur Web Nginx est définie dans le blocserver
. La directivelisten
définit le numéro de port sur lequel votre serveur écoutera les requêtes entrantes. Les directiveserror_log
etaccess_log
définissent les fichiers pour l'écriture des journaux. La directiveproxy_pass
est utilisée pour configurer le serveur en amont pour transmettre les requêtes àhttp://app_server
.
Enregistrez et fermez le fichier.
Avec le serveur Web Nginx configuré, vous pouvez passer à la création de l’API Flask to-do.
[[step-4 -—- creation-the-flask-to-do-api]] == Étape 4 - Création de l'API Flask To-do
Maintenant que vous avez créé votre environnement, vous êtes prêt à créer votre application. Dans cette étape, vous allez écrire une application API de tâches à effectuer qui enregistrera et affichera les notes de tâches envoyées à partir d'une demande POST.
Commencez par créer le fichierrequirements.txt
dans le répertoireapp
:
nano app/requirements.txt
Ce fichier est utilisé pour installer les dépendances de votre application. L'implémentation de ce didacticiel utiliseraFlask
,Flask-PyMongo
etrequests
. Ajoutez ce qui suit au fichierrequirements.txt
:
app/requirements.txt
Flask==1.0.2
Flask-PyMongo==2.2.0
requests==2.20.1
Enregistrez le fichier et quittez l'éditeur après avoir entré les conditions requises.
Ensuite, créez le fichierapp.py
pour contenir le code d'application Flask dans le répertoireapp
:
nano app/app.py
Dans votre nouveau fichierapp.py
, entrez le code pour importer les dépendances:
app/app.py
import os
from flask import Flask, request, jsonify
from flask_pymongo import PyMongo
Le packageos
est utilisé pour importer les variables d'environnement. À partir de la bibliothèqueflask
, vous avez importé les objetsFlask
,request
etjsonify
pour instancier l'application, gérer les demandes et envoyer des réponses JSON, respectivement. Depuisflask_pymongo
, vous avez importé l'objetPyMongo
pour interagir avec MongoDB.
Ensuite, ajoutez le code nécessaire pour vous connecter à MongoDB:
app/app.py
. . .
application = Flask(__name__)
application.config["MONGO_URI"] = 'mongodb://' + os.environ['MONGODB_USERNAME'] + ':' + os.environ['MONGODB_PASSWORD'] + '@' + os.environ['MONGODB_HOSTNAME'] + ':27017/' + os.environ['MONGODB_DATABASE']
mongo = PyMongo(application)
db = mongo.db
LeFlask(__name__)
charge l'objet d'application dans la variableapplication
. Ensuite, le code construit la chaîne de connexion MongoDB à partir des variables d'environnement à l'aide deos.environ
. Passer l'objetapplication
à la méthodePyMongo()
vous donnera l'objetmongo
, qui à son tour vous donnera l'objetdb
demongo.db
.
Maintenant, vous allez ajouter le code pour créer un message d'index:
app/app.py
. . .
@application.route('/')
def index():
return jsonify(
status=True,
message='Welcome to the Dockerized Flask MongoDB app!'
)
Le@application.route('/')
définit la route GET/
de votre API. Ici, votre fonctionindex()
renvoie une chaîne JSON en utilisant la méthodejsonify
.
Ensuite, ajoutez la route/todo
pour lister toutes les tâches:
app/app.py
. . .
@application.route('/todo')
def todo():
_todos = db.todo.find()
item = {}
data = []
for todo in _todos:
item = {
'id': str(todo['_id']),
'todo': todo['todo']
}
data.append(item)
return jsonify(
status=True,
data=data
)
Le@application.route('/todo')
définit la route GET/todo
de votre API, qui renvoie les tâches dans la base de données. La méthodedb.todo.find()
renvoie toutes les tâches de la base de données. Ensuite, vous parcourez les_todos
pour construire unitem
qui inclut uniquement lesid
ettodo
des objets en les ajoutant à un tableaudata
et retourne finalement eux comme JSON.
Ensuite, ajoutez le code pour la création de la tâche:
app/app.py
. . .
@application.route('/todo', methods=['POST'])
def createTodo():
data = request.get_json(force=True)
item = {
'todo': data['todo']
}
db.todo.insert_one(item)
return jsonify(
status=True,
message='To-do saved successfully!'
), 201
Le@application.route('/todo')
définit la route POST/todo
de votre API, qui crée une note à faire dans la base de données. Lerequest.get_json(force=True)
obtient le JSON que vous publiez sur la route, etitem
est utilisé pour créer le JSON qui sera enregistré dans la tâche. Ledb.todo.insert_one(item)
est utilisé pour insérer un élément dans la base de données. Une fois la tâche enregistrée dans la base de données, vous renvoyez une réponse JSON avec un code d'état201 CREATED
.
Maintenant, vous ajoutez le code pour exécuter l'application:
app/app.py
. . .
if __name__ == "__main__":
ENVIRONMENT_DEBUG = os.environ.get("APP_DEBUG", True)
ENVIRONMENT_PORT = os.environ.get("APP_PORT", 5000)
application.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG)
La condition__name__ == "__main__"
permet de vérifier si la variable globale,__name__
, dans le module est le point d'entrée de votre programme, est"__main__"
, puis lancez l'application. Si le__name__
est égal à"__main__"
alors le code à l'intérieur du blocif
exécutera l'application en utilisant cette commandeapplication.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG)
.
Ensuite, nous obtenons les valeurs desENVIRONMENT_DEBUG
etENVIRONMENT_PORT
à partir des variables d'environnement en utilisantos.environ.get()
, en utilisant la clé comme premier paramètre et la valeur par défaut comme deuxième paramètre. Leapplication.run()
définit les valeurshost
,port
etdebug
pour l'application.
Le fichierapp.py
terminé ressemblera à ceci:
app/app.py
import os
from flask import Flask, request, jsonify
from flask_pymongo import PyMongo
application = Flask(__name__)
application.config["MONGO_URI"] = 'mongodb://' + os.environ['MONGODB_USERNAME'] + ':' + os.environ['MONGODB_PASSWORD'] + '@' + os.environ['MONGODB_HOSTNAME'] + ':27017/' + os.environ['MONGODB_DATABASE']
mongo = PyMongo(application)
db = mongo.db
@application.route('/')
def index():
return jsonify(
status=True,
message='Welcome to the Dockerized Flask MongoDB app!'
)
@application.route('/todo')
def todo():
_todos = db.todo.find()
item = {}
data = []
for todo in _todos:
item = {
'id': str(todo['_id']),
'todo': todo['todo']
}
data.append(item)
return jsonify(
status=True,
data=data
)
@application.route('/todo', methods=['POST'])
def createTodo():
data = request.get_json(force=True)
item = {
'todo': data['todo']
}
db.todo.insert_one(item)
return jsonify(
status=True,
message='To-do saved successfully!'
), 201
if __name__ == "__main__":
ENVIRONMENT_DEBUG = os.environ.get("APP_DEBUG", True)
ENVIRONMENT_PORT = os.environ.get("APP_PORT", 5000)
application.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG)
Enregistrez le fichier et quittez l'éditeur.
Ensuite, créez le fichierwsgi.py
dans le répertoireapp
.
nano app/wsgi.py
Le fichierwsgi.py
crée un objet d'application (ou appelable) afin que le serveur puisse l'utiliser. Chaque fois qu'une demande est reçue, le serveur utilise cet objet d'application pour exécuter les gestionnaires de demandes de l'application lors de l'analyse de l'URL.
Placez le contenu suivant dans le fichierwsgi.py
, enregistrez le fichier et quittez l'éditeur de texte:
app/wsgi.py
from app import application
if __name__ == "__main__":
application.run()
Ce fichierwsgi.py
importe l'objet application à partir du fichierapp.py
et crée un objet application pour le serveur Gunicorn.
L'application Tâches est maintenant en place, vous êtes donc prêt à commencer à exécuter l'application dans des conteneurs.
[[step-5 -—- building-and-running-the-containers]] == Étape 5 - Construction et exécution des conteneurs
Maintenant que vous avez défini tous les services dans votre fichierdocker-compose.yml
et leurs configurations, vous pouvez démarrer les conteneurs.
Les services étant définis dans un seul fichier, vous devez émettre une seule commande pour démarrer les conteneurs, créer les volumes et configurer les réseaux. Cette commande crée également l'image de votre application Flask et du serveur Web Nginx. Exécutez la commande suivante pour construire les conteneurs:
docker-compose up -d
Lors de la première exécution de la commande, toutes les images Docker nécessaires seront téléchargées, ce qui peut prendre un certain temps. Une fois les images téléchargées et stockées sur votre machine locale,docker-compose
créera vos conteneurs. L'indicateur-d
démonise le processus, ce qui lui permet de s'exécuter en arrière-plan.
Utilisez la commande suivante pour répertorier les conteneurs en cours d'exécution une fois le processus de génération terminé:
docker ps
Vous verrez une sortie semblable à celle-ci:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f20e9a7fd2b9 digitalocean.com/webserver:latest "nginx -g 'daemon of…" 2 weeks ago Up 2 weeks 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp webserver
3d53ea054517 digitalocean.com/flask-python:3.6 "gunicorn -w 4 --bin…" 2 weeks ago Up 2 weeks 5000/tcp flask
96f5a91fc0db mongo:4.0.8 "docker-entrypoint.s…" 2 weeks ago Up 2 weeks 27017/tcp mongodb
LeCONTAINER ID
est un identifiant unique utilisé pour accéder aux conteneurs. LeIMAGE
définit le nom de l'image pour le conteneur donné. Le champNAMES
est le nom du service sous lequel les conteneurs sont créés, similaire àCONTAINER ID
, ils peuvent être utilisés pour accéder aux conteneurs. Enfin, leSTATUS
fournit des informations sur l'état du conteneur, qu'il soit en cours d'exécution, redémarré ou arrêté.
Vous avez utilisé la commandedocker-compose
pour créer vos conteneurs à partir de vos fichiers de configuration. Dans l'étape suivante, vous allez créer un utilisateur MongoDB pour votre application.
[[step-6 -—- creation-a-user-for-your-mongodb-database]] == Étape 6 - Création d'un utilisateur pour votre base de données MongoDB
Par défaut, MongoDB permet aux utilisateurs de se connecter sans informations d'identification et accorde des privilèges illimités. Dans cette étape, vous allez sécuriser votre base de données MongoDB en créant un utilisateur dédié pour y accéder.
Pour ce faire, vous aurez besoin du nom d'utilisateur et du mot de passe root que vous avez définis dans les variables d'environnement du fichierdocker-compose.yml
MONGO_INITDB_ROOT_USERNAME
etMONGO_INITDB_ROOT_PASSWORD
pour le servicemongodb
. En général, il est préférable d’éviter d’utiliser le compte administratif racine lors de l’interaction avec la base de données. Au lieu de cela, vous allez créer un utilisateur de base de données dédié pour votre application Flask, ainsi qu'une nouvelle base de données à laquelle l'application Flask sera autorisée à accéder.
Pour créer un nouvel utilisateur, démarrez d'abord un shell interactif sur le conteneurmongodb
:
docker exec -it mongodb bash
Vous utilisez la commandedocker exec
afin d'exécuter une commande dans un conteneur en cours d'exécution avec l'indicateur-it
pour exécuter un shell interactif à l'intérieur du conteneur.
Une fois à l'intérieur du conteneur, connectez-vous au compte administratif de MongoDBroot:
mongo -u mongodbuser -p
Vous serez invité à entrer le mot de passe que vous avez entré comme valeur de la variableMONGO_INITDB_ROOT_PASSWORD
dans le fichierdocker-compose.yml
. Le mot de passe peut être modifié en définissant une nouvelle valeur pour leMONGO_INITDB_ROOT_PASSWORD
dans le servicemongodb
, auquel cas vous devrez réexécuter la commandedocker-compose up -d
.
Exécutez la commandeshow dbs;
pour répertorier toutes les bases de données:
show dbs;
Vous verrez la sortie suivante:
Outputadmin 0.000GB
config 0.000GB
local 0.000GB
5 rows in set (0.00 sec)
La base de donnéesadmin
est une base de données spéciale qui accorde des autorisations administratives aux utilisateurs. Si un utilisateur a un accès en lecture à la base de donnéesadmin
, il aura des droits de lecture et d'écriture sur toutes les autres bases de données. Puisque la sortie répertorie la base de donnéesadmin
, l'utilisateur a accès à cette base de données et peut donc lire et écrire dans toutes les autres bases de données.
La sauvegarde de la première note à faire sera automatiquementcreate the MongoDB database. MongoDB vous permet de basculer vers une base de données qui n'existe pas à l'aide de la commandeuse database
. Il crée une base de données lorsqu'un document est enregistré dans une collection. Par conséquent, la base de données n'est pas créée ici. cela se produira lorsque vous sauvegarderez votre première note dans la base de données à partir de l'API. Exécutez la commandeuse
pour basculer vers la base de donnéesflaskdb
:
use flaskdb
Ensuite, créez un nouvel utilisateur qui sera autorisé à accéder à cette base de données:
db.createUser({user: 'flaskuser', pwd: 'your password', roles: [{role: 'readWrite', db: 'flaskdb'}]})
exit
Cette commande crée un utilisateur nomméflaskuser avec un accèsreadWrite
à la base de donnéesflaskdb
. Assurez-vous d'utiliser un mot de passe sécurisé dans le champpwd
. Lesuser
etpwd
ici sont les valeurs que vous avez définies dans le fichierdocker-compose.yml
sous la section des variables d'environnement pour le serviceflask
.
Connectez-vous à la base de données authentifiée avec la commande suivante:
mongo -u flaskuser -p your password --authenticationDatabase flaskdb
Maintenant que vous avez ajouté l'utilisateur, déconnectez-vous de la base de données.
exit
Et enfin, sortez du conteneur:
exit
Vous avez maintenant configuré une base de données et un compte utilisateur dédiés pour votre application Flask. Les composants de la base de données sont prêts. Vous pouvez maintenant exécuter l'application Flask to-do.
[[step-7 -—- running-the-flask-to-do-app]] == Étape 7 - Exécution de l'application Flask To-do
Maintenant que vos services sont configurés et en cours d'exécution, vous pouvez tester votre application en accédant àhttp://your_server_ip
dans un navigateur. De plus, vous pouvez exécutercurl
pour voir la réponse JSON de Flask:
curl -i http://your_server_ip
Vous recevrez la réponse suivante:
Output{"message":"Welcome to the Dockerized Flask MongoDB app!","status":true}
La configuration de l'application Flask est transmise à l'application à partir du fichierdocker-compose.yml
. La configuration de la connexion à la base de données est définie à l'aide des variablesMONGODB_*
définies dans la sectionenvironment
du serviceflask
.
Pour tout tester, créez une note à l'aide de l'API Flask. Vous pouvez le faire avec une requête curlPOST
vers la route/todo
:
curl -i -H "Content-Type: application/json" -X POST -d '{"todo": "Dockerize Flask application with MongoDB backend"}' http://your_server_ip/todo
Cette demande aboutit à une réponse avec un code d'état de201 CREATED
lorsque l'élément à faire est enregistré dans MongoDB:
Output{"message":"To-do saved successfully!","status":true}
Vous pouvez lister toutes les notes de tâches de MongoDB avec une requête GET à la route/todo
:
curl -i http://your_server_ip/todo
Output{"data":[{"id":"5c9fa25591cb7b000a180b60","todo":"Dockerize Flask application with MongoDB backend"}],"status":true}
Avec cela, vous avez dockérisé une API Flask exécutant un backend MongoDB avec Nginx en tant que proxy inverse déployé sur vos serveurs. Pour un environnement de production, vous pouvez utilisersudo systemctl enable docker
pour vous assurer que votre service Docker démarre automatiquement au moment de l'exécution.
Conclusion
Dans ce didacticiel, vous avez déployé une application Flask avec Docker, MongoDB, Nginx et Gunicorn. Vous disposez maintenant d'une application API moderne sans état qui fonctionne et peut être mise à l'échelle. Bien que vous puissiez obtenir ce résultat en utilisant une commande commedocker container run
, ledocker-compose.yml
simplifie votre travail car cette pile peut être placée dans le contrôle de version et mise à jour si nécessaire.
De là, vous pouvez également jeter un œil à nos autresPython Framework tutorials.