Warning
À rendre au plus tard le 16 décembre 2024 à 23h59
Le projet noté du module de Virtualisation & Cloud computing évaluera compétences et bonnes pratiques de développement vues en cours. La notation tiendra compte de l'infrastructure déployée, des fonctionnalités déployées dans l'application, de la bonne mise en place des points d’exigences projets, de votre compréhension de votre code ainsi que de la collaboration entre les membres du groupe.
Vous allez réaliser une Calculatrice Cloud Native.
De la déclaration des ressources d'infrastructure, à l'implémentation des composants logiciels de l'application tout en passant par la configuration de l'environnement.
Ce projet va se dérouler comme la mise sur le marché d'une application.
À l'image de l'équipe tech d'une startup, vous allez deployer une application pour la mettre à disposition d'utilisateurs. Vous passerez donc par la conception et le provisionnement d'une infratructre à la déclaration des fichiers de déploiement pour déployer sans oublier la conception de l'application.
Pour marcher sur les traces du Cloud Natif, nous allons mettre en place de bonnes pratiques dès le départ :
-
L'infrastructure de base sera définie en code (IaC) via
Terraform. -
La configuration et l'architecture de déploiment sera faite via
Kubernetes. -
L'application sera architecturée d'un point de vue logique comme une grappe de microservices:
Loadinggraph TB; A(Utilisateur) --> B[Frontend] B -->|"Envoi du calcul ou Demande d'un résultat"| C[API] C -->|Transmission du calcul à faire | E[\RabbitMQ/] -.-> F(["Consumer ( calcul )"]) -->|Récupèration d'un calcul| E F -->|Stockage du résultat| D C <-->|Accès aux résultats| D[(Redis)]
Utilisez votre dépôt utilisé en TD.
Déplacez votre travail de TD ( fichiers, dossiers et README.md ) dans un dossier du même nom à la racine du dépôt.
Créez un nouveau README.md à la racine du projet qui servira de rapport pour le projet (pour l’instant vous pouvez y saisir les membres du groupe).
Créez les dossiers foundation, kubernetes et application, qui serviront à stocker respectivement, les fichiers Terraform, Kubernetes et les fichiers de l'application à déployer.
Chacun de ces dossiers contiendra un
README.mddédié.
Dans le dossier application, vous organiserez le contenu en trois dossiers:
- un pour le
frontendpour le code de l'interface utilisateur. - un pour le
backend, pour le code de votre API. - un pour le
consumer, pour le code de votre consommateur de message.
Le fichier application/README.md contiendra également les commandes nécéssaires pour contruire les images de conteneur du projet ainsi que celles pour en pousser une version dans Google Artifact Registry.
Qui dit "projet" dit aussi "contraintes supplémentaires" ! Nous voulons une calculatrice qui soit hébergée en France et par un fournisseur français. 🐓
terraform {
required_providers {
scaleway = {
source = "scaleway/scaleway"
}
}
required_version = ">= 0.13"
}En utilisant le provider Terraform de Scaleway, fournisseur de Cloud français, décrivez l'infrastructure as code:
- Un registre de conteneur.
- Un cluster Kubernetes.
- Une base de données de
developmentet deproduction. - Une entrée DNS pour
calculatrice-<nombinome1>-<nombinome2>-polytech-dijon.kiowy.netpour résoudre l'IP d'un des LoadBalancers. - Une entrée DNS pour
calculatrice-dev-<nombinome1>-<nombinome2>-polytech-dijon.kiowy.netpour résoudre l'IP d'une des LoadBalancers. - Un LoadBalancer de
developmentet un LoadBalancer deproduction.
Stocker les fichiers dans le dossier
foundation
graph LR
subgraph k8s ["Cluster Kubernetes"]
direction TB
node1
node2
node3
end
lbA["LoadBalancer
(production)"] --> k8s
lbB["LoadBalancer
(development)"] --> k8s
dns1(["DNS
calculatrice-dev.polytech-dijon.kiowy.net"]) --> lbB
dns2(["DNS
calculatrice.polytech-dijon.kiowy.net"]) --> lbA
k8s --> db["Base de données
(production)"]
k8s --> reg[registre de conteneur]
k8s --> db2["Base de données
(develop)"]
Vous devez utiliser des variables pour nommer les ressources dédiées à un environment selon les environments.
Tip
Ce qui veut dire que les fichiers ne contiendrons qu'une instance de chaque type de ressource (une pour le registre, une pour le cluster, une pour les bases de données, une pour les entrées DNS et une pour les LoadBalancers).
Cette section est terminée si les commandes terraform fmt, terraform validate et terraform plan s'exécutent sans erreur dans le dossier foundation.
Important
Le résultat du terraform plan est à ajouter au README.md de ce même dossier.
Caution
L'API Terraform de Scaleway ne nécéssite pas d'authentification pour réaliser les commandes terraform fmt, terraform validate et terraform plan. Vous pouvez donc réaliser des commandes sans être connecté. Vous n'avez pas besoin de vous créer un compte chez Scaleway pour réaliser cette section.
Utilisez Kubernetes pour déployer votre application au sein d'un namespace nombinome1-nombinome2.
- Pour chaque microservice, déclarez un ReplicaSet et un Service pour exposer le conteneur de ce dernier.
- Passer en variable environnement les variables permettant la connexion entre les services qui doivent l'être.
- Exposer le service frontend via une règle Ingress pour le nom de domaine défini dans la section Fondation.
Une fois la configuration déployée, accéder à votre nom de domaine via un navigateur doit vous permettre d'utiliser la calculatrice.
Schema récapitulatif
graph LR
subgraph "Kubernetes"
subgraph "Namespace du binôme"
subgraph "front-replicaset"
pod-front
end
subgraph "api-replicaset"
pod-api
end
subgraph "redis-replicaset"
pod-redis[("Redis
pod")]
end
subgraph "rabbitmq-replicaset"
pod-rabbitmq[\" RabbitMQ
pod"/]
end
subgraph "consumer-replicaset"
pod-consumer
end
svc-front([svc-front]) --> pod-front
svc-api([svc-api]) --> pod-api
svc-redis([svc-redis]) --> pod-redis
svc-rabbitmq([svc-rabbitmq]) --> pod-rabbitmq
pod-consumer -.-> svc-rabbitmq
pod-consumer -.-> svc-redis
pod-front -.-> svc-api
pod-api -.-> svc-redis
pod-api -.-> svc-rabbitmq
ing(Ingress NGINX rule) --> svc-front
end
end
Les liens en pointillés ne sont pas à décrire de façon explicite dans la configuration Kubernetes, mais seront à coder dans les applications.
Cette section est terminée si vous accédez à votre application en utilisant l'URL calculatrice-<nombinome1>-<nombinome2>-polytech-dijon.kiowy.net dans votre navigateur.
Note
Documentations pour la section: Kubernetes - K8S Pod - K8S Service - K8S ReplicaSet - K8S Deployment - K8S Namespace - K8S Ingress - kubectl Cheat Sheet
Concevoir une API simple.
La calculatrice doit permettre les additions, les soustractions, les multiplications et les divisions.
Pour demander ces calculs :
POST: Envoyer un tuple pour demander un calcul. ( Renvoie l'idde l'opération )GET: Récupérer un résultat à partir unid. ( Renvoie le résultat du calcul )
Pour vos tests, vous pouvez stocker les résultats dans une variable dictionnaire.
Tip
Bonne pratique : pour plus de clarté, utilisez un préfix pour vos routes api.
exemple :/api/ma_route ou /v1/ma_route pour le versionning des endpoints.
Utilisez curl pour demander des calculs et récupérer le résultat. Rappel HTTP/S et API
# Rappel
curl -X POST/GET -h localhost:PORT -d "tuple={}"Et que ce soit par contrainte produit ou par goût de la chose bien faite : on va éviter de perdre toutes les demandes de calcul en cours pour un calcul impossible !
Utilisons Redis comme Redis externe à l'API pour la gestion des résultats.
Utilisez Redis comme serveur de données, c’est un système de stockage clé/valeur qui utilise le port 6379 pour communiquer. Vous pouvez le lancer dans un conteneur via la commande suivante :
# À exécuter dans un autre terminal.
docker run -p 6379:6379 --name myredis --rm redisOui, on pourrait utiliser -d pour lancer le conteneur en mode detached mais dans un terminal on peut voir les logs, pratique pour débuguer ! 🧐
Tip
Utilisez redis-cli pour accéder à redis via les commandes set, get, keys.
Connectons maintenant l’API à la Redis Documentation 👉 python et redis
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
# Ajout de variable
r.set('foo', 'bar') # Retourne True si réussite
# Lecture de
r.get('foo') # Retourne la value de fooRemplacer le système de stockage des opérations et des résultats (précédemment en variable) par un stockage via Redis
Utilisez
curlpour demander des calculs et récupérer le résultat.
Via un nouveau conteneur, démarrez RabbitMQ qui servira de serveur de files.
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-managementTip
Si vous n'avez pas eu l'occasion d'essayer lors du TD sur la conteneurisation, tester RabbitMQ avec le tutoriel suivant ! 👉 RabbitMQ Hello World
Comment la file d'attente doit être ajoutée à l'API: chaque fois que l'API reçoit le calcul à effectuer, elle crée un message avec opérateur et opérandes et le place dans la queue. Un autre programme est donc à développer, il sera chargé de consommer les messages. Pour chaque message, il réalisera le calcul et le stokera le resultat dans le redis.
Ça vous dit un peu de design et d’implémentation d’interface ?
Une seule consigne : Créer un frontend qui permet à l’utilisateur de saisir et d’envoyer des demandes de calcul à l’API ou de récupérer des résultats.
Conteneurisez les microservices backend, frontend et consumer.
graph LR
user([Utilisateur]) -->|saisit une addition| F[Frontend]
F -->|"HTTP POST /api/addition"| B[Backend]
B -->|"{id, calcul à faire}"| Q[\ RabbitMQ /]
B -.->|HTTP 200 OK| F
C[Consumer] -->|"récupére le dernier message"| Q[\ RabbitMQ /]
C -->|"redis.set(id, resultat du calcul)"| R[(Redis DB)]
graph LR
user([Utilisateur]) -->|saisit id du calcul à récupérer| F[Frontend]
F -->|"HTTP GET /api/result/{id}"| B[Backend]
B -->|"redis.get(id)"| R[(Redis DB)]
R -.->|"résultat ou null"| B
B -.->|HTTP 200 + Résultat| F
B -.->|HTTP 404 Not Found| F
F -.->|Affiche le résultat ou l'erreur| user
Note
Documentations pour la section: Documentation Flask - Documentation Docker - Documentation Redis - Documentation RabbitMQ - RAPPEL Docker - RAPPEL GitHub & Readme - RAPPEL HTTP/S et API
Ce projet à rendre au plus tard le 16 décembre 2024 à 23h59.
Warning
À partir de cette date, aucune modification de votre dépôt ou de son code ne sera prise en compte.
Vous rendrez votre code via un dépôt GitHub, auquel vous m’aurez ajouté en tant que collaborateur.
- L’historique des changements sur le dépôt devra montrer la collaboration entre les membres du groupe ( changement de sources différentes sur les fichiers du projet ).
- Le dépôt devra être documenté de 4 READMEs :
- un pour les fondations du projet.
- un pour la configuration Kubernetes.
- un pour l'application microservice.
- un global à la racine du dépôt.
- Le README principal contiendra au minimum les noms des membres du groupe, des détails sur le déroulé du projet et ce qui a été implémenté ainsi que des schémas de votre infrastructure et architecture globale.
Important
Vos READMEs jouent le rôle de rapport de projet, ajoutez y toutes les informations possibles sur celui-ci.
- Les fichiers
.tfpermettant la déclaration des éléments de fondations doivent être valides syntaxiquement. - Le
README.mddu dossierfoundationdoit contenir un schema descriptif des fondations avec les noms de vos ressources. - Le
README.mddu dossierfoundationdoit contenir le résultat de la commandeterraform plan.
- Le dossier
kubernetesdoit contenir les manifestes.yamlpermettant la déclaration de la configuration de votre environnement. - Vos manifestes doivent être déployés sans erreur sur le cluster de rendu.
- Un schema descriptif des configuration doit être présent dans le
README.mddu dossierkubernetes.
- Avoir un Dockerfile pour construire l'API (
backend). - Avoir un Dockerfile pour construire le
frontendsi vous utilisezNode,ReactouVueJs. - Avoir un Dockerfile pour construire le conteneur du consommateur de message.
Tip
Si vous utilisez du HTML/CSS/JS utilisez un Dockerfile nginx.
- Décrire dans le README de l'application la structure de donnée utilisée pour stocker les calculs.
- L'interface utilisateur doit permettre de demander la réalisation d'un calcul.
- L'interface utilisateur doit permettre de récupérer le résultat d'un calcul.
- L'API doit permettre d'effectuer les quatre opérations de base.
- L'API doit permettre d'effectuer le stockage et la récupération des calculs dans
redis. - L'API doit permettre d'effectuer la mise en file d'attente des demandes de calcul.
