Exemple de design de
microservices
Rappels sur les microservices
Le monolithe
- Petit et rapide au début
- Gros et lent avec le temps
- Accumulation de dette technique
- Maintenance de plus en plus coûteuse
coût
temps
Le microservice
- Un monolithe qui ne grandit jamais
- Dette technique raisonnable
- Un coût de maintenance raisonnable
coût
temps
Architecture microservice
- Des boîtes noires qui échangent des messages
- Chaque service ignore ce que fait son voisin
(il n'en connait que l'interface - API)
coût
temps
Risques
- Externaliser la complexité (le plat de spaghetti) dans les relations entre services
=> formaliser les règles de communication- normes
- formats
- asynchrone, synchrone, offline
- Augmenter le nombre de pannes possibles
=> formaliser les règles de conception- service minimum
- résilience aux pannes
- redéploiement automatique
Les contraintes et avantages
Les points clés d'un microservice
- Élastique
- Résilient
- Composable
- Minimal
- Complet
Les points clés
Élastique
- il peut y avoir une ou plusieurs instances
- permet la montée en charge
Les points clés
Résilient
- ne doit pas planter si un autre est indisponible
- lors d'une interruption dû à une mise à jour
- lorsque la base est momentanément indisponible
Les points clés
Composable
- seule l'API définit le service
- pas de couplage
- éviter les services de conversion de format
Les points clés
Minimal
- responsabilité unique
- pas de fonctionnalité inutile
Les points clés
Complet
- toutes les fonctionnalités nécessaires
- il doit être autonome
- possède sa propre base de données
Quelques analogies avec la POO
SOLID
- Simple responsibility principle
- Open/close principle
- Liskov substitution principle
- Interface segregation principle
- Dependency inversion principle
Corollaires
Stateless
L'élasticité implique que toute requête doit être
- stateless
- self content
Autorisation
- le système étant ouvert tout est accessible
=> utilisation d'un contrôle d'accès - pour ne pas dépendre d'un service tiers
=> via token self content
=> contrôle d'accès autonome
Droits d'accès
- le service définit et gère
- ses propres rôles
- ses propres droits
Format d'échange
- utilisation de normes pour le format des données
- existantes
- ou à créer
- protocole RESTful pour le CRUD des ressources
Découverte du service
- ce n'est pas wsdl
- néanmoins des standards apparaissent
- OpenAPI (swagger) permet de spécifier l'API
Typologie des services
- Différentes types de services ayant chacun leur rôle
- référentiels = réalise CRUD sur des entités
- fonctions = réalise une fonction
- intermédiateur = converti un format
- orchestre/chorégraphe = appelle d'autres services
- ...
- si plusieurs rôles dans un même service


Phylogénie des services
- les services peuvent évoluer
- se scinder si deux rôles
- ou fusionner si couplage
Webhooks
- ils sont pour les services
ce que sont les messages pour les objets - évitent le couplage
Principaux types
Référentiel
Rôle
- API CRUD sur des entités
- Interface entre l'API et le stockage des entités
- Gère les droits d'accès aux entités
- Les limitations ne sont pas de son ressort
Exemples
- Tiers
- Tâches
- ...
Fonction
Rôle
- Réaliser une ou des fonctions
- Gère les droits d'accès aux fonctions
Exemples
- Envoyer un SMS
- Fusionner des données dans un modèle de document
- Effectuer un virement
Intermédiateur
Rôle
- S'insérer entre deux services aux formats incompatibles
- Convertir des données d'un format vers un autres
Exemples
- conversion d'un format spécifique d'utilisateurs vers le format adullact
- ...
Orchestrateur
Rôles
- Composer une fonction complexe en appelant les autres services
- Réaliser la chorégraphie entre les services
Exemples
- Des fonctions métier
- ...
Choses communes
Choses communes
La plupart des services ont en commun
- l'exposition des informations et status
- le contrôle d'accès
- les webhooks
- le multi-tenant & configurations
- la gestion des ressources
Informations
& Status
Informations
- liens de découverte du service
- rôles
- version
- swagger
- license
Status
- état du service
- états des dépendances
Contrôle d'accès
Distinguer les rôles
Rôles ≠ Groupes
Groupe
Le groupe dont on fait parti, c'est lié à :
- l'organigramme
- la hiérarchie
- les unités
- ...
exemples :
- marketing, stagiaires, permanents, développeur, rh,...
Un utilisateur peut faire parti de plusieurs groupes
Rôle
Le rôle que l'on a vis-à-vis du service, dépend de ce qu'on a le droit de faire :
- administrateur : gère l'ensemble du service
- manager : gère un tenant du service
- utilisateur : utilise le service
Les rôles peuvent être déclinés en sous-rôles pour plus de finesse
- rédacteur, contrôleur,...
Exemple
On a
- un utilisateur chez un intégrateur de service
- il a accès à trois plateformes/tenants
- test/* : celle de test pour vendre
- prod/client : celle de son client qu'il est en train d'intégrer
- prod/lui-même : celle qu'il utilise pour gérer ses projets
- ses accès sont respectivement :
- administrateur : il doit pouvoir faire ce qu'il veut
- manager : il doit pouvoir modifier le tenant de son client
- utilisateur : il est simple utilisateur de son propre tenant
Pourtant c'est le même utilisateur faisant parti des mêmes groupes
Group/Role mapping
- Pour connaître les droits d'un utilisateur il faut déterminer ces rôles à partir de ses groupes
- C'est le rôle du dictionnaire groupe/rôle qui à chaque groupe associée des rôles
- Ce dictionnaire est spécifique à chaque tenant
tenant
group/role
groups
roles
requête
utilisateur
Le problème de l'initalisation
- global/pas de tenant => il faut qu'un administrateur initialise le groupRoleMapping général pour l'administrateur => 💀
=> il faut un compte initial dans la config
supprimé par la suite
- un tenant est créé => le groupRoleMapping de ce tenant est vide => le manager n'a pas accès et ne peut pas mettre le mapping à jour => 💀
=> l'administrateur doit ajouter un groupe pour le manager, ensuite le manager peut gérer le mapping de son tenant

Attention aux droits
💀
le manager ne doit pas pouvoir ajouter le rôle administrateur dans le mapping de son tenant
sinon il peut augmenter ses propres droits
Basic auth
username + password
- ne contient pas d'authentification intrinsèque
=> il faut authentifier l'utilisateur avec son identifiant et son mot de passe - ne contient pas de payload
=> il faut recherche les groupes associés à l'utilisateur
=> gérer une liste interne contenant les utilisateurs autorisés et définir pour chaque utilisateur la liste des groupes dont il fait parti (ou faire appel à un service tiers)
Utile pour
- les tests
- l'initialisation (temporairement)
JWT
Token self content avec authentification & payload
- on sait que l'utilisateur a été authentifié par l'émetteur du token
-
self content peut donc contenir toute l'information nécessaire
- groupes par tenant
- id de l'utilisateur
Droits positif/négatif
-
droit positif
tout le monde a le droit sauf ... - droit négatif
personne n'a le droit sauf ...

Toujours utiliser un droit de même type
Ne jamais mixer les deux types sur une même ressource
Webhooks
Webhooks
- ce sont les messages du service
- permettent chaîner les services
- pas de norme, mais des standards apparaissent
Webhook
définit par
- un déclencheur
- une opération
- création, mise à jour, suppression
-
une cible
- une ressource ou un type de ressources
- une opération
-
une réponse : l'appel d'un service
- opération : GET, POST,...
- une url
-
un corps
- brut, filtré, reformaté,...
Création d'un webhook
un webhook est défini
- au niveau du service ou du tenant
- statiquement ou dynamiquement
- dans la configuration
- par un appel à une API
- avec ou sans durée de vie
Exemple
référentiel tâches
PATCH tâche
POST sms
data wharehouse
POST tâche
envoi de sms
Exemple
référentiel tâches
PATCH tâche
formatage sms
POST tâche
data wharehouse
POST tâche
envoi de sms
POST sms
Exemple de configuration
module tiers MGDIS
"webhooks": [
{
"topic": "POST+*/tiers",
"callback": "/document-collect/stnazaire/root/tiers?cmisaction=createFolder&propertyId[0]=cmis:name&propertyValue[0]={reference}&propertyId[1]=cmis:objectTypeId&propertyValue[1]=cmis:folder&succinct=true",
"method": "POST",
"options": {
"withoutBody": true
}
},
{
"topic": "POST+*/tiers",
"callback": "/request/api/stnazaire/collections/tiers/{reference}",
"method": "PUT",
"headers": {
"Authorization": "Basic YWRtaW46QzdOYVdWMzlwM1M4R0hFd2RTTjNIZ1lwVzFXMGVtS1E="
}
},
{
"topic": "POST+*/tiers",
"callback": "https://wwx2.mairie-saintnazaire.fr/BlueAccess/application/referentiel_association_TEST/modules/webhook/index.php?reftiers={reference}",
"method": "PUT"
},
]Multi-tenant & Configuration
Multi-tenant
- partager un même service entre plusieurs locataires
- tenant ≠ client
(même si 99% du temps c'est pareil) - le tenant est créé dynamiquement
(à chaud pas de redéploiement)
Configuration
Plusieurs parties :
- paramètres globaux du service accessibles à l'administrateur
- associés à chaque tenant
- paramètres accessibles à l'administrateur (privés)
- paramètres accessibles au manager (publics)
Ressources/objets
Les schémas
Ils sont obligatoires pour :
-
la validation de l'API
- définition (OpenAPI/swagger)
- requête
- réponse
- la gestion du format de la persistance
Persistance
Rappel
- L'objet manipulé par
- l'ihm (reçu par le navigateur via l'API)
- le serveur (pour préparer sa réponse)
- la base de données (pour les stocker)
NE SONT PAS (forcément/souvent) LES MÊMES
Snapshot
On ne garde que le dernier état de la ressource
- simple
- la ressource est immédiatement disponible
- permet peu de choses
Incrémentale
On stocke toutes les modifications réalisées sur la ressource
- complet : qui, quoi, quand
- besoin de reconstituer la ressource
- permet de retracer l'historique
(on peut ajouter un cache snapshot pour accélérer l'accès)
Référentiel
Un référentiel doit gérer l'historique des ressources qu'il gère
=>
Utilisation de la sauvegarde incrémentale obligatoire
Fonctions & orchestre
Fonctions
- Simples (pas d'état)
- intermédiateurs
- Complexes (avec état)
- fonctionnalités métier
- orchestration
Simples
Intermédiateurs
- pas de stockage d'information
- fonction pure
- idempotence
- donc service simplifié
- facilement remplaçable
- authentification simplifiée (voir inutile)
- utilisation d'EIP => Apache Camel
- container obligatoire
Complexes
Métier ou orchestrateur
- éventuellement du stockage d'information
- pas fonction pure
- pas d'idempotence
- donc service plus classique
- authentification complète
(mais rôles souvent moins nombreux) - pour les orchestrateur => EIP / BPM
(Apache Camel / Bonita) - pour les autres => comme un service référentiel
- authentification complète
Apache Camel
Basé sur les Entreprise Integration Pattern
(C'est à l'intégration ce que sont les Design Patterns à la POO)


Migration
Du monolithe
aux services
en trois étapes
- factoriser/modulariser
- créer des api
- faire des services
Découpage
première étape
- factoriser/modulariser le code existant
- limiter les dépendances
API
deuxième étape
- créer des api
- faire des tests unitaires dessus
- utiliser les API
Tests
Migration
troisième étape
- faire des services
- extraire le code
Tests
D'une base à une autre
- dissocier les bases de données en trois étapes
- la troisième vous étonnera
Dissocier lecture et écriture
première étape
- utiliser l'api pour l'écriture
Dissocier les données
deuxième étape
- récrire le service
- utiliser une autre base
Migration totale
troisième étape
- utiliser uniquement l'API
Environnement
Déploiement
Containers rules the world
-
pour les containers
- Docker s'impose
- pour la composition de containers
- Docker Compose
- pour le cluster
- Docker Swarm ↘
- Kubernetes (k8s) ↗
Atelier logiciel
- Automatiser du développement au déploiement
- Utiliser les outils nécessaires
- organisation : redmine, jira, trello,...
- automatisation : jenkins
- qualité : sonarqube, linters,...
- tests unitaires
- tests d'intégration
- bug tracker : mantis, redmine, jira,...



Log
Monitorer
- Sans log impossible de suivre le fonctionnement, l'état de santé des nombreux containers
- Outiller les logs : ELK (ElasticSearch Logstash Kibana)
Prendre la solution adaptée


Exemples de design de microservices
By Benoît Chanclou
Exemples de design de microservices
en cours
- 312