angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Gestion de plusieurs sites web (Flask) avec une seule configuration Docker

En partageant le code et (éventuellement) les modèles, nous évitons de faire des copies et réduisons le temps de maintenance.

30 septembre 2020
Dans Docker, Flask
post main image
https://unsplash.com/@windows

J'ai développé un site web Flask sur Docker mais après un certain temps, lorsque mon code est devenu plus stable, j'ai voulu utiliser la même configuration pour d'autres sites web. Pour un site web, j'ai fait une copie parce qu'il devait fonctionner hier. Mais ce que je voulais vraiment, c'était partager tout le code et certains modèles. Bien sûr, chaque site web a son propre répertoire statique, son répertoire de connexion, ses modèles, etc. La principale raison de partager est que le code est encore en cours de développement et que je ne veux pas maintenir plusieurs copies du même code.

Extension de mon script de compilation et de démarrage Docker

J'ai écrit un script interactif que j'utilise pour construire les Docker images et pour démarrer le conteneur Docker avec la bonne version. Avec ceux-ci, je peux exécuter le développement, les tests et les conteneurs staginglocal, et staging et la production, même en parallèle. Il suffit d'ouvrir une autre fenêtre de terminal et d'exécuter mon script de démarrage Docker . J'ai dû utiliser ce script pour prendre en charge plusieurs sites web. Dans le répertoire principal, il y a deux sous-répertoires :

  • docker-templates
  • docker-versions

Docker-templates conserve les modèles de Docker-compose lors de la création d'une nouvelle version pour un site web. Une version signifie toujours un nouvel ensemble de fichiers docker-compose et un fichier avec des variables d'environnement. En outre, pour staging et la production, elle contiendra également un fichier (taré) Docker image et, en option, un répertoire statique et un vidage de base de données.

Le script de construction Docker prend les fichiers dans le répertoire docker-templates approprié, génère un nouveau numéro de version, patche le nouveau numéro de version dans les fichiers, crée le nouveau répertoire de version dans docker-versions, et y place les fichiers. Cette configuration me permet d'apporter des modifications à Docker-compose et aux fichiers d'environnement dans docker-templates. Les nouvelles versions incluent les dernières modifications et les anciennes versions restent inchangées. Pour le développement et les tests, tous les fichiers d'application sont en dehors du conteneur, ce qui signifie que la génération d'une nouvelle image n'est nécessaire que lors de l'ajout ou de la suppression de paquets (requirements.txt). La nouvelle structure des répertoires :

.
|--  docker-templates
|   `-- sites
|       |--  peterspython
|       |   |--  docker-compose_development.yml
|       |   |--  docker-compose_production.yml
|       |   |--  docker-compose_shared.yml
|       |   |--  docker-compose_staginglocal.yml
|       |   |--  docker-compose_staging.yml
|       |   |--  docker-compose_testing.yml
|       |   |-- env_development
|       |   |-- env_production
|       |   |-- env_staging
|       |   |-- env_staginglocal
|       |   `-- env_testing
|       `-- anothersite
|           |--  docker-compose_development.yml
|           |--  docker-compose_production.yml
|           |--  docker-compose_shared.yml
|           |--  docker-compose_staginglocal.yml
|           |--  docker-compose_staging.yml
|           |--  docker-compose_testing.yml
|           |-- env_development
|           |-- env_production
|           |-- env_staging
|           |-- env_staginglocal
|           `-- env_testing
|--  docker-versions
|   `-- sites
|       |--  peterspython
|       |   |-- 1.821_development
|       |   |   |-- deployment.env
|       |   |   |--  docker-compose_deployment.yml
|       |   |   `--  docker-compose_shared.yml
|       |   |   ...
|       |   |-- 1.829_production
|       |   |   |-- deployment.env
|       |   |   |--  docker-compose_deployment.yml
|       |   |   |--  docker-compose_shared.yml
|       |   |   `--  peterspython_web_production_image_1.829.tar
|       `-- anothersite
|           |-- 1.778_development
|           |   |-- deployment.env
|           |   |--  docker-compose_deployment.yml
|           |   `--  docker-compose_shared.yml
|           `-- 1.779_development
|               |-- deployment.env
|               |--  docker-compose_deployment.yml
|               `--  docker-compose_shared.yml
|-- project

Le script de démarrage Docker me permet de sélectionner un site web (peterspython, autre site) et me présente ensuite un menu de toutes les versions. Lorsque je sélectionne une version, un menu est présenté avec une liste d'actions comme start a container, exec into a container, etc. Avant de démarrer une action, le script de démarrage Docker copie les fichiers du répertoire de la version docker dans le répertoire principal de sorte que nous ayons toujours les fichiers au même endroit comme si nous faisions tourner un seul site.

Notez que cette configuration n'entre pas en conflit avec le fonctionnement de Docker . Après avoir démarré un conteneur Docker avec Docker-compose, nous pouvons supprimer les fichiers docker-compose et les variables d'environnement. Lorsque vous redémarrez Docker à un moment donné, il suffit de redémarrer les conteneurs qui étaient exécutés auparavant sans avoir besoin de ces fichiers.

Étendre la structure du répertoire des projets

Je voulais partager tout le code entre les sites mais je voulais qu'ils aient leurs propres modèles, répertoire statique, fichiers de log, etc. La nouvelle structure des répertoires du projet :

.
|-- app
|   |--  blueprints
|   |-- factory.py
|   |-- services.py
|   `-- templates
|-- sites
|   |--  peterspython
|   |   |--  docker-volumes
|   |   |-- static
|   |   |-- stylesheets
|   |   `-- templates
|   `-- anothersite
|       |--  docker-volumes
|       |-- static
|       |-- stylesheets
|       `-- templates
|
|-- app_run.py
|--  Dockerfile
|

Le code dans l'application est partagé. Docker-volumes est un montage de volume pour les fichiers journaux, etc. Une différence avec le montage sur site unique est l'emplacement du fichier de configuration Flask config.py. Je charge ce fichier dans create_app() en utilisant la méthode from_object(). Pour être sûr que le fichier puisse être trouvé, j'ajoute le répertoire du fichier, spécifié par les variables d'environnement Docker , au sys.path :

def  create_app(deploy_config):
    ...
    # to find config.py
    sys.path.insert(0, project_docker_volume_config_dir)

	# load config
    app.config.from_object(all_configs[deploy_config])

Les modèles constituent une autre différence avec la configuration du site unique. Je veux que cela fonctionne comme suit. Lorsque le répertoire du site ne contient pas de modèle, il revient au répertoire des modèles d'applications. Il est très facile de dire à Jinja où chercher des modèles. Jinja supporte de nombreux loaders, j'ai choisi le ChoiceLoader :

from jinja2 import (
    ChoiceLoader,
)

def  create_app(deploy_config):
    ...
    # set template paths
    template_loader = ChoiceLoader([
        # site templates
        app.jinja_loader,
        # default templates
        FileSystemLoader('/home/flask/project/app/templates')
    ])
    app.jinja_loader = template_loader
    ...

Conclusion

J'ai présenté ici un moyen de partager le code et (éventuellement) les modèles entre plusieurs sites sans faire une copie de toute l'arborescence du répertoire pour un nouveau site. Bien qu'il y ait beaucoup de choses qui peuvent être améliorées, je l'utilise et je suis heureux d'avoir pris le temps de le mettre en œuvre.

Liens / crédits

API
https://jinja.palletsprojects.com/en/2.11.x/api/

Laissez un commentaire

Commentez anonymement ou connectez-vous pour commenter.

Commentaires

Laissez une réponse

Répondez de manière anonyme ou connectez-vous pour répondre.