Prepare battlefield for debian deployment
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Fred Pauchet 2020-11-27 22:19:47 +01:00
parent 05166ccb87
commit 6236d5d52a
7 changed files with 90 additions and 137 deletions

View File

@ -1,42 +1,43 @@
<<<<<<< Updated upstream
== 12 facteurs
=======
== Douze facteurs
>>>>>>> Stashed changes
Pour la méthode de travail et de développement, on va se baser sur les https://12factor.net/fr/[The Twelve-factor App] - ou plus simplement les *12 facteurs*.
Pour la méthode de travail et de développement, on va se baser sur les https://12factor.net/fr/[The Twelve-factor App] - ou plus simplement les *12 facteurs*.
L'idée derrière cette méthode, et indépendamment des langages de développement utilisés, consiste à suivre un ensemble de douze concepts , afin de:
<<<<<<< Updated upstream
. *Faciliter la mise en place de phases d'automatisation*; plus concrètement, de faciliter les mises à jour applicatives, simplifier la gestion de l'hôte, diminuer la divergence entre les différents environnements d'exécution et offrir la possibilité d'intégrer le projet dans un processus d'https://en.wikipedia.org/wiki/Continuous_integration[intégration continue]/link:https://en.wikipedia.org/wiki/Continuous_deployment[déploiement continu]
. *Faciliter la mise à pied de nouveaux développeurs ou de personnes souhaitant rejoindre le projet*
. *Minimiser les divergences entre les différents environnemens composant un projet*
. *Augmenter l'agilité générale du projet*, en permettant une meilleure évolutivité architecturale et une meilleure mise à l'échelle - _Vous avez 5000 utilisateurs en plus? Ajoutez un serveur et on n'en parle plus ;-)_.
=======
. Faciliter la mise en place de phases d'automatisation; plus simplement, faciliter les mises à jour applicatives, simplifier la gestion de l'hôte, diminuer la divergence entre les différents environnements d'exécution, faciliter la maintenance et offrir la possibilité d'intégrer le projet dans un processus d'https://en.wikipedia.org/wiki/Continuous_integration[intégration continue]/link:https://en.wikipedia.org/wiki/Continuous_deployment[déploiement continu]
. Faciliter la mise à pied de nouveaux développeurs ou de personnes rejoignant le projet. A l'inverse, faciliter également le départ d'autres personnes et la communication générale.
. Définir des bonnes pratiques à chaque étape de la chaîne.
. Réduire les frictions entre les équipes de développement et les équipes d'opération.
. Augmenter l'agilité générale du projet, en permettant une meilleure évolutivité architecturale et une meilleure mise à l'échelle - _Vous avez 5000 utilisateurs en plus? Ajoutez un serveur et on n'en parle plus ;-)_.
>>>>>>> Stashed changes
En pratique, les idées qui se trouvent derrière les points ci-dessus permettront de monter facilement un nouvel environnement - qu'il soit sur la machine du petit nouveau dans l'équipe, sur un serveur Azure/Heroku/Digital Ocean ou votre nouveau Raspberry Pi Zéro caché à la cave.
En pratique, les idées qui se trouvent derrière les points ci-dessus permettront de monter facilement un nouvel environnement - qu'il soit sur la machine du petit nouveau dans l'équipe, sur un serveur Azure/Heroku/Digital Ocean ou votre nouveau Raspberry Pi Zéro caché à la cave.
Pour reprendre de manière très brute les différentes idées derrière cette méthode, on a:
Pour reprendre de manière très brute les différentes idées derrière cette méthode, on a:
<<<<<<< Updated upstream
. *Une base de code unique, suivie par un système de contrôle de versions*. Chaque déploiement de l'application se basera sur cette source, afin de minimiser les différences que l'on pourrait trouver entre deux environnements d'un même projet. On utilisera un dépôt Git - Github, Gitlab, Gitea, ... Au choix.
. *Déclarez explicitement les dépendances nécessaires au projet, et les isoler du reste du système lors de leur installation*. L'idée est que chaque installation ou configuration se fasse toujours de la même manière, et puisse être répétée quel que soit l'environnement cible. Cela permet également d'éviter que l'application n'utilise une dépendance qui soit déjà installée sur un des sytèmes de développement, et qu'elle soit difficile à répercuter sur un autre environnement. Dans notre cas, cela pourra être fait au travers de https://pypi.org/project/pip/[pip - Package Installer for Python]. Dans tous les cas, chaque application doit disposer d'un environnement sain, qui lui est assigné, et vu le peu de ressources que cela coûte, il ne faut pas s'en priver.
. *Déclarez explicitement les dépendances nécessaires au projet, et les isoler du reste du système lors de leur installation*. L'idée est que chaque installation ou configuration se fasse toujours de la même manière, et puisse être répétée quel que soit l'environnement cible. Cela permet également d'éviter que l'application n'utilise une dépendance qui soit déjà installée sur un des sytèmes de développement, et qu'elle soit difficile à répercuter sur un autre environnement.
Dans notre cas, cela pourra être fait au travers de https://pypi.org/project/pip/[pip - Package Installer for Python].
Dans tous les cas, chaque application doit disposer d'un environnement sain, qui lui est assigné, et vu le peu de ressources que cela coûte, il ne faut pas s'en priver.
. *Sauver la configuration directement au niveau de l'environnement*. On veut par exemple éviter d'avoir à recompiler/redéployer l'application parce que l'adresse du serveur de messagerie a été modifiée, ou parce qu'un protocole a changé en cours de route. Concrètement, toute information susceptible de modifier le comportement intrinsèque de l'application doit se trouver dans un fichier ou dans une variable d'environnement. En allant un pas plus loin, cela permettra de paramétrer facilement un container, simplement en modifiant une variable de configuration, qui spécifiera la base de données sur laquelle l'application devra se connecter. Toute clé de configuration (nom du serveur de base de données, adresse d'un service Web externe, clé d'API pour l'interrogation d'une ressource, ...) sera définie directement au niveau de l'hôte - à aucun moment, on ne doit trouver un mot de passe en clair dans le dépôt source ou une valeur susceptible d'évoluer, écrite en dur dans le code.
. *Sauver la configuration directement au niveau de l'environnement*.
On veut par exemple éviter d'avoir à recompiler/redéployer l'application parce que l'adresse du serveur de messagerie a été modifiée, ou parce qu'un protocole a changé en cours de route.
Concrètement, toute information susceptible de modifier le comportement intrinsèque de l'application doit se trouver dans un fichier ou dans une variable d'environnement.
En allant un pas plus loin, cela permettra de paramétrer facilement un container, simplement en modifiant une variable de configuration, qui spécifiera la base de données sur laquelle l'application devra se connecter.
Toute clé de configuration (nom du serveur de base de données, adresse d'un service Web externe, clé d'API pour l'interrogation d'une ressource, ...) sera définie directement au niveau de l'hôte - à aucun moment, on ne doit trouver un mot de passe en clair dans le dépôt source ou une valeur susceptible d'évoluer, écrite en dur dans le code.
. *Traiter les ressources externes comme des ressources attachées*. On parle de bases de données, de services de mise en cache, d'API externes, ... L'application doit également être capable d'effectuer des changements au niveau de ces ressources sans que le code intrinsèque ne soit modifié. On parle alors de *ressources attachées*, dont la présence est nécessaire au bon fonctionnement de l'application, mais pour lesquelles le *type* n'est pas obligatoirement défini. On veut par exemple "une base de données" et "une mémoire cache", et pas "une base MariaDB et une instance Memcached". De cette manière, les ressources peuvent être attachées et détachées d'un déploiement à la volée. Si une base de données ne fonctionne pas correctement (problème matériel?), l'administrateur pourrait simplement restaurer un nouveau serveur à partir d'une précédente sauvegarde, et l'attacher à l'application sans que le code source ne soit modifié. une solution consiste à passer toutes ces informations (nom du serveur et type de base de données, clé d'authentification, ...) directement via des variables d'environnement.
. *Traiter les ressources externes comme des ressources attachées*.
On parle de bases de données, de services de mise en cache, d'API externes, ...
L'application doit également être capable d'effectuer des changements au niveau de ces ressources sans que le code intrinsèque ne soit modifié. On parle alors de *ressources attachées*, dont la présence est nécessaire au bon fonctionnement de l'application, mais pour lesquelles le *type* n'est pas obligatoirement défini.
On veut par exemple "une base de données" et "une mémoire cache", et pas "une base MariaDB et une instance Memcached". De cette manière, les ressources peuvent être attachées et détachées d'un déploiement à la volée.
Si une base de données ne fonctionne pas correctement (problème matériel?), l'administrateur pourrait simplement restaurer un nouveau serveur à partir d'une précédente sauvegarde, et l'attacher à l'application sans que le code source ne soit modifié. une solution consiste à passer toutes ces informations (nom du serveur et type de base de données, clé d'authentification, ...) directement via des variables d'environnement.
. *Séparer proprement les phases de construction, de mise à disposition et d'exécution*. La *construction* (_build_) convertit un code source en un ensemble de fichiers exécutables, associé à une version et à une transaction dans le système de gestion de sources. La *mise à disposition* (_release_) associe cet ensemble à une configuration prête à être exécutée, tandis que la phase d'*exécution* (_run_) démarre les processus nécessaires au bon fonctionnement de l'application. On doit pouvoir se baser sur les _releases_ de Gitea, sur un serveur d'artefacts ou sur https://fr.wikipedia.org/wiki/Capistrano_(logiciel)[Capistrano].
. *Séparer proprement les phases de construction, de mise à disposition et d'exécution*.
La *construction* (_build_) convertit un code source en un ensemble de fichiers exécutables, associé à une version et à une transaction dans le système de gestion de sources.
La *mise à disposition* (_release_) associe cet ensemble à une configuration prête à être exécutée, tandis que la phase d'*exécution* (_run_) démarre les processus nécessaires au bon fonctionnement de l'application. On doit pouvoir se baser sur les _releases_ de Gitea, sur un serveur d'artefacts ou sur https://fr.wikipedia.org/wiki/Capistrano_(logiciel)[Capistrano].
. *Les processus d'exécution ne doivent rien connaître ou conserver de l'état de l'application*. On suppose donc que toute information stockée en mémoire ou sur disque n'altérera pas le comportement futur de l'application, par exemple après un redémarrage non souhaité. Si une réinitialisation devait être nécessaire, l'application ne devra pas compter sur la présence d'une information au niveau du système.
. *Les processus d'exécution ne doivent rien connaître ou conserver de l'état de l'application*.
On suppose donc que toute information stockée en mémoire ou sur disque n'altérera pas le comportement futur de l'application, par exemple après un redémarrage non souhaité.
Si une réinitialisation devait être nécessaire, l'application ne devra pas compter sur la présence d'une information au niveau du système.
. *Autoriser la liaison d'un port de l'application à un port du système hôte*. Les applications 12-factors sont auto-contenues et peuvent fonctionner en autonomie totale. L'idée ici est qu'elles puissent être joignables grâce à un mécanisme de pont, où l'hôte effectue la redirection vers l'un des ports ouverts par l'application, typiquement, en HTTP ou via un autre protocole.
@ -44,35 +45,8 @@ Pour reprendre de manière très brute les différentes idées derrière cette m
. *Améliorer la robustesse de l'application grâce à des arrêts élégants et à des démarrages rapides*. Par "arrêt élégant", on veut surtout éviter le `kill -9 <pid>` ou tout autre rechargement brutal du superviseur; de cette manière, on évite qu'une requête d'un utilisateur n'aboutisse sur un code d'erreur. Au contraire, les requêtes en cours doivent être terminées au mieux, tandis que le démarrage rapide de nouveaux processus limite les perturbations et améliore la balance du travail d'un processus en cours d'extinction vers des processus tout frais. L'intégration de ces mécanismes dès les premières étapes de développement limite les perturbations et facilite la prise en compte d'arrêts inopinés (problème matériel, redémarrage du système hôte, etc.).
. *Conserver les différents environnements aussi similaires que possible, et limiter les divergences entre un environnement de développement et de production*. L'exemple donné est un développeur qui utilise macOS, NGinx et SQLite, tandis que l'environnement de production tourne sur une CentOS avec Apache2 et PostgreSQL. L'idée derrière ce concept limite les divergences entre environnements, facilite les déploiements et limite la casse et la découverte de modules non compatibles dès les premières phases de développement.
. *Conserver les différents environnements aussi similaires que possible, et limiter les divergences entre un environnement de développement et de production*. L'exemple donné est un développeur qui utilise macOS, NGinx et SQLite, tandis que l'environnement de production tourne sur une CentOS avec Apache2 et PostgreSQL. L'idée derrière ce concept limite les divergences entre environnements, facilite les déploiements et limite la casse et la découverte de modules non compatibles dès les premières phases de développement.
. *Gérer les journeaux d'évènements comme des flux*. Une application ne doit jamais se soucier de l'endroit où ces évènements seront écrits, mais simplement de les envoyer sur la sortie `stdout`. De cette manière, qu'on soit en développement sur le poste d'un développeur avec une sortie console ou sur une machine de production avec un envoi vers une instance https://www.graylog.org/[Greylog], le routage des journaux sera réalisé en fonction de sa nécessité et de sa criticité.
. *Isoler les tâches administratives du reste de l'application*. Evitez qu'une migration puisse être démarrée depuis une URL de l'application, ou qu'un envoi massif de notifications ne soit accessible pour n'importe quel utilisateur: les tâches administratives ne doivent être accessibles qu'à un administrateur. Les applications 12facteurs favorisent les langages qui mettent un environnement REPL (pour _Read_, _Eval_, _Print_ et _Loop_) à disposition (au hasad: https://pythonprogramminglanguage.com/repl/[Python]).
=======
NOTE: pensez à retravailler la partie ci-dessous; la version anglophone semble plus compréhensible... :-/
. Une base de code suivie, avec un système de contrôle de versions, d'où démarreront chaque déploiement.
. Déclarez explicitement et isolez les dépendances
. Stockez la configuration dans des variables d'environnement
. Traitez les services externes comme des ressources attachées (*?*)
. Séparez strictement les étapes dassemblage et dexécution
. Exécutez lapplication comme un ou plusieurs processus sans état
. Exportez les services via des associations de ports (*?*)
. Grossissez à laide du modèle de processus (*?*)
. Maximisez la robustesse et la disponibilité avec des démarrages rapides et des arrêts gracieux (la commande `kill -9` est donc à proscrire)
. Gardez le développement, la validation et la production aussi proches l'un de l'autre que possible
. Traitez les logs comme des flux dévènements (*?*)
. Lancez les processus dadministration et de maintenance comme des one-off-processes (*?*)
.Concrètement
|===
|Concept|Concept |Outil |Description
|1|Base de code suivie avec un système de contrôle de version| Git, Mercurial, SVN, ...|Chaque déploiement démarre à partir d'une base de code unique. Il n'y pas de dépôt "Prod", "Staging" ou "Dev". Il n'y en a qu'un et un seul.
|2|Déclaration explicite et isolation des dépendances| Pyenv, environnements virtuels, RVM, ...|Afin de ne pas perturber les dépendances systèmes, chaque application doit disposer d'un environnement sain par défaut.
|3|Configuration dans l'environnement| Fichiers .ENV| Toute clé de configuration (nom du serveur de base de données, adresse d'un service Web externe, clé d'API pour l'interrogation d'une ressource, ...) sera définie directement au niveau de l'hôte - à aucun moment, on ne doit trouver un mot de passe en clair dans le dépôt source ou une valeur susceptible d'évoluer, écrite en dur dans le code.
|4|Services externes = ressources locales| Fichiers .ENV| Chaque ressource doit pouvoir être interchangeable avec une autre, sans modification du code source. La solution consiste à passer toutes ces informations (nom du serveur et type de base de données, clé d'authentification, ...) directement via des variables d'environnement.
|5|Bien séparer les étapes de construction des étapes de mise à disposition| Capistrano, Gitea, un serveur d'artefacts, ...| L'idée est de pouvoir récupérer une version spécifique du code, sans que celle-ci ne puisse avoir été modifiée. Git permet bien de gérer des versions (au travers des tags), mais ces éléments peuvent sans doute être modifiés directement au travers de l'historique.
|===
>>>>>>> Stashed changes

View File

@ -1,49 +1,52 @@
= Déploiement
On va déjà parler de déploiement.
Le serveur que django met à notre disposition _via_ la commande `runserver` est prévu uniquement pour le développement: en production, il est inutile de passer par du code Python pour charger des fichiers statiques (feuilles de style, fichiers JavaScript, images, ...).
De même, la base de donnée doit être capable de supporter plusieurs utilisateurs et connexions simultanément: SQLite fonctionne très bien dès lors qu'on se limite à un seul utilisateur... Mais sur une application Web, il est plus que probable que vous rencontriez rapidement des erreurs de verrou parce qu'un autre processus a déjà pris la main pour écrire ses données.
Il est donc plus que bénéfique de passer sur quelque chose de plus solide.
Si vous avez suivi les étapes jusqu'ici, vous devriez disposer d'un espace de travail proprement configuré, d'un modèle relativement basique et d'une configuration avec une base de données type SQLite.
En bref, vous avez quelque chose qui fonctionne, mais qui ressemble de très loin à ce dont vous aurez besoin au final.
Il y a une raison très simple à aborder le déploiement dès maintenant: à trop attendre et à peaufiner son développement en local, on en oublie que sa finalité sera de se retrouver exposé sur un serveur.
Il est du coup probable d'oublier une partie des désidérata, de zapper une fonctionnalité essentielle ou simplement de passer énormément de temps à adapter les sources pour qu'elles fonctionnent sur un environnement en particulier.
Aborder le déploiement dès le début permet également de rédiger dès le début les procédures d'installation, de mises à jour et de sauvegardes.
Déploier une nouvelle version sera aussi simple que de récupérer la dernière archive depuis le dépôt, la placer dans le bon répertoire, appliquer des actions spécifiques (et souvent identiques entre deux versions), puis redémarrer les services adéquats, et la procédure complète se résumera à quelques lignes d'un script bash.
Le serveur que django met à notre disposition _via_ la commande `runserver` est extrêmement pratique, mais il est uniquement prévu pour la phase développement: en production, il est inutile de passer par du code Python pour charger des fichiers statiques (feuilles de style, fichiers JavaScript, images, ...).
De même, Django propose par défaut une base de données SQLite, qui fonctionne parfaitement dès lors que l'on connait ses limites et que l'on se limite à un utilisateur à la fois. En production, il est légitime que la base de donnée soit capable de supporter plusieurs utilisateurs et connexions simultanément... En restant avec les paramètres par défaut, il est plus que probable que vous rencontriez rapidement des erreurs de verrou parce qu'un autre processus a déjà pris la main pour écrire ses données.
En bref, vous avez quelque chose qui fonctionne, mais qui ressemble de très loin à ce dont vous aurez besoin au final.
Dans cette partie, nous aborderons les points suivants:
* La définition de l'infrastructure nécessaire à notre application,
* La configuration de l'hôte, qui hébergera l'application: dans une machine physique, virtuelle ou dans un container. Nous aborderons aussi les déploiements via Ansible et Salt.
* Les différentes méthodes de supervision de l'application: comment analyser les fichiers de logs, comment intercepter correctement une erreur si elle se présente et comment remonter l'information.
* Une partie sur la sécurité et la sécurisation de l'hôte.
* Définir l'infrastructure nécessaire à notre application et configurer l'hôte qui hébergera l'application: dans une machine physique, virtuelle ou dans un container. Nous aborderons aussi les déploiements via Ansible et Salt.
* Déployer notre code source
* Configurer les outils nécessaires à la bonne exécution de ce code et de ses fonctionnalités: les différentes méthodes de supervision de l'application, comment analyser les fichiers de logs, comment intercepter correctement une erreur si elle se présente et comment remonter l'information.
* Rendre notre application accessible depuis l'extérieur.
== Infrastructure
Si on schématise l'infrastructure et le chemin parcouru par une éventuelle requête, nous devrions arriver à quelque chose de synthéthique:
* Au niveau de l'infrastructure,
. l'utilisateur fait une requête via son navigateur (Firefox ou Chrome)
. le navigateur envoie une requête http, sa version, un verbe (GET, POST, ...), un port et éventuellement du contenu
. le firewall du serveur (Debian GNU/Linux, CentOS, ...) vérifie si la requête peut être prise en compte
. la requête est transmise à l'application qui écoute sur le port (probablement 80 ou 443; et _a priori_ Nginx)
. elle est ensuite transmise par socket et est prise en compte par Gunicorn
. qui la transmet ensuite à l'un de ses _workers_ (= un processus Python)
. après exécution, une réponse est renvoyée à l'utilisateur.
. l'utilisateur fait une requête via son navigateur (Firefox ou Chrome)
. le navigateur envoie une requête http, sa version, un verbe (GET, POST, ...), un port et éventuellement du contenu
. le firewall du serveur (Debian GNU/Linux, CentOS, ...) vérifie si la requête peut être prise en compte
. la requête est transmise à l'application qui écoute sur le port (probablement 80 ou 443; et _a priori_ Nginx)
. elle est ensuite transmise par socket et est prise en compte par Gunicorn
. qui la transmet ensuite à l'un de ses _workers_ (= un processus Python)
. après exécution, une réponse est renvoyée à l'utilisateur.
image::images/diagrams/architecture.png[]
* Au niveau logiciel (la partie mise en subrillance ci-dessus), la requête arrive dans les mains du processus Python, qui doit encore
. effectuer le routage des données,
. trouver la bonne fonction à exécuter,
. récupérer les données depuis la base de données,
. effectuer le rendu ou la conversion des données,
. et renvoyer une réponse à l'utilisateur.
== Code source
Au niveau logiciel (la partie mise en subrillance ci-dessus), la requête arrive dans les mains du processus Python, qui doit encore
. effectuer le routage des données,
. trouver la bonne fonction à exécuter,
. récupérer les données depuis la base de données,
. effectuer le rendu ou la conversion des données,
. et renvoyer une réponse à l'utilisateur.
Comme nous l'avons vu dans la première partie, Django est un framework complet, intégrant tous les mécanismes nécessaires à la bonne évolution d'une application.
Il est possible de démarrer petit, et de suivre l'évolution des besoins en fonction de la charge estimée ou ressentie, d'ajouter un mécanisme de mise en cache, des logiciels de suivi, ...
== Outils de supervision et de mise à disposition
Pour une mise ne production, le standard _de facto_ est le suivant:
* Nginx comme reverse proxy
@ -53,13 +56,15 @@ Pour une mise ne production, le standard _de facto_ est le suivant:
* Celery et RabbitMQ pour l'exécution de tâches asynchrones
* Redis / Memcache pour la mise à en cache (et pour les sessions ? A vérifier).
== Méthode de déploiement
Nous allons détailler ci-dessous trois méthodes de déploiement:
* Sur une machine hôte, en embarquant tous les composants sur un même serveur. Ce ne sera pas idéal, puisqu'il ne sera pas possible de configurer un _load balancer_, de routeur plusieurs basées de données, mais ce sera le premier cas de figure.
* Dans des containers, avec Docker-Compose.
* Sur une *Plateforme en tant que Service* (ou plus simplement, *PaaS*), pour faire abstraction de toute la couche de configuration du serveur.
== Sur une machine hôte
=== Sur une machine hôte
La première étape pour la configuration de notre hôte consiste à définir les utilisateurs et groupes de droits. Il est faut absolument éviter de faire tourner une application en tant qu'utilisateur *root*, car la moindre faille pourrait avoir des conséquences catastrophiques.
@ -72,39 +77,21 @@ Une fois que ces utilisateurs seront configurés, nous pourrons passer à l'éta
La machine hôte peut être louée chez Digital Ocean, Scaleway, OVH, Vultr, ... Il existe des dizaines d'hébergements typés VPS (**Virtual Private Server**). A vous de choisir celui qui vous convient footnote:[Personnellement, j'ai un petit faible pour Hetzner Cloud].
include::centos+debian.adoc[]
include::debian.adoc[]
== Via Ansible & Salt
include::ansible.adoc[]
include::heroku.adoc[]
include::docker.adoc[]
== Sur Heroku
== Docker-Compose
=== Mise à jour
Script de mise à jour.
[source,bash]
----
su - <user>
source ~/.venvs/<app>/bin/activate
cd ~/webapps/<app>
git fetch
git checkout vX.Y.Z
pip install -U requirements/prod.txt
python manage.py migrate
python manage.py collectstatic
gunicorn reload -HUP
----
WARNING: le serveur de déploiement ne doit avoir qu'un accès en lecture au dépôt source.
On peut aussi passer par fabric, ansible, chef ou puppet.
=== Supervision
== Supervision
Qu'est-ce qu'on fait des logs après ? :-)
@ -115,15 +102,15 @@ Qu'est-ce qu'on fait des logs après ? :-)
Il existe également https://munin-monitoring.org[Munin], https://www.elastic.co[Logstash, ElasticSearch et Kibana (ELK-Stack)] ou https://www.fluentd.org[Fluentd].
=== Autres outils
== Autres outils
Voir aussi devpi, circus, uswgi, statsd.
include::infrastructure.adoc[]
include::database.adoc[]
See https://mattsegal.dev/nginx-django-reverse-proxy-config.html
== Ressources
* https://zestedesavoir.com/tutoriels/2213/deployer-une-application-django-en-production/
* https://docs.djangoproject.com/fr/3.0/howto/deployment/[Déploiement].
* https://docs.djangoproject.com/fr/3.0/howto/deployment/[Déploiement].
include::database.adoc[]

View File

@ -0,0 +1 @@
=== Ansible

View File

@ -1,8 +1,8 @@
=== Déploiement sur CentOS
=== Déploiement sur Debian
[source,bash]
----
yum update
apt update
groupadd --system webapps <1>
groupadd --system gunicorn_sockets <2>
useradd --system --gid webapps --shell /bin/bash --home /home/gwift gwift <3>
@ -13,7 +13,7 @@ chown gwift:webapps /home/gwift <5>
<2> On crée un groupe pour les communications via sockets
<3> On crée notre utilisateur applicatif; ses applications seront placées dans le répertoire `/home/gwift`
<4> On crée le répertoire home/gwift
<5> On pourrait sans doute fusioner les étapes 3, 4 et 5.
<5> On donne les droits sur le répertoire /home/gwift
==== Installation des dépendances systèmes
@ -26,11 +26,6 @@ Pour CentOS, vous avez donc deux possibilités :
[source,bash]
----
yum install python36 -y
# CentOS 7 ne dispose que de la version 3.7 d'SQLite. On a besoin d'une version 3.8 au minimum:
wget https://kojipkgs.fedoraproject.org//packages/sqlite/3.8.11/1.fc21/x86_64/sqlite-devel-3.8.11-1.fc21.x86_64.rpm
wget https://kojipkgs.fedoraproject.org//packages/sqlite/3.8.11/1.fc21/x86_64/sqlite-3.8.11-1.fc21.x86_64.rpm
sudo yum install sqlite-3.8.11-1.fc21.x86_64.rpm sqlite-devel-3.8.11-1.fc21.x86_64.rpm -y
----
Ou passer par une installation alternative:
@ -283,30 +278,24 @@ server {
<2> Ce répertoire sera complété par la commande `collectstatic` que l'on verra plus tard. L'objectif est que les fichiers ne demandant aucune intelligence soit directement servis par Nginx. Cela évite d'avoir un processus Python (relativement lent) qui doive être instancié pour servir un simple fichier statique.
<3> Afin d'éviter que Django ne reçoive uniquement des requêtes provenant de 127.0.0.1
=== Mise à jour
Script de mise à jour.
=== Déploiement sur Debian
[source,bash]
----
su - <user>
source ~/.venvs/<app>/bin/activate
cd ~/webapps/<app>
git fetch
git checkout vX.Y.Z
pip install -U requirements/prod.txt
python manage.py migrate
python manage.py collectstatic
gunicorn reload -HUP
----
==== Installation des dépendances systèmes
==== Préparation de l'environnement utilisateur
==== Configuration de l'application
==== Création des répertoires de logs
==== Création du répertoire pour le socket
==== Gunicorn
==== Supervision, keep-alive et autoreload
==== Ouverture des ports
==== Installation d'Nginx
== Configuration des sauvegardes
=== Configuration des sauvegardes
Les sauvegardes ont été configurées avec borg: `yum install borgbackup`.
@ -326,7 +315,7 @@ Et dans le fichier crontab :
----
== Rotation des jounaux
=== Rotation des jounaux
[source,bash]
----

View File

@ -1,3 +1,5 @@
=== Docker-Compose
(c/c Ced' - 2020-01-24)
Ça y est, j'ai fait un test sur mon portable avec docker et cookiecutter pour django.

View File

@ -0,0 +1 @@
=== Heroku

View File

@ -1 +0,0 @@
See https://mattsegal.dev/nginx-django-reverse-proxy-config.html