soutenance/content/50_specifications_techniques.md

382 lines
18 KiB
Markdown

\newpage
# Spécifications techniques
Après avoir décrit, via un cahier des charges, les différents besoins du
projet, les livrables attendus, il est temps de décrire une solution. Nous
aborderons avant tout l'étude de l'existant puis enchaînerons sur le détail de
l'infrastructure choisie pour terminer sur divers sujets intégrés et quelques
outils utilisés.
## Étude de l'application
Le dépôt Git contenant l'application **existait déjà**. Une étude des
composants fournis a donc été nécessaire, ce qui a permis d'en mesurer les
implications.
### Composants de l'application
L'équipe de développement a fait le choix du **monorepo** pour contenir
l'ensemble des éléments de l'application. L'application est composée de :
* une **base de données** PostgreSQL,
* un **backend** écrit en Python et construit sur **FastAPI**,
* un **frontend** écrit en TypeScript et construit avec **ReactJS**.
\newpage
L'ensemble se comprend mieux à l'aide du schéma suivant :
![Schéma des composants de
l'application](./media/schema_composants_application.png){height=55%}
### Outils fournis aux développeurs
Via le dépôt, les développeurs ont accès à :
* une documentation principale via un fichier **README.md**,
* une documentation secondaire via :
* un fichier **backend/README.md** pour les développeurs du Backend,
* un fichier **frontend/README.md** pour les développeurs du Frontend,
* plusieurs fichiers **Docker Compose** afin de déployer localement :
* une **base de données (BDD) PostgreSQL** avec un **jeu de données
préchargé**,
* un accès à la BDD via une interface Web, via l'outil nommé **adminer**,
* le **backend** (FastAPI),
* le **frontend** (ReactJS),
* une documentation **deployment.md** pour déployer le projet à l'aide de
**Docker Compose**,
* et un fichier **docker-compose.traefik.yml** afin de déployer une instance
locale du **proxy Traefik** configuré pour utiliser Docker.
Ces éléments sont un **bon point de départ pour l'équipe de DevOps** qui
prendra connaissance des particularités de cette application.
### Points d'attentions
La **partie Frontend** permet de générer des fichiers dits
« statiques », du **serverless** est envisageable. L'application,
bien que faisant des appels à une API, fonctionne de manière **autonome**. Ce
qui, a priori, facilite la préparation pour un déploiement. Cependant les
développeurs de l'application utilisent **un nom de domaine inscrit en dur
dans le fichier Dockerfile**, ce qui peut compliquer un déploiement sur
plusieurs domaines et environnements.
La **partie backend** s'appuie sur une base de données de type PostgreSQL. Elle
est donc **dépendante de la BDD**.
La **partie proxy** utilise actuellement **Traefik comme outil**. Ce qui n'est
pas une obligation d'usage pour un déploiement en production.
Ces trois parties ont une influence sur le choix de l'infrastructure à mettre
en place. Il reste cependant une **marge de manœuvre sur la partie proxy**. En
effet il n'est pas obligatoire d'utiliser Træfik en production.
## Infrastructure
Afin d'accueillir l'application dans le Cloud, l'infrastructure de base va
poser les fondations de l'environnement complet nécessaire à un usage
quotidien.
### Couche basse
La couche basse pourrait se définir comme le minimum nécessaire avant
d'installer quoique ce soit pour exploiter l'application. En ce sens, on
utilise des éléments de base d'Amazon Web Services (AWS) pour fabriquer notre
infrastructure :
* un espace privé, Virtual Private Cloud (**VPC**),
* sur plusieurs **régions**,
* avec plusieurs zones de disponibilités (**Availability Zone**),
* contenant chacune, d'un point de vue réseau informatique, des réseaux
publics (**public subnet**) et des réseaux privés (**private subnet**),
* en utilisant une passerelle entre le VPC et Internet, appelée **Internet
Gateway** (IGW),
* en utilisant des passerelles **NAT** (Network Access Translation) entre les
réseaux privés et les réseaux publics pour un accès à l'IGW,
* avec des groupes de sécurité (**Security groups**) pour définir les règles
d'entrée/sortie,
* et des équilibreurs de charge de type réseau (**Network Load Balancer**)
afin de gérer les accès aux services de manière équilibrée.
\newpage
Le schéma de la couche basse de l'infrastructure ressemble donc à :
![Schéma de la couche basse de
l'infrastructure](./media/schema_couche_basse.png){width=100%}
### Environnement Kubernetes
C'est sur la couche basse qu'il est possible d'ajouter un environnement
permettant d'intégrer, déployer, automatiser et gérer des applications
conteneurisées. Pour cela nous choisissons **Kubernetes**.
Kubernetes est un système capable de faire tourner des **applications
conteneurisées**, d'**automatiser le déploiement** et de gérer la mise à
l'échelle (**auto-scaling**).
Sur l'infrastructure présentée dans le paragraphe précédent il va falloir
ajouter quelques éléments comme :
* un cluster Kubernetes appelé EKS (**Elastic Kubernetes Service**) géré par
Amazon,
* avec l'usage d'une mise à l'échelle (**autoscaling**) des **serveurs
virtuels EC2**(Elastic Container) d'Amazon,
* un équilibreur de charge de type réseau entre l'extérieur du cluster et le
cluster (**AWS Elastic LoadBalancer** ou ELB) ; présent d'ailleurs dans le
schéma de la couche basse de l'infrastructure dans le paragraphe précédent,
* un équilibreur de charge de type réseau (couche 4 du modèle OSI - Open
Systems Interconnection) qui fait le lien entre les services et l'extérieur du
cluster : **NGINX Ingress Controller** ; il va notamment échanger avec
l'AWS Elastic LoadBalancer précédent,
* l'utilisation d'un agent **externaldns** qui va mettre à jour les routes DNS
(Domain Name System) de **Route53** pour les sous-domaines utilisés (~16€/mois
pour 3 routes),
* et avec l'usage de **cert-manager** pour faire la demande de certificats SSL
(Secure Sockets Layer) via le service - gratuit - de **Let's Encrypt** pour
nos sous-domaines.
Le contenu du cluster EKS, une fois implémenté, pourrait ressembler à
ceci :
![Schéma des applications et services contenu(e)s dans le cluster
EKS](./media/schema_contenu_eks.png){width=100%}
**Pourra tourner dans le cluster**, en plus des agents précédemment cités,
**les applications suivantes** :
* le serveur de BDD **postgreSQL**,
* le **backend** de l'application (FastAPI),
* et le **frontend** de l'application (en fichiers statiques).
Afin de permettre une **livraison régulière** de l'application, il va falloir
**automatiser au maximum** les étapes entre la publication d'une nouvelle
version de l'application et son déploiement en production en passant par la
livraison en environnement de pré-production par une intervention humaine.
### Environnements
Nous parlons de production depuis un moment. À quoi cela correspond ?
Afin de mener à bien le travail de DevOps, nous avons défini les différents
environnements par lesquels nous allons passer pour toute notre chaîne de
production logicielle. Ainsi **nous avons 4 environnements** :
* l'environnement de **développement** : c'est l'environnement disponible
sur **chaque machine des développeurs** à l'aide des outils fournis
(Dockerfile, docker-compose du projet applicatif),
* l'environnement de **test** : il est composé de l'**ensemble des Runner
Gitlab** utilisés à l'intérieur de la chaîne d'intégration continue,
* l'environnement de **pré-production** (appelé « **staging** »
) : c'est l'infrastructure présentée ci-avant, appliquée dans AWS avec
une configuration dite *plus légère* (moins de machines virtuelles EC2 par
exemple),
* et l'environnement de **production** : c'est l'**infrastructure
finale** ; celle qui est disponible aux utilisateurs finaux (les usagers).
\newpage
Le schéma des différents environnements est plus compréhensible :
![Schéma des environnements
utilisés](./media/schema_workflow_environnement.png){height=50%}
[commentaire1]: # Cf. https://mermaid.live/view#pako:eNptkkFugzAQRa9izRoiAiUkLLrKtlKldtXShYUHYtXY1Nhp05AD5Ry5WAcCUSuVFR6_-X4e-QilEQg5VMp8ljtuHXveFprRJ3D_WvG84mGLtjM6FLKupa7Z9nLeozJtiw1q93alP_gE18gte8Zu3ugcH7qmXSU7F5Y7LN_Zo72cw9Ya4UsnjZ7woTCxpTJeEPaLuJmxMLxnvcCGa4FUYJXvCOnJY_a5Io5MOsa9Mw138sNj189Kf_yu9J4rKfhwGKNkj0phPyrNR8-xl_NwCTam94PQP2FSj3GX8wRAAA3ahktB8z4ODQW4HQ2xgJx-BVbcK1dAoU-EDspPB11C7qzHAKzx9Q5oLqqjlW9JE7eS15Y3M9Jy_WJMc4NoDfkRviCPo2SxSdZplEXrKMrWyziAA5Wz5SJJ0ihebrJ4la7i9BTA9xgRLVZJnCXZJrlL19S6CgCFdMY-XN_L-GxOP_j4v68
### Livraison continue et déploiement
Il est visé une **CI/cd**, c'est à dire une **Intégration Continue**
(Continuous Integration) et une **livraison continue** (continuous delivery).
**L'automatisation est donc essentielle**.
**Le déploiement en production passera par une validation manuelle**.
Doivent être automatisés :
* les **tests du backend et du frontend**,
* l'étude de **sécurité sur les dépendances des composants** de l'application,
* la **génération** d'une **image Docker** pour le **frontend** et le
**backend**,
* la **publication** de cette image sur un **dépôt d'images**,
* le **déploiement d'un environnement de pré-production** (appelé *staging*,
dont nous parlerons dans le chapitre [Démarche suivie](#demarche)),
* le **déploiement**, une fois la validation manuelle sur l'environnement de
pré-production faite, **d'un environnement de production**,
* et la **mise en place initiale** de l'infrastructure (appelée **boostrap**).
Nous retrouverons ces éléments dans les chapitres suivants.
## Services et outils divers
Plusieurs sujets tournent autour des services mis en place :
* les **données** : définit les éléments enregistrés à l'usage quotidien
de l'application,
* la **supervision** : définit tous les éléments permettant de mesurer
les différents services et d'alerter si les métriques dépassent des seuils
définis,
* la **sécurité** : définit tout ce qui peut être mis en œuvre pour
palier rapidement à des problèmes de sécurité de l'application, de
l'infrastructure et des outils utilisés.
### Données
Le sujet des données ne couvre pas uniquement les données brutes enregistrées
par l'application, mais aussi la manière de les stocker, de les sauver via un
plan de sauvegarde et de les restaurer si besoin.
#### Où sont les données ?
Les données de ce projet sont multiples. En voici une liste
non-exhaustive :
* les dépôts contenant le **code applicatif** (backend + frontend),
* les dépôts contenant la **description de l'infrastructure**,
* les données brutes de l'application, stockées dans la **base de données
postgreSQL**,
* les **données sensibles** (mots de passe, clés d'accès),
* les **copies de sauvegardes** des données elles-mêmes,
* et les **fichiers de journalisation** des services en production.
Regardons pour chacun des points de cette liste où se situe le stockage.
#### Stockage
Les éléments précédents donnent lieu au tableau suivant :
: Données présentes et leur lieu de stockage
Données | Stockage
-----|-----
Code applicatif | **dépôt Gitlab**
Code de l'infrastructure | **dépôt Gitlab**
Base de données postgreSQL | **stockage AWS EBS** (Elastic Block Store)
Sauvegardes | **stockage AWS S3** (Simple Storage Service)
Cela devrait être suffisant pour stocker les diverses données disponibles.
\newpage
#### Base de données postgreSQL
Pour le choix d'un service de base de données, nous avons fini par opter pour
**postgresql-ha** (pour postgreSQL High Availability) qui s'appuie sur **2
bases de données répliquées** avec un service **pgpool** par lequel on accède
pour chaque requête faite à la base de données.
![Schéma du fonctionnement de
postgreSQL-HA](./media/postgresql-ha.png){height=50%}
#### Sauvegardes
Les dépôts de version utilisés étant sur Gitlab, [service qui se targue d'être
entre 99% et 100% disponible](
https://handbook.gitlab.com/handbook/engineering/monitoring/#historical-service-availability)
, une **sauvegarde dite « préventive » mensuelle** suffit.
En revanche **la production**, même en **étant un service en haute
disponibilité**, doit fournir au moins **une sauvegarde 1 fois par jour**.
L'outil de sauvegarde choisi est **Velero**. Compatible avec l'environnement
Kubernetes et permettant aussi de **sauver l'état du cluster** à un instant
*T*. Son outil en ligne de commande permet de gérer les sauvegardes mais aussi
les restaurations de ces dernières.
Comme énoncé précédemment, les sauvegardes du cluster seront mises **sur un
stockage AWS S3** (dit « bucket S3 »).
\newpage
Le fonctionnement de Velero dans ce projet est visible sur le schéma suivant.
[commentaire2]: # Cf. https://mermaid.live/view#pako:eNptVE1v00AQ_SvWSr0lkWOTOPEBKU2CFLWUgkuRkKVqY08dK7Y37EegRLlxqiqBygFuvSH4B1zopT-I_gTWazteK1g-2G9m35t5s7sbFJAQkIsMxjGHSYwjitP22vKzgwNjMn02O5mdzV6ceH5myEcwoIZrvOZxEjOZL2iBryEBSi6CJJbRx7ub63MFGOPjWZGwHLALvMqjR2IONAMOzBidllFYMhmZHpUqzFYsX38cimAJ3PDshsqKhE0VCRQJIY3XqsDHu9v76aHXHnuz9kSBdRlrkhQZf85JIlJgZQ1zpuBvn_7-_izXFih-z0qt0RvPqPQSEcVZuYwHeTXTs_GkrGGuFnz5fkoYjyh4L4-LgHL01fR4pPmpddRuP60av7lmWKwhwjSEnSN5fM8ACnJsgoI2HS1PjmNvPHm4HkbOEZA0FVn8TkBzVE3B_VjeueaBRvzf3monQ0hxFoIhX5bhFVsQXvijjbBiK4YVPfysesxplPq8oqs46jHurMQ0WEi6_dpDbU9oihXp7T1kFKKY8UpWTrVREuMkWD788stdoA6P2sabAtAEa6B2rOlPjel1afu1BmT7Wva8-N76GWqhFGiK41CeZVWDj_gCUvCRKz9DuMQi4T7ys61MxYIT7yoLkMupgBaiREQL5F7ihMk_sQrrq6BKWeHsLSHpLkn-I3eDPiDXMu3O0B70TMccmKYz6FotdCVhp9ux7Z5pdYeO1e_1rd62hT4qCrPTty3Hdob2k95ALu23EIQxJ_R5cRepK2n7D1LIfM8
![Schéma du système de sauvegarde](./media/schema_velero.png){height=70%}
\newpage
### Supervision
Le choix de l'outil de supervision se porte sur **Datadog** pour sa
**souplesse** et sa capacité à proposer des **services supplémentaires de
manière progressive**.
Le fonctionnement semble simple : installation d'agents Datadog dans le
système Kubernetes pour receuillir de nombreuses informations. Comme peut le
montrer le schéma suivant.
[commentaire3]: # Cf. https://mermaid.live/view#pako:eNp1VEtu2zAQvQrBImgLKIYs-RctCji2ChhxHMNKUaDQhhZHjiCZNCiqbRL4DgV6gB6g-266C9D79Agl9ZeTaiPyzZsZzvcRB5wCdnAqiYR5RHaC7M8_Wz7z2dkZmrvvF6vF7eJm5fkMqY8SSSjfIQf9_fHtF5oX10IGcarw6Z48cIbcq1Ij4EwKnijJ6s_3jKKnn2hWQuuEMEBPvwviFy5iEG3exwLRhNJ7QLSHHTBZuUY0Q0GSpRJEyWEvcpg2WjDibAsJSMW6Kk5VaOndlhNBlWBenQvRnrNIcv22a32CTLxJ35YiEunYZjwTIoKkANOEBLFCPf03EMig1ySDRAxEP9dhEpgyhuhrcjgkUQ_1T2jWyzSroJFDpENdL5AH4rNOgCrZ7GZ5s6lyn5A0nUOINkBRGCWJ8yoMaUgHRqoKEIMjgJ4wL5MMSioZBCFsK-pWCU6464jFtVkYQFhxD0rQ4uZ123Rc5WW67JrM41nnqnkkG3c5bbVeVbbz83e5dlPuHAlI0yMlpQso603aNBB3ql-ptTu6Nt4Gq2bQgrL606W7uXW95_KqEUoCetYFnZe2yl7jxRhOVx5aumi2_ODdupuyyfTE5kP3WAANWM1cS1AG3gXqpOnveGqlHMgTI52s1YYY6QJNiP_ByxY-dn6F32rHtBzT7jy20lzrYwPvQaiCULXNclUfyzvYg48ddaQQkiyRPvbZUVFJJrl3zwLsSJGBgQXPdnfYCUmSqlt2oM02rCgHwj5xvq9J6o6dR_wVO5Zp9y7sydAcmxPTHE_6loHvFTzu92x7aFr9i7E1Go6s4dHAD7kJszeyrbE9vrAHw4lSHRkYqA7nutjG-VI-_gOoBrf7
![Schéma des agents Datadog dans notre système
Kubernetes](./media/schema_datadog.png){height=70%}
Une fois installé, l'agent Datadog recueille et envoie les informations sur
les serveurs officiels de l'entreprise Datadog qui en gère le stockage et
l'accès.
#### Surveillance (monitoring)
L'utilisation de Datadog donne accès à de nombreux moniteurs pré-configurés.
On veillera à utiliser des **indicateurs simples** comme l'**utilisation CPU**
et la **mémoire vive** des instances AWS EC2 (Elastic Compute Cloud) utilisées.
Il y a également :
* le **nombre de pods utilisés** par l'instance EC2,
* et la **disponibilité du service** de l'application *API Utilisateurs*.
Cependant ces moniteurs sont insuffisants. On pourrait ajouter :
* le temps de réponse de l'API,
* le nombre de requêtes par seconde sur l'API,
* même chose pour le nombre de requêtes sur la base de données,
* le nombre d'erreurs 500 retournées par le frontend et le backend,
* etc.
#### Alertes
On va utiliser **un canal Slack** (*#alertes*) **pour avertir les DevOps**
d'une quelconque **alerte levée**. Datadog permet cela facilement comme énoncé
dans l'introduction de ce chapitre sur la Supervision.
Suite aux alertes, les **DevOps peuvent opérer et notifier** de la prise en
charge d'un problème **via le chatbot Gitlab intégré** à ce canal Slack. Nous
utilisons donc le [**Gitlab ChatOps**](https://docs.gitlab.com/ci/chatops/).
En suivant toutes ces indications, nous devrions avoir une base stable et
saine pour constuire une supervision correcte de l'application
*API Utilisateurs*.
### Sécurité
Au niveau de la sécurité, **vaste sujet**, nous partirons de ces
éléments :
* lancement de **tests** sur le **code applicatif**,
* lancement de **tests SAST** (Static application security testing), sur
Terraform notamment,
* et utilisation d'un **coffre fort numérique** pour les mots de passes et
clés d'accès en tous genres.
Le coffre-fort choisi est **Vaultwarden**.
Il y a beaucoup à faire pour **améliorer la sécurité**. Ceci est un
**processus continu** à faire tout au long du **suivi et la maintenance du
projet**.
## Conclusion
Les spécifications techniques décrivent bien l'application, composée de 3
éléments (backend, frontend et base de données) qui s'intégreront bien dans
l'environnement Kubernetes installé sur l'infrastructure posée dans le cloud
AWS.
On retient ainsi un déploiement automatique dans le Cloud d'une infrastructure
prête à accueillir à la fois l'application et d'autres services tierces comme
la supervision avec Datadog et les sauvegardes à l'aide de Velero.
La sécurité aura cette spécificité de devoir être régulièrement vérifiée,
maintenue et améliorée au fil du temps. C'est donc un processus continu dont
la réussite dépend beaucoup de la discipline et la régularité.