Skip to content
Snippets Groups Projects
Verified Commit 76fe61a1 authored by Julien Wittouck's avatar Julien Wittouck
Browse files

:sparkles: : add cloud content

parent 22bf4167
No related branches found
No related tags found
No related merge requests found
Pipeline #53123 passed
Showing
with 13688 additions and 0 deletions
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>ALOM - Cloud</title>
<meta name="description" content="ALOM - High Availability">
<meta name="author" content="Julien WITTOUCK <julien@codeka.io>">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="../reveal/dist/reveal.css">
<link rel="stylesheet" href="../reveal/dist/theme/white.css" id="theme">
<link rel="stylesheet" href="../css/miage-lille.css"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>ALOM</h1>
<h2><i class="em em-cloud"></i> Patterns orientés cloud</h2>
</section>
<section>
<h3><i class="fab fa-uber"></i> UBER</h3>
<img src="images/Microservice-Architecture-Of-UBER.png" style="width: 50%"/>
</section>
<section>
<h2>Problématiques : </h2>
<p>Comment déployer les services ?</p>
<p>Comment gérer la configuration des services ?</p>
<p>Comment analyser l'enchaînement des appels ?</p>
<p>Comment connaître l'état de l'application ?</p>
</section>
<!-- cloud -->
<section>
<h2>Cloud "as a service"</h2>
<ul>
<li>IaaS : Infrastructure as a Service</li>
<li>PaaS : Platform as a Service</li>
<li>SaaS : Software as a Service</li>
</ul>
<img src="images/iaas--paas-saas-diagram.png"/>
</section>
<section>
<h2>Cloud 🇫🇷</h2>
<ul>
<li>
IaaS : VM, Disks, Load-Balancers
<ul>
<li>OVH Cloud</li>
<li>Scaleway</li>
<li>nua.ge</li>
<li>hopla.cloud</li>
<li>Outscale</li>
</ul>
</li>
<li>
PaaS : Database, Middleware, Object Storage, Runtime Java / Container, Functions
<ul>
<li>OVH : Databases & k8s, Object Storage</li>
<li>Scaleway: Databases & k8s, Object Storage, Serverless Functions</li>
<li>Clever-Cloud: PaaS, Databases, Object Storage</li>
<li>Scalingo: PaaS, Databases</li>
</ul>
</li>
</ul>
</section>
<section>
<h2>Cloud 🇺🇲</h2>
<ul>
<li>
IaaS : VM, Disks, Load-Balancers
<ul>
<li>AWS EC2</li>
<li>GCP GCE</li>
<li>Azure VM</li>
</ul>
</li>
<li>
PaaS : Database, Middleware, Object Storage, Runtime Java / Container, Functions
<ul>
<li>AWS : RDS Databases, EKS, S3 Object Storage, AWS Lambdas</li>
<li>GCP Cloud SQL, GKE, GCS Object Storage, Cloud Functions, App Engine, Pub/Sub</li>
<li>Azure SQL Database, AKS, Azure Blob Storage, Azure Functions</li>
</ul>
</li>
</ul>
</section>
<section>
<h2>Une architecture Cloud</h2>
<p>Une application Java dans un assemblage de services Cloud</p>
<img src="images/second-hand.png"/>
</section>
<section>
<h2>Une architecture Cloud</h2>
<ul>
<li>DNS (Route53)</li>
<li>Load Balancers (ALB)</li>
<li>VM (EC2) ⬅️ notre code est ici</li>
<li>Base de données managée (PostgreSQL)</li>
<li>Cache managé (ElasticSearch)</li>
<li>CDN (CloudFront)</li>
<li>Stockage objet (S3)</li>
<li>Messaging (SQS)</li>
<li>Mailing (SES)</li>
</ul>
</section>
<!-- configuration -->
<section>
<h3>Patterns d'architecture</h3>
<h4>Configuration externalisée</h4>
</section>
<section>
<h4>Configuration externalisée</h4>
<p>Permet d'exécuter un service dans multiples environnements sans modifications</p>
<ul>
<li>Accès BDD</li>
<li>Gestion sécurité</li>
<li>etc...</li>
</ul>
<p>Plusieurs stratégies</p>
<ul>
<li>Profiles : un fichier de configuration par profil</li>
<li>Variables d'environnement</li>
<li>Serveur de configuration</li>
</ul>
</section>
<section>
<h4>Configuration externalisée en Spring </h4>
<p>Profils</p>
<ul>
<li>Activation par la properties <code>spring.profiles.active</code></li>
<li>ou variable d'environnement <code>SPRING_PROFILES_ACTIVE</code></li>
</ul>
<p>Permet de charger un fichier <code>application-{profile}.properties</code> en plus du <code>application.properties</code>.
</p>
<p>Exemples: <code>application-local.properties</code> et <code>application-prod.properties</code> contenant
des ports/connexions BDD différentes.</p>
</section>
<section>
<h4>Configuration externalisée chez Spring</h4>
<p>Variables d'environnement</p>
<p>Toutes les properties Spring peuvent être surchargées par des variables d'environnement</p>
<ul>
<li>Les <code>.</code> sont remplacés par des <code>_</code>.</li>
<li>Tout est mis en majuscule</li>
<li>Le camel-case est convertit en <code>_</code></li>
</ul>
</section>
<section>
<h4>Configuration externalisée chez Spring</h4>
<p>Variables d'environnement</p>
<p>Exemples: </p>
<ul>
<li><code>server.port=8080</code> ➡️ <code>SERVER_PORT=8080</code></li>
<li><code>trainer.service.username=vegeta</code> ➡️ <code>TRAINER_SERVICE_USERNAME=vegeta</code></li>
<li><code>trainer.serviceUrl=https://someurl:8080</code> ➡️ <code>TRAINER_SERVICE_URL=https://someurl:8080</code>
</li>
</ul>
</section>
<section>
<h4>Configuration externalisée chez Spring</h4>
<p>Interpolation de properties</p>
<p>Il est possible dans des properties d'en utiliser d'autres</p>
<pre><code>trainer.service.host=someHost
trainer.service.port=8080
trainer.service.url=https://${trainer.service.host}:${trainer.service.port}</code></pre>
</section>
<section data-markdown>
<textarea data-template>
#### Serveurs de configuration
Chargement de properties gérées dans un serveur
Spring requête le serveur au démarrage pour charger les properties
* Vault / Consul
* Azure Key Vault, AWS/GCP Secret Manager
* Kubernetes ConfigMaps / Secrets
---
#### Serveurs de configuration
![](images/configuration-server.png)
Intérêts :
* partage de configuration entre plusieurs apps
* rotation de mots de passes sans devoir rebuilder l'appli
* centralisation et contrôle d'accès
</textarea>
</section>
<!-- centralisation de logs -->
<section>
<h3>Patterns d'architecture</h3>
<h4>Centralisation des logs et correlation</h4>
</section>
<section>
<h4>Centralisation des logs</h4>
<p>Dans un environnement load-balancé, les requêtes d'un utilisateur peuvent être traitées par n'importe
quel serveur.</p>
<p>Dans un environnement cloud, on ne peut pas forcément accéder aux machines pour consulter les fichiers de
log.</p>
<p>Dans un environnement conteneurisé, on ne peut pas forcément accéder aux logs des containers
(kubernetes...)</p>
</section>
<section>
<h4>Centralisation des logs</h4>
<p>On envoie tous les logs dans un service dédié</p>
<ul>
<li>un service lit les fichiers de log ou la sortie standard `stdout` et envoie les lignes au serveur</li>
<li>les logs sont indexés et conservés</li>
<li>une IHM permet de les consulter</li>
</ul>
</section>
<section>
<h4>Centralisation des logs</h4>
<h5>logs JSON</h5>
<p>Pour rendre les logs _requêtables_, ils sont souvent parsés :</p>
<pre><code>2023-11-28T14:05:57.429+01:00 INFO 62385 --- [ main] c.miage.altea.tp.trainer_api.TrainerApi : Started TrainerApi in 2.891 seconds (process running for 3.219)</code></pre>
<p>On configure parfois les loggers pour émettre du JSON directement utilisable en centralisation.</p>
</section>
<section>
<h4>Centralisation des logs</h4>
<img src="images/elk.png"/>
</section>
<section>
<h4>Centralisation des logs</h4>
<p>Produit connus :</p>
<p>Stack "ELK"</p>
<ul>
<li>Elasticsearch : indexation des logs, et recherche "full-text"</li>
<li>Logstash : Parsing des fichiers de logs, et envoi à Elasticsearch</li>
<li>Kibana : IHM de consultation d'Elasticsearch : recherche, dashboards...</li>
</ul>
</section>
<section>
<h4>Correlation des logs</h4>
<p>Observer la séquencialité des appels</p>
<p>Observer les logs d'un même utilisateur</p>
<p>Trouver des points de contention</p>
<p>Aide au debugging</p>
</section>
<section>
<h4>Correlation des logs</h4>
<p>Correlation des appels via des Headers HTTP</p>
<p>Création d'un id pour chaque requête reçue</p>
<p>Transmission de l'id à chaque requête envoyée</p>
<p>Envoi des traces à un outil centralisé</p>
</section>
<section>
<h4>Correlation des logs</h4>
<p><a href="https://spring.io/projects/spring-cloud-sleuth">Spring Cloud Sleuth</a> permet de gérer ces
correllation (il modifie les RestTemplate pour transmettre ces fameux headers).</p>
<p><a href="https://zipkin.io/">Zipkin</a> permet de collecter/consulter ce type d'information</p>
</section>
<section>
<h4>Correlation des logs</h4>
<img src="images/zipkin.png"/>
</section>
<!-- métriques -->
<section>
<h3>Patterns d'architecture</h3>
<h4>Observabilité / Métriques</h4>
</section>
<section>
<h4>Métriques</h4>
<p>Observer la santé des services</p>
<ul>
<li>healthcheck : est-ce que le service répond, est-ce que la BDD est bien connectée</li>
<li>trace : récupérer les dernières requêtes HTTP traitées</li>
<li>metrics : consommations mémoire / CPU</li>
</ul>
<p>Métriques métier (~analytics)</p>
<ul>
<li>Combien d'inscriptions au site</li>
<li>Combien de commandes passées</li>
<li>...</li>
</ul>
</section>
<section>
<h4>Métriques</h4>
<p>Exposition des métriques dans une application spring-boot</p>
<p>Utilisation de <a
href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html">spring-boot-actuator</a>
</p>
<p>Expose des métriques basiques de nos applications/api</p>
</section>
<section>
<h4>Métriques</h4>
<h5>Collecte des métriques et exploitation</h5>
<p>Comme pour les logs, les métriques peuvent être envoyées à un serveur dédié pour être consultées</p>
<p>Centralisation des métriques</p>
</section>
<section>
<h4>Métriques</h4>
<p>Même principe que pour les logs</p>
<img src="images/prometheus.png"/>
</section>
<section>
<h4>Métriques</h4>
<p>Produits connus :</p>
<p>Stack "Prometheus/Grafana"</p>
<ul>
<li>Prometheus : Concentration des métriques (BDD time/series)</li>
<li>Grafana : Affichage sous forme de graphes, altering</li>
</ul>
</section>
<section>
<h4>Métriques</h4>
<p>Agir en fonction des métriques</p>
<p>Pris en charge par les orchestrateurs de containers (kubernetes par exemple)</p>
<ul>
<li>healthcheck KO => redémarrer le service</li>
<li>consommation mémoire / CPU élevée => déployer une instance supplémentaire du service (scale up)</li>
</ul>
</section>
<section>
<h2>TP</h2>
<img src="../images/leonidas.png"/>
<p>
<a href="09-tp-cloud.html">Patterns cloud <i class="em em-cloud"></i></a>
</p>
</section>
</div>
</div>
<script src="../reveal/dist/reveal.js"></script>
<script src="../reveal/plugin/markdown/markdown.js"></script>
<link rel="stylesheet" href="../reveal/plugin/highlight/zenburn.css">
<script src="../reveal/plugin/highlight/highlight.js"></script>
<script>
// More info about initialization & config:
// - https://revealjs.com/initialization/
// - https://revealjs.com/config/
Reveal.initialize({
hash: true,
// Learn about plugins: https://revealjs.com/plugins/
plugins: [RevealMarkdown, RevealHighlight],
markdown: {
smartypants: true
}
});
</script>
<aside class="miage_aside_logo"></aside>
</body>
</html>
File added
:source-highlighter: rouge
:prewrap!:
:icons: font
:toc: left
:toclevels: 4
:linkattrs:
:sectlinks:
:sectanchors:
:sectnums:
:experimental:
:stem:
= ALOM - TP 9 - Patterns Cloud
== Présentation et objectifs
Le but de ce TP est de mettre en place quelques mécaniques pour les développements orientés cloud.
Nous allons :
* déployer nos applications chez Clever Cloud
* créer des profils pour chacun de nos micro-services
* exposer des métriques avec `spring-boot-actuator`
* charger les properties d'accès à notre base de données depuis un Vault
* envoyer des emails avec un nouveau micro-service d'envoi d'emails
// * charger un fichier de données depuis un bucket
== Déploiement chez Clever Cloud
NOTE: Clever Cloud a accepté de nous sponsoriser en nous offrant une organisation avec des crédits illimités 🙏.
Nous allons déployer nos TP chez Clever Cloud en utilisant 2 de leurs services :
* Pour la persistence : les bases de données PostgreSQL managées
* Pour le code : les applications Docker
=== Votre compte Clever Cloud
Créez un compte sur https://www.clever-cloud.com, en utilisant votre adresse mail d'étudiant !
En principe, vous devriez avoir aussi reçu une "invitation" à rejoindre l'organisation Clever Cloud _Université de Lille_. Acceptez cette invitation pour y avoir accès.
Vous pouvez accéder à l'organisation avec https://console.clever-cloud.com/organisations/orga_d02d9099-9664-47fd-8029-d90e36628e1d[ce lien direct].
=== La base de données
Pour remplacer notre base de données embarquée ou en docker, nous pouvons nous connecter sur une base de données réelle, que nous allons instancier sur un cloud public.
==== Créer la base de données
CAUTION: Les droits d'accès que vous avez ne permettent pas de créer des bases de données, je les ai créées en avance de phase pour vous. Cette partie est purement documentaire, vous pouvez la lire si ça vous intéresse, ou passer à la partie suivante <<_déploiement_des_applications>>.
Une fois votre compte créé, vous pouvez instancier une base de données en quelques clics !
* Dans la console, sélectionnez `Create > an add-on`.
image::images/clever-create.png[]
* Sélectionnez la base de données `postgresql`
image::images/clever-create-postgresql.png[]
* Sélectionnez le plan `DEV`, qui est gratuit
* Donnez un nom à votre base de données, et sélectionnez la région `Paris` (un hébergement de notre base de données à Montréal créerait des temps de latence importants !)
image::images/clever-dev-free-plan.png[]
image::images/clever-naming-database.png[]
* Validez, et attendez quelques secondes. Votre base de données est prête !
Accédez au dashboard de votre base de données. Vous pourrez y trouver:
* Les informations de connexion à votre base de données
* Des menus permettant de réinitialiser votre base, re-généré de nouveaux identifiants de connexions, ou effectuer un backup.
* Vous pouvez également accéder à une interface "PGStudio" vous permettant de naviguer dans votre base de données.
.La page d'informations de votre base de données !
image::images/clever-database-information.png[]
=== Déploiement des applications
WARNING: Pour cette partie, je dois vous donner les droits d'accès à l'organisation. Appelez-moi pour que je puisse le faire avec vous si vos accès ne sont pas ouverts. J'ai aussi créé pour vous les applications sur Clever Cloud pour vous faciliter la vie. Vous pouvez les utiliser, ou en créer d'autres.
==== Création d'un token Clever Cloud
Générez un access token et un secret Clever Cloud pour que le pipeline GitLab puisse s'authentifier.
Rendez-vous à cette URL : https://console.clever-cloud.com/cli-oauth[, role="external", window="_blank"]
Récupérez le Token et Secret affichés.
Rendez-vous dans votre projet GitLab, dans la section _Settings / CI/CD_ / Variables.
Créez deux variables `CLEVER_TOKEN` et `CLEVER_SECRET`, de type _Variable_, avec les valeurs récupérées (attention aux espaces en début et fin de ligne).
==== Ajout d'un Dockerfile
Dans le code de _chacun_ de vos micro-services, ajoutez le `Dockerfile` suivant (il n'est pas parfait, mais fais bien le travail) :
[source,Dockerfile]
.Dockerfile
----
# Stage 1: Build the application
FROM maven:3-eclipse-temurin-21-alpine AS build
WORKDIR /app
# Copy the pom.xml file
COPY pom.xml .
# Copy your source code
COPY src ./src
# Build the application
RUN mvn package -DskipTests
# Stage 2: Create the runtime image
FROM eclipse-temurin:21-alpine
WORKDIR /app
# Copy the jar file from the build stage
COPY --from=build /app/target/*.jar app.jar
# Expose the port the app runs on
EXPOSE 8080
# Run the jar file
ENTRYPOINT ["java","-jar","app.jar"]
----
==== Ajout d'un pipeline de CI
Sur Clever Cloud, récupérez le `app_id` en allant dans l'onglet _Information_ de votre application, ou en haut à droite de l'écran _Overview_ de votre application.
Modifiez vos fichiers `.gitlab-ci.yml` pour y ajouter une étape _deploy_, ainsi qu'une variable `CC_APP_ID` :
..gitlab-ci.yml
[source,yaml]
----
variables:
CC_APP_ID: # <1>
deploy:
image:
name: clevercloud/clever-tools
entrypoint: ["/bin/sh", "-c"]
stage: deploy
script:
- clever link $CC_APP_ID
- clever deploy --force
----
<1> : Renseignez ici l'application id de votre application sur Clever Cloud
Pushez sur Git votre `Dockerfile` et votre `.gitlab-ci.yml` modifié.
NOTE: Si toutes les étapes sont correctes, chaque `git push` occasionnera un déploiement de votre application !
Répétez les opérations pour chacune de vos applications.
== Création de profils et activation
Aujourd'hui, nos micro-services devront tourner sur plusieurs environnements distincts :
* notre poste de développeur
* un déploiement d'application Docker chez _Clever Cloud_
On pourrait aussi imaginer vouloir créer un troisième environnement, de recette métier par exemple.
=== Extraction des profils
Pour chacun de vos micro-services :
* Créez un fichier de configuration `application-clever.properties`
Ce fichier contiendra toutes les properties liées à l'environnement d'exécution Clever-Cloud,
par exemple les URL des autres micro-services, et l'URL de connexion à la base de données.
* Créez un fichier de configuration `application-local.properties`
Ce fichier contiendra toutes les properties liées à l'exécution en local de votre projet,
par exemple les URL des autres micro-services en `localhost`, ainsi que les properties `server.port`
À cette étape, vous pouvez vider vos fichiers `application.properties`, dont le contenu a dû être migré dans les deux fichiers
`application-local.properties` et `application-clever.properties`.
NOTE: Il est parfois utile d'avoir des properties communes dans le `application.properties`. Attention par contre, dans le cas d'utilisation d'un profil, les properties du `application.properties` sont d'abord chargées, et ensuite les properties du profil `application-{profil}.properties`.
=== Activation des profils
==== Sur votre poste
Lorsque vous démarrez vos micro-services sur votre poste, il vous faut maintenant utiliser le profil `local`.
Pour ce faire, vous pouvez indiquer à Spring que le profil local est le profil à utiliser par défaut en absence de tout autre profil.
Pour ce faire, nous allons ajouter un paramètre au lancement de notre application.
Dans IntelliJ, ce paramètre s'ajoute dans la fenêtre de lancement :
image::images/profile-intellij.png[]
Pour les autres IDE, le paramètre peut être passé à la ligne de commande java :
[source,bash]
----
java -jar trainer-api.jar --spring.profiles.active=local
----
ou positionné avec une variable d'environnement :
[source,bash]
----
export SPRING_PROFILES_ACTIVE=local
java -jar trainer-api.jar
----
==== Sur l'environnement Clever
Pour vos applications déployées sur Clever-Cloud, nous allons utiliser des variables d'environnement.
L'ajout d'une variable d'environnement se fait directement depuis l'onglet _Environment variables_ d'une application :
image::images/clever-env-vars.png[]
Ajoutez à vos applications la variable `SPRING_PROFILES_ACTIVE=clever`.
== Exposition de métriques
L'exposition de métriques pour nos applications se fait avec `spring-boot-actuator`.
=== Dépendance maven
Ajoutez la dépendance maven suivante dans vos projets :
[source,xml]
.pom.xml
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
----
NOTE: Ajouter la dépendance suffit à _spring-boot_ pour configurer des routes par défaut.
Démarrez ensuite vos applications.
Vous devriez y observer des logs dédiés à actuator au démarrage :
----
INFO 28827 --- [main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
TRACE 28827 --- [main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Register "{GET /actuator/health, produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}" to java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
TRACE 28827 --- [main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Register "{GET /actuator/health/**, produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}" to java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
TRACE 28827 --- [main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Register "{GET /actuator/info, produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}" to java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
TRACE 28827 --- [main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Register "{GET /actuator, produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}" to public java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$WebMvcLinksHandler.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
----
Consultez enfin pour vos services le endpoint "/actuator/health" :
[source,json]
.GET localhost:8080/actuator/health
----
{"status":"UP"}
----
=== Activer d'autres endpoints
`spring-boot-actuator` propose de nombreux endpoints par défaut.
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints
Exposez au moins les endpoints suivants :
* `env`
* `metrics`
Allez jeter un œil aux endpoints suivants :
* http://localhost:8080/actuator/env
* http://localhost:8080/actuator/metrics
* http://localhost:8080/actuator/metrics/process.cpu.usage
== Connection au Vault
Un serveur _Vault_ est disponible à l'adresse suivante : https://vault-alom-2024.cleverapps.io
Vous pouvez vous y connecter avec vos identifiants GitLab (laissez le rôle vide) :
image::images/vault-login.png[]
Une fois authentifié, ouvrez le _Secret Engine_ nommé _secret/_.
Vous y trouverez un espace pour chacun d'entre vous. Vous avez les droits pour consulter / modifier les secrets qui vous appartiennent.
image::images/vault-secrets-jwk.png[]
Un secret _database-secrets_ a déjà été initialisé pour vous, avez les informations liées à votre base de données.
image::images/vault-database-secret.png[]
=== Spring Cloud Vault
Pour connecter votre application au Vault, ajoutez la dépendance suivante à vos projets :
[source,xml]
.pom.xml
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
<version>4.1.3</version>
</dependency>
----
Configurez ensuite les properties suivantes :
[source,properties]
.application-clever.properties
----
spring.cloud.vault.uri=https://vault-alom-2024.cleverapps.io/
spring.cloud.vault.token=<token>
spring.config.import=vault://secret/<name>/database-secrets
----
Remplacez `<name>` par votre nom d'utilisateur GitLab (se terminant par `.etu`), et en supprimant les `<>`.
Pour le token, une fois connecté au Vault, vous pouvez en récupérer un en dans le menu.
image::images/vault-get-token.png[]
NOTE: Dans vos properties locales, si vous ne voulez pas utiliser le Vault, vous pouvez aussi ajouter la properties `spring.cloud.vault.enabled=false`.
NOTE: Comme Clever Cloud exécute les tests avec maven au démarrage de l'application, tout en ayant la variable d'environnement `SPRING_PROFILES_ACTIVE` injectée, vous pouvez aussi ajouter un fichier `src/test/resources/application-clever.properties` vide pour éviter que les tests consomment les properties de prod.
=== Reconfiguration des properties
Reconfigurez vos properties, en particulier l'accès à la base de données (url, user, mot de passe).
Les properties utilisées par Vault sont accessibles directement, vous pouvez par exemple écrire la properties suivante : `spring.datasource.username=${pg_user}`, la valeur `pg_user` de votre Vault sera chargée au démarrage de l'application.
== Envoi d'emails
Pour l'envoi d'emails, initialisez un nouveau projet avec le lien suivant : https://gitlab-classrooms.cleverapps.io/assignments/05c7191e-ef4e-421f-b112-38ed91d86227/accept[GitLab Classrooms].
Ajoutez dans le `pom.xml` les dépendances suivantes :
* spring-boot-starter-mail
* spring-cloud-starter-vault-config
Importez le secret nommé `mail-secrets` depuis le Vault.
Pour envoyer un email, recevez en injection de dépendance une instance de `JavaMailSender`.
Voici un exemple de code qui envoie un email :
[source,java]
.SendMail.java
----
var message = mailSender.createMimeMessage();
message.setFrom("no-reply@gitlab-classrooms.org");
message.setRecipients(Message.RecipientType.TO, "");
message.setSubject("Test From Spring Boot");
message.setText("This is a test from a Spring Boot application.");
mailSender.send(message);
----
Exposez des routes HTTP dans votre service de mailing qui permettent d'envoyer différents mails :
* un email de bienvenue (reçoit le nom d'un Trainer en paramètre, ainsi que son email)
* un email de fin de combat (reçoit les noms des 2 adversaires, leurs emails, et l'information de qui a gagné le combat)
Modifiez en conséquence le `game-ui` pour appeler ces deux nouvelles routes depuis `game-ui` et `battle-api`.
//
// == Consommation d'un bucket
//
// Dans cette partie, nous allons connecter le micro-service `battle-api` à un bucket, dans lequel nous allons stocker des rapports de combat.
//
// Lorsqu'un combat est terminé, nous allons le stocker dans un fichier au format JSON, à titre d'archivage.
//
// === Création du bucket
//
// Dans Clever-Cloud, créez un add-on de type *Cellar S3 storage*, ne le liez pas tout de suite à une application.
// Nommez le _cellar-<Votre Pseudo Github>_.
//
// Dans l'add-on, créez un bucket, nommez-le _battle-reports-<Votre Pseudo Github>_
//
// WARNING: les buckets doivent avoir un nom unique parmi tous les buckets existants.
//
// === battle-api
//
// ==== Dépendance Spring
//
// Pour consommer un bucket, nous allons utiliser le client du SDK Amazon S3.
//
// NOTE: Les buckets exposés par Clever-Cloud sont compatibles avec l'API Amazon S3.
//
// Ajoutez la dépendance suivante à votre code :
//
// [source,xml]
// .pom.xml
// ----
// <dependency>
// <groupId>com.amazonaws</groupId>
// <artifactId>aws-java-sdk-s3</artifactId>
// <version>1.12.109</version>
// </dependency>
// ----
//
// ==== Ajout de nouvelles properties
//
// Dans l'onglet _Information_ de l'add-on Cellar, sur Clever-Cloud, on peut voir que l'add-on expose des variables d'environnement.
//
// image::images/cellar-env.png[]
//
// Créez dans votre fichier `application-local.properties` les 3 properties correspondant aux variables d'environnement.
//
// NOTE: Pour l'exécution sur Clever-Cloud, les variables d'environnement seront directement injectées à l'application, nous n'avons pas besoin de les déclarer dans le profil `clever`.
//
// ==== Configuration d'un client S3
//
// Créez une classe de configuration, dans laquelle vous créez un `@Bean` de type `AmazonS3`,
// un peu à la manière de ce qu'on a déjà fait pour les `RestTemplate` par exemple.
//
// Recevez en injection de dépendance avec `@Value` les 3 properties Cellar.
//
// Initialisez votre client S3 avec le code suivant (à adapter):
//
// [source,java]
// .CellarConfiguration.java
// ----
// AWSCredentials credentials = new BasicAWSCredentials(
// cellarKeyId,
// cellarKeySecret
// );
//
// AmazonS3 s3client = AmazonS3ClientBuilder
// .standard()
// .withCredentials(new AWSStaticCredentialsProvider(credentials))
// .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(cellarHost,""))
// .build();
// ----
//
// ==== Création d'un objet dans le bucket
//
// Pour créer un nouvel objet dans le bucket, vous pouvez utiliser la méthode `putObject(String bucketName,String key,String content)`.
//
// À la fin d'un combat, sérialisez l'objet Battle en JSON (en utilisant un ObjectMapper), puis créez un nouvel objet dans votre bucket,
// ayant comme clé _<Battle.id>.json_.
//
// Déployez votre code modifié, et liez votre add-on cellar à votre _battle-api_, pour que ses variables d'environnement soient injectées.
//
// ==== Parcours du bucket
//
// Clever-cloud ne propose pas d'IHM pour parcourir les buckets.
// Vous pouvez utiliser https://www.filestash.app/aws-s3-explorer.html pour explorer votre bucket, en y saisissant:
//
// * votre access key id (CELLAR_ADDON_KEY_ID)
// * votre secret access key (CELLAR_ADDON_KEY_SECRET)
// * le endpoint (dans la partie advanced) (CELLAR_ADDON_HOST)
This diff is collapsed.
This diff is collapsed.
w09-cloud/images/Microservice-Architecture-Of-UBER.png

55.5 KiB

w09-cloud/images/cellar-env.png

26.4 KiB

w09-cloud/images/clever-create-postgresql.png

9.14 KiB

w09-cloud/images/clever-create.png

5.83 KiB

w09-cloud/images/clever-database-information.png

70.8 KiB

w09-cloud/images/clever-dev-free-plan.png

4.65 KiB

w09-cloud/images/clever-env-vars.png

75.3 KiB

File added
w09-cloud/images/clever-naming-database.png

9.81 KiB

<mxfile host="Electron" modified="2023-11-28T09:48:42.169Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="JTlYzwPmbqsIv_NEV598" version="22.1.2" type="device">
<diagram name="Page-1" id="jDyy53wIk9Mf8CvKnBFR">
<mxGraphModel dx="539" dy="310" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="kHj-4aMl6Otf4dMbhvV_-1" value="storage" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
<mxGeometry x="440" y="80" width="60" height="80" as="geometry" />
</mxCell>
<mxCell id="kHj-4aMl6Otf4dMbhvV_-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="kHj-4aMl6Otf4dMbhvV_-2" target="kHj-4aMl6Otf4dMbhvV_-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="kHj-4aMl6Otf4dMbhvV_-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="kHj-4aMl6Otf4dMbhvV_-2" target="kHj-4aMl6Otf4dMbhvV_-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="kHj-4aMl6Otf4dMbhvV_-2" value="config server" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
<mxGeometry x="280" y="90" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="kHj-4aMl6Otf4dMbhvV_-5" value="get config" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;" edge="1" parent="1" source="kHj-4aMl6Otf4dMbhvV_-4" target="kHj-4aMl6Otf4dMbhvV_-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="kHj-4aMl6Otf4dMbhvV_-4" value="app instance" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="40" y="90" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="kHj-4aMl6Otf4dMbhvV_-6" value="" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.saml_token;fillColor=#D2D3D3;gradientColor=none;" vertex="1" parent="1">
<mxGeometry x="170" y="95" width="20" height="20" as="geometry" />
</mxCell>
<mxCell id="kHj-4aMl6Otf4dMbhvV_-9" value="" style="dashed=0;outlineConnect=0;html=1;align=center;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;shape=mxgraph.weblogos.json" vertex="1" parent="1">
<mxGeometry x="205" y="120" width="30" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
w09-cloud/images/configuration-server.png

10.8 KiB

<mxfile host="Electron" modified="2020-03-14T11:51:56.852Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.6.5 Chrome/80.0.3987.86 Electron/8.0.0 Safari/537.36" etag="_dyBuH4mdJftQV1mscXY" version="12.6.5" type="device" pages="2"><diagram id="ccw_6uiwa0TcYFpVubD9" name="elk">7VrbbtswDP2aPC6wJTtOHnPrVqAFCvRh2FOh2oqjVbEMWc5lXz8qluNrm25Nc2nbAIV1TFMUDynRTDp4vFh/lySe34qA8g6ygnUHTzoIeZ4L/zWwyQDHcTIglCzIILsA7tkfakDLoCkLaFIRVEJwxeIq6Isoor6qYERKsaqKzQSvzhqTkDaAe5/wJvqTBWqeoX3XKvAflIXzfGbbMncWJBc2QDIngViVIDzt4LEUQmVXi/WYcu273C/Zc1fP3N0ZJmmkXvMAHl5fhb1fY4zvJJ7x6ciNb78ZdpaEp2bBCZVLKgEzEyRqk/tixjgfCy4kDCMRATpKlBRPNAc7CLvD3rjfgzsBSeZUT23DADQqBk4dchZGgCkRAzoTkbo36i0zblNlbAQddP3s4u2dSyEUqVhQJTcgYh5wDAkmCvtmuCooRdhg8zKduSAxYRTuNBeehgvj7H9wPGo4vuHuWLBIUTldwhoT48hdEFllF+vBXC14LlQhxTBVJg+c62DIRBdwksRZ3szYWisbcfJI+Z1ImGJCc+VTbUWJxJuawKNQSiyeZZmY0U6PSBVnEdiXZ6yVLSzW616sQ72PdJfLoMtF+ABm6/Q/RAzYdjUIbNSMAqclCNz3igG8PwZafVXh/VCslOOnxgVZJbirJAm2ugl/MHtEI6i8iTf2xoCHWpgW2Wxi8AAk9s6MQ+8rj0+ex4MTx0C/EQNQjWg3SaJoCmdpj4MJo0d9FeqrgDYxcFLyuvSvHZPwudLGNpIO7g0cd3KFSvcmTIKijO9ISO2uekS5Q2yN3Lazfbb9O8IGtC0MslLQRi2FQiPWW3YspytpIlLp02tf2zOCYXZVlaKcJGBeQon059udjfkH2qsw2r9ZuccM1DxxShFGAyh3zVDHgwj1Dj8t0JEUaRTs2C5kboTmccvXb6rUxhBGUiWqbGZz6ole9iPYteXrhQUMMjlFZEjVvuqqyYsEshVbVu04vJeblfPH9LL3Ri9vHx1KSTYlge1pmZQ032mgSCpUSypkuzXGMo0FfzvT3kBp81T/mJT2T5k4g0uqh1dCPrXVwJPB0HPsd62BkXVu50r/wtPD9i4hP+yjv2y8+ztEvfa09Kcl5RaJT2gXlpZGtJtClfYQQvzEB0gmx9mfTL2jJlNzG9z15Jp8f5ye3Dk05axjJ9jX23z9bR6fuqOTL+EyypDzbMudnsSv/vrpM/nUfTmEL7wsRe4ry9LSF4onqEuR82n8/NbG0kFaHs4xWh6o91lIfes73f9xOqhtlk6F073ytnOMGGj+POCMS6Ez6si01T8H6sjAsPjNSEZ08cMbPP0L</diagram><diagram id="bL8FhdlCwTQHA1C7OWGw" name="prometheus">7Vrfc5s4EP5r/FgPCLDh0cZxrzNtLzOZm2ufMjLIWBdARIjYzl9/KxCYX63TOCZuE/vB0iKtpP2+XS07HhlutPvIcbL5wnwSjpDm70bGYoSQblka/EjJvpDYtl0IAk59NegguKGPRAnVvCCjPkkbAwVjoaBJU+ixOCaeaMgw52zbHLZmYXPVBAekI7jxcNiV/kt9sVGnKI8l5X8RGmzKlXVNPYlwOVgJ0g322bYmMq5GhssZE0Ur2rkklMYr7XJ//2jPApbNw5Xrb4P94+0/9odC2fJXplRH4CQWz1b9aast/e93q7uvk72NXPH3ty9YTdEecJgpe6WEPxAOMrVqKvalKdc0DF0WMg7dmMUgnaeCsztSCkfIsGYT157AEx+nGyKX1qEDGgUFTGYhDWKQCZaAdM1icaPUa6rfp0rtEXSQXQvUIxbRK5iA34RFRPA9zFNaTHX6ktmquz3QBBlKtqlTxFFCrKgZVJoP5oeGQuAX0EAdNDoYsEyENAaLl96i1W2t1Wz9Ga9IeM1SKiiTNl8xIVj0QzCw6nlgUcDfmG9EFCr4gPmJXD/aBTJIjPE2NcaCYz/XjcNbRRqAsEYRgHC6mLpTF+SBHEwO8Cr6nAvZSRNZHXWhNXuQtc4FrNkBFsKdtDTHgmTgbZMQtjBfyVYgWz7pyqKRa4xmjuD0PoOI+iRmtFwKvku57Q4e8MwxrcUS1Z4tKAdFBXlixqXh2vhaM0ObW31xYJ1/BuBmHkSKW0dHPUEFp0lhjjXdyX30kdkcc5KyjHvkkyf3M4du0WqOIiFOYXspwdzb5KSn3jlpbKDjPLaG5LHVYR3x4bZVXckRFsiAcHWQzjnLYr9iwGHMZyaxzTH8jwixVyDiTLAmwsWacqFn2BY2mwP7k0OpfEZgHhDxk3G60w8WB1oI+tDcXZ/p1dRrRmHfFci61QLZtJoqio2pWS0Aq208H9PJW8a0lsidgOmMc7yvDUgkVumPIUctvwYOtJAtND6NMOXsoQgzfcuEMU/ky0nh1/6d8sMt43d9OeHCmU1NfficEGkXdpk6f6Ifla/9l+1Ieve9twNGHsQJv3ogMpZXRC9KAB2vqntDIxdWrA5b3la50Uu5Yzsz1+S3xzej1MNkDEfLYjLOIIe9DYBUybm8zjSPe91kSK/TX+X6IjsqvtXa36WqsaV6i53SnHf2tc414RTOLRHOZed2X2QN5L7Py5ucJpkMq5E3HR1fptZPy7NQK88y2ol5Yc2z5Vm60wlSOKEXfOPTOBU4zt+IW9FoadmWYQ5/5+v6hd35qHvxvGN6IqbOa2OqdzCtiujdtOIPL6KjHjSGrqK/l9HPU0Y3jC62g5bRkfEaudvF5Fxo8hJJ19F6UplVDVVPQubbRnX6EqieWoI00SklyHL2YJSxfqcQf+mVsL64PmwGNenA+Z4Vn5YVvz6m03dMXxhTUzsbptA9/JGpiNKHv4MZV/8D</diagram></mxfile>
\ No newline at end of file
w09-cloud/images/elk.png

24 KiB

w09-cloud/images/iaas--paas-saas-diagram.png

51.1 KiB

w09-cloud/images/profile-intellij.png

33.8 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment