From 8051f06417569882c47a9c19a05e667ffe59608a Mon Sep 17 00:00:00 2001 From: SoTrx <--> Date: Fri, 8 Jul 2022 17:09:43 +0200 Subject: [PATCH] [Lab2] Proofreading 03-05, 03-06, 03-07 and 03-08 --- instructions/_entries/03-05 monitoring.md | 38 +++++++------- instructions/_entries/03-06 secrets.md | 63 +++++++++++++---------- instructions/_entries/03-07 sdks.md | 6 +-- instructions/_entries/03-08 testing.md | 40 +++++++------- 4 files changed, 78 insertions(+), 69 deletions(-) diff --git a/instructions/_entries/03-05 monitoring.md b/instructions/_entries/03-05 monitoring.md index 322f82b..1c6beab 100644 --- a/instructions/_entries/03-05 monitoring.md +++ b/instructions/_entries/03-05 monitoring.md @@ -105,7 +105,7 @@ On remarquera aussi que les bindings ne sont pas représentés. En effet ceux-ci ### Observer les métriques -Un autre axe de l'observabilité est celui des métriques des conteneurs. Ces métriques sont des statistiques généralistes qui permettent d'avoir une vue opérationelle sur le cluster. +Un autre axe de l'observabilité est celui des "métriques" des conteneurs. Ces métriques sont des statistiques généralistes qui permettent d'avoir une vue opérationelle sur le cluster. Ces statistiques contiennent notamment : @@ -116,11 +116,11 @@ Ces statistiques contiennent notamment : - Etats des composants - Statistiques des appels HTTP/gRPC -La liste complète des métriques envoyées par chaque composant de Dapr est disponible [ici](https://github.com/dapr/dapr/blob/master/docs/development/dapr-metrics.md) +La liste complète des métriques envoyées par chaque service de Dapr est disponible [ici](https://github.com/dapr/dapr/blob/master/docs/development/dapr-metrics.md) -Toutes ces métriques sont émises dans des formats ouverts et peuvent être récupérées et analysées par des outils dédiées tels que [Azure Monitor](https://azure.microsoft.com/fr-fr/services/monitor/#overview), ou [Prometheus](https://prometheus.io). +Toutes ces métriques sont émises dans [un format ouvert](https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md) et peuvent être récupérées et analysées par des outils dédiées tels que [Azure Monitor](https://azure.microsoft.com/fr-fr/services/monitor/#overview), ou [Prometheus](https://prometheus.io). -[Chaque release](https://github.com/dapr/dapr/releases) de Dapr propose également des dashboards [Grafana](https://grafana.com/) permettant d'avoir un récapitulatif graphique des métriques collectées. +[Chaque release](https://github.com/dapr/dapr/releases) de Dapr propose également des dashboards [Grafana](https://grafana.com/) préconçus permettants d'avoir un récapitulatif graphique des métriques collectées. ![grafana dapr doc](/media/lab2/metrics/grafana-doc-example.png) @@ -128,36 +128,36 @@ Un guide est disponible [sur la documentation](https://docs.dapr.io/operations/m #### En application (Facultatif) -> **Important** : Cette section va montrer comment obtenir certaines métriques sur notre exemple fil rouge. Il faut cependant noter que les dashboards grafana fournis par l'équipe Dapr sont conçus pour Kubernetes, certaines métriques ne seront pas disponibles. +> **Important** : Cette section se concentrera sur l'obtention de certaines métriques sur l'exemple fil rouge. Il faut cependant noter que les dashboards grafana fournis par l'équipe Dapr sont conçus pour Kubernetes, certaines métriques ne seront pas disponibles. Pour obtenir les métriques de notre application, nous allons donc avoir besoin de rajouter deux services à notre déploiement : Prometheus et Grafana. -Prometheus est un outil d'analyse de séries temporelles (variables variant au cours du temps). Il permet de récupérer de plusieurs sources HTTP des informations et de les aggréger, proposant même un système d'alertes. +Prometheus est un outil d'analyse de séries temporelles (~= variables évoluants sur un axe de temps). Il permet de récupérer et d'aggréger des informations de *n* sources HTTP. -Grafana est un outil de visualisation souvent utilisé en conjonction de Prometheus. Il est capable de créer des _dashboards_ à partir de pluseiurs sources de données, donnant alors une visualisation fine des données à l'utilisateur. +Grafana est un outil de visualisation souvent utilisé en conjonction de Prometheus. Il est capable de créer des _dashboards_ à partir de plusieurs sources de données, offrant alors une visualisation fine des données à l'utilisateur. > **En pratique**: Déployez l'application spécifiée par `src/Lab2/5-metrics/docker-compose.yml`. Naviguez maintenant vers Grafana à l'adresse **localhost:9417**, puis choississez le _dashboard_ "dapr-sidecar-dashboard" dans _Dashboards -> Browse_. Qu'observez-vous ? -**Indication** : Il vous faudra sûrement réduire la fenêtre d'observation à 5 minutes pour voir une évolution dans les graphiques, ainsi que de lancer quelques commandes +**Indication** : Il vous faudra sûrement réduire la fenêtre d'observation à 5 minutes pour voir une évolution dans les graphiques, ainsi que de lancer quelques commandes de Charentaises Solution: {% collapsible %} ![sample grafana result](/media/lab2/metrics/sample-grafana-result.png) -On observe que les métriques présente sont celles des latences et des composants. +On observe que les métriques présentes sont celles des latences et des composants. -L'utilisation CPU/RAM n'est elle pas renseignée pour cet exemple. En effet, ces données sont extrapolées à partir des données des [métriques Kubernetes](https://github.com/kubernetes/kubernetes/blob/master/test/instrumentation/testdata/stable-metrics-list.yaml), qui ne sont pas présentes ici pour des raisons évidentes. +L'utilisation CPU/RAM n'est elle pas renseignée pour cet exemple. En effet, ces données sont extrapolées à partir des [métriques Kubernetes](https://github.com/kubernetes/kubernetes/blob/master/test/instrumentation/testdata/stable-metrics-list.yaml), qui ne sont pas présentes dans un contexte docker-compose {% endcollapsible %} ##### Par curiosité : Quelques détails sur Prometheus et docker-compose -Le déploiement de cette section n'est pas expliqué, seulement exécuté. La raison est que faire fonctionner Prometheus avec Dapr sur docker-compose demande d'utiliser une configuration qui n'a pas vraiment d'intérêt dans un scénario de production. +Le déploiement de cette section n'est pas expliqué à proprement parler, seulement exécuté. La raison à cela est que faire fonctionner Prometheus avec Dapr sur docker-compose demande d'utiliser une configuration particulière qui n'a pas sa place dans un scénario de production. -En effet, les métriques de Dapr sont émises par chaque sidecar sur leur port 9090 (par défaut). -Dans une utilisation sur Kubernetes ou sans orchestrateur, chaque sidecar émettrait sur le même endpoint sur le port 9090. Il n'y aurait plus qu'alors qu'à renseigner ce endpoint dans Prometheus. +En effet, les métriques de Dapr sont émises par chaque sidecar sur leur port respectif 9090 (par défaut). +Dans le contexte d'une utilisation sur Kubernetes ou sans orchestrateur, chaque sidecar émettrait sur le même endpoint sur le port 9090. Il n'y aurait plus qu'alors qu'à renseigner ce endpoint dans Prometheus. -Cependant, la gestion des [docker networks](https://docs.docker.com/network/) dans docker-compose ne permet pas à chaque sidecar d'émettre sur le même endpoint. Afin de restaurer le fonctionnement, il faut alors lister chacun des services dans la configuration de Prometheus. +Cependant, la gestion des [docker networks](https://docs.docker.com/network/) dans docker-compose ne permet pas à chaque sidecar d'émettre sur le même endpoint. Afin de retrouver le comportement voulu, il faut alors lister explicitement chacun des services dans la configuration de Prometheus. ```yml global: @@ -176,7 +176,7 @@ scrape_configs: ] ``` -De plus, si ce sont bien les sidecars qui émettent les métriques, ces sidecars partagent une interface avec leur service. Il faut donc donc exposer le port 9090 du service qui permettra d'accéder à ce port sur le sidecar. +De plus, chaque couple (service, sidecar) partage une même interface réseau, il faut donc de manière assez contre-intuitive exposer le port 9090 du service pour atteindre ce même port sur le sidecar. ```diff order-processing: @@ -192,7 +192,7 @@ De plus, si ce sont bien les sidecars qui émettent les métriques, ces sidecars network_mode: "service:order-processing" ``` -Une fois Prometheus configuré il suffit de configurer Grafana pour utiliser Prometheus de cette manière +Une fois Prometheus configuré, Graphana lui ne pose pas de problème particulier. ```ini [auth] @@ -208,11 +208,11 @@ org_role = Admin ### Observer les logs -Le dernier axe de l'observabilité que nous allons aborder est celui des logs. La possibilité de stocker et d'analyser les logs est une partie intégrante de la vie d'une application distribuée – peut être même encore plus que les parties précédentes – et il est courant que chacun ait déjà une solution plus ou moins managée avec laquelle il est familier. +Le dernier axe de l'observabilité que nous allons aborder est celui des logs. La possibilité de stocker et d'analyser les logs est une partie intégrante de la vie d'une application distribuée – peut être même encore plus que les parties précédentes – et il est courant que chaque développeur ait déjà une solution plus ou moins managée avec laquelle il est familier. Il n'est donc pas question ici de discuter de la manière dont les logs des services en eux-mêmes sont traités, cette partie va plutôt se concentrer seulement sur **les logs des sidecars**. -Le support utilisé sera une pile ELK (Elastisearch, Logstash, Kibana). +Le support utilisé pour cet exemple sera une pile ELK (Elasticsearch, Logstash, Kibana). Ce n'est cependant pas la seule solution supportée par Dapr. > **En pratique**: Déployez l'application spécifiée par `src/Lab2/6-logs/docker-compose.yml`. Naviguez maintenant vers Kibana à l'adresse **localhost:5601** @@ -243,7 +243,7 @@ Par rapport au format de Dapr, il y a de nombreuses variables supplémentaires. Il suffit maintenant pour consulter les logs de cliquer à nouveau sur **☰** puis de cliquer sur _Discover_ dans la section _Analytics_. -**Remarque** : On remarque des doublons dans les attributs, suffixés par ".keyword". Il s'aggit d'une spécificité de Elastisearch. Lors de la rencontre d'une chaîne de charactères, Elastisearch va l'indexer à la fois en tant que type _TEXT_, champ dans lequel il est possible de rechercher un sous-texte, et en tant que type _KEYWORD_, non indexé. Il est cependant possible de spécifier quel comportement à adopter pour chaque champ. +**Remarque** : On remarque des doublons dans les attributs, suffixés par ".keyword". Il s'aggit d'une spécificité de Elasticsearch : Lors de la rencontre d'une chaîne de charactères, Elasticsearch va l'indexer à la fois en tant que type _TEXT_, champ dans lequel il est possible de rechercher un sous-texte, et en tant que type _KEYWORD_, non indexé. Il est cependant possible de spécifier quel comportement adopter pour chacun des champs. > **En pratique** : Isolez les logs du conteneur **order-processing**. Commentez les attributs diff --git a/instructions/_entries/03-06 secrets.md b/instructions/_entries/03-06 secrets.md index fe67765..1c76a00 100644 --- a/instructions/_entries/03-06 secrets.md +++ b/instructions/_entries/03-06 secrets.md @@ -5,23 +5,24 @@ title: La gestion des secrets parent-id: lab-2 --- -Dans tous les scénarios que nous avons vu jusque là, nous avons +Dans tous les scénarios que nous avons vu jusque là, nous avons par simplicité utilisé des services sans aucune forme d'authentification. +Dans un scénario de production, il sera néanmoins essentiel de s'adonner à une bonne gestion des secrets. ### Généralités -> **Question généraliste** : Qu'est-ce qu'un coffre fort numérique (ou gestionnaire de secrets) ? Quel est l'avatange de stocker des secrets dans ce coffre au lieu de les renseigner directement dans l'environnement des services ? +> **Question généraliste** : Qu'est-ce qu'un coffre fort numérique (ou gestionnaire de secrets) ? Quel est l'avatange de stocker des secrets dans ce coffre en lieu et place de les renseigner directement dans l'environnement des services ? Solution : {% collapsible %} -Un gestionnaire de secrets est un service centralisation la creation/récupération/suppression des secrets d'une application distribuée. +Un gestionnaire de secrets est un service centralisant la creation/récupération/suppression des secrets d'une application distribuée. -Bien qu'ajoutant une indirection supplémentaire, cette solution a de nombreux avantages comme : +Bien qu'ajoutant une indirection supplémentaire, cette solution présente des avantages indispensables comme : - Empêcher la duplication d'un secret utilisé plusieurs fois -- Permettre une authentification/autorisation, contrôlant quels services accèdent à quels secrets -- Garder une trace des accès, permettant des audits de sécurité +- Permettre une forme d'authentification/autorisation, contrôlant quels services accèdent à quels secrets +- Garder une trace des accès, facilitant les audits de sécurité {% endcollapsible %} @@ -48,23 +49,23 @@ D'après [la documentation](https://docs.dapr.io/reference/components-reference/ | GCP Parameter Store | Alpha | Externe | Oui. Attention à la maturité du composant | | Azure Key Vault | Stable | Externe | Oui | -De manière générale, il sera toujours préférable de stocker des secrets en dehors de la plateforme d'exécution des services, pour ne pas placer tous ses oeufs dans le même panier. Dans le cas où le gestionnaire de secret est hébergée dans la même plateforme que les services, il faudra prévoir une haute fiabilité (mode cluster, persistence, sauvegardes...). +De manière générale, il sera toujours préférable de stocker les secrets en dehors de la plateforme d'exécution des services, pour ne pas "placer tous ses oeufs dans le même panier". Dans le cas où le gestionnaire de secret est hébergé sur la même plateforme que les services, il faudra prêter attention à la fiabilité de cette partie ultra critique (mode cluster, persistence, sauvegardes...). {% endcollapsible %} -> **Question** : Quelles sont les deux entités capables de demander la valeur d'un secret ? +> **Question** : Quels sont les deux moyens pour accéder au gestionnaire de secrets à travers Dapr ? Solution : {% collapsible %} -La page de documentation présente deux moyens de récupérer des secrets stockés après avoir déclaré le composant correspondant au coffre fort: +La page de documentation présente deux moyens d'accéder au gestionnaire de secrets à travers Dapr: - Utiliser l'API REST / les SDKs de Dapr depuis les **services** eux-mêmes - Utiliser des références aux secrets depuis les **composants** déclarés #### Depuis les services -Depuis le code des services, il est possible de demander la valeur d'un secret en utilisant une simple requête +Depuis le code des services, il suffit d'utiliser l'API correspondante : ```curl GET/POST http://localhost:3500/v1.0/secrets// @@ -72,17 +73,18 @@ GET/POST http://localhost:3500/v1.0/secrets// où: -- **\** : Nom du composant de gestion de secrets Dapr -- **\** : Clef du secret stocké +- **\** : Nom du composant de gestion de secrets +- **\** : Clef / Namespace (en fonction du stockage sous-jacent) du secret stocké #### Depuis les composants -```yml +L'autre manière est de modifier les composants Dapr existant pour y intégrer des références au gestionnaire de secret. + +```diff apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: statestore - namespace: default spec: type: state.redis version: v1 @@ -90,11 +92,14 @@ spec: - name: redisHost value: localhost:6379 - name: redisPassword - secretKeyRef: - name: redis-secret - key: redis-password -auth: - secretStore: + # Au lieu d'utiliser une valeur +- value: "" + # Une référence est passée ++ secretKeyRef: ++ name: ++ key: ++auth: ++ secretStore: ``` @@ -107,6 +112,7 @@ Solution : {% collapsible %} Il faudrait simplement appliquer cette configuration (voir partie monitoring) au service **secret-1**. + ```yml apiVersion: dapr.io/v1alpha1 kind: Configuration @@ -122,14 +128,14 @@ spec: Il faut cependant noter les autres services auraient accès à l'ensemble des secrets, ce qui pourrait poser problème. -Une autre configuration possible dans ce cas serait d'appliquer une configuration à tous les services qui par défaut refuse l'accès à tous les secrets. De manière analogue au fonctionnement d'un pare-feu, il faudrait ensuite explicitement autoriser chaque service à accéder à chaque secret. +Une autre configuration possible dans ce cas serait d'appliquer une configuration à tous les services qui par défaut refuse l'accès à tous les secrets. De manière analogue au fonctionnement d'un pare-feu, il faudrait ensuite explicitement autoriser chaque service à accéder à chaque secret. {% endcollapsible %} ### En application L'application fil rouge continue alors à évoluer. Cette fois-ci, l'instance de Redis servant à la communication entre `command-api` et `order-processing` a été modifiée pour nécessiter un mot de passe : **suchStrongP4ssword!!** -Un nouveau service a également été ajouté dans l'application : un [Vault d'HashiCorp](https://www.vaultproject.io/). Ce coffre fort a été initialisé (en mode de développement) comme suit : +Un nouveau service a également été ajouté dans l'application : un [Vault d'HashiCorp](https://www.vaultproject.io/). Ce coffre fort a été initialisé (en [mode de développement](https://www.vaultproject.io/docs/concepts/dev-server)) comme suit : | Namespace | Valeur | | --------- | ------------------------------- | @@ -145,9 +151,9 @@ Solution : {% collapsible %} -Le coffre fort utilisé étant un Vault d'HashiCorp, il faut utiliser le [composant correspondant](https://docs.dapr.io/reference/components-reference/supported-secret-stores/hashicorp-vault/). +Le coffre fort utilisé étant un Vault d'HashiCorp, il faut utiliser le [composant Dapr correspondant](https://docs.dapr.io/reference/components-reference/supported-secret-stores/hashicorp-vault/). -Ce composant dispose d'un grand nombre de paramètres; mais très peu sont en fait requis pour le déploiement très simple qui est utilisé ici. +Ce composant dispose d'un grand nombre de paramètres. Cependant, le déploiement du Vault dans ce cas étant très simple, seulement trois paramètres sont réellement requis. Le composant à créer est donc : @@ -177,7 +183,9 @@ spec: Le composant étant créé, il est possible de récupérer les secrets des deux manières que nous avons abordées plus haut. -> **En pratique**: Modifiez le composant `pubsub.yml` pour inclure la récupération du mot de passe depuis le composant de gestion de secret. Verfiez le fonctionnement en exécutant l'application située à `src/Lab2/7-secrets/docker-compose.yml` +> **En pratique**: Modifiez le composant `pubsub.yml` pour inclure la récupération du mot de passe depuis le composant de gestion de secret. Vérifiez le fonctionnement en exécutant l'application située à `src/Lab2/7-secrets/docker-compose.yml` + +**Indication** : En cas d'échec de récupération du mot de passe de l'instance de Redis, certains services vont simplement crasher. Solution : @@ -205,15 +213,14 @@ spec: auth: secretStore: vault ``` - {% endcollapsible %} ### Conclusion La gestion des secrets est une facette si essentielle de la vie d'une application distribuée qu'elle doit être incluse dès sa conception. -Dans cet exemple, nous utilisons un gestionnaire de secret directement intégré dans l'application, via un Vault. Si cette configuration est amplement suffisante dans le cadre d'un exercice, elle n'est évidemment pas conseillée en production. +Dans cet exemple, nous utilisons un gestionnaire de secret directement intégré dans l'application, via un Vault. Si cette configuration est amplement suffisante dans le cadre d'un exercice, elle n'est évidemment pas conseillée sous cette forme en production. -Dans une configuration de production entièrement privée, il faudrait ainsi prévoir une persistance pour le secret et une meilleure sécurité pour l'accès. +Dans une configuration de production entièrement privée, il faudrait ainsi prévoir une couche de persistance pour le gestionnaire de secret et une meilleure sécurité d'accès. -Dans une configuration utilisant le Cloud public, il sera plus conseillé d'utiliser un service managé, comme par exemple Azure Keyvault. +Dans une configuration utilisant le Cloud public, il sera en revanche plus conseillé de se tourner vers un service managé, comme par exemple [Azure Keyvault](https://azure.microsoft.com/fr-fr/services/key-vault/). diff --git a/instructions/_entries/03-07 sdks.md b/instructions/_entries/03-07 sdks.md index 40c6cc6..4905474 100644 --- a/instructions/_entries/03-07 sdks.md +++ b/instructions/_entries/03-07 sdks.md @@ -5,7 +5,7 @@ title: Les SDKs parent-id: lab-2 --- -Jusqu'ici, nous nous sommes concentrés sur l'utilisation de l'API REST fournie par Dapr. En plus de ne pas dépendre d'un langage de programmation particulier, c'est également un excellent moyen de comprendre le fonctionnement du logiciel. +Jusqu'ici, nous nous sommes concentrés sur l'utilisation de l'API REST fournie par Dapr. En plus de ne pas dépendre d'un langage de programmation particulier, c'est également un excellent moyen de comprendre l'articulation du logiciel. Cependant, dans des déploiement réels, n'utiliser que du HTTP rend le développeur responsable de la maintenance du *wrapper* HTTP écrit, ce qui peut mener à certaine dette technique. Pour pallier ce problème, il existe donc des [SDKs](https://docs.dapr.io/developing-applications/sdks/), propres à chaque langage. @@ -20,7 +20,7 @@ Les langages supportés sont : - [C++](https://github.com/dapr/cpp-sdk) (en Alpha, 07/2022) - [Rust](https://github.com/dapr/rust-sdk) (en Alpha, 07/2022) -S'il n'est pas vraiment utile de détailler chaque SDK, il faut néanmoins remarquer **qu'ils suivent la même convention de conception.** +S'il n'est pas vraiment utile de détailler chaque SDK, il faut néanmoins remarquer **qu'ils sont conçus avec une convention unifiée**. On retrouvera donc toujours : @@ -48,4 +48,4 @@ ctx := context.Background() state, _ := client.GetState(ctx, "statestore", "") ``` -> **Note** : Comme indiqué [ici](https://docs.dapr.io/developing-applications/sdks/sdk-serialization/), les SDKs de Dapr sérialiseront les données avec un serialisateur JSON. Par conséquent, tout objet envoyé doit pouvoir être converti dans l'un des [types supportés par le JSON](https://www.w3schools.com/js/js_json_datatypes.asp). Il ne serait donc par exemple pas possible (ni souhaitable) de passer des fonctions par les SDKs. +> **Note** : Comme indiqué [ici](https://docs.dapr.io/developing-applications/sdks/sdk-serialization/), les SDKs de Dapr sérialiseront par défaut les données en JSON. Par conséquent, tout objet envoyé doit pouvoir être converti dans l'un des [types supportés par le JSON](https://www.w3schools.com/js/js_json_datatypes.asp). Il ne serait donc par exemple pas possible (ni souhaitable) de passer des fonctions par les SDKs. diff --git a/instructions/_entries/03-08 testing.md b/instructions/_entries/03-08 testing.md index 7fcb244..3bdbec0 100644 --- a/instructions/_entries/03-08 testing.md +++ b/instructions/_entries/03-08 testing.md @@ -7,15 +7,15 @@ parent-id: lab-2 ## Préambule -Cette partie du laboratoire va s'intéresser au cycle de développement d'une application. Par conséquent elle sera moins accessible aux personnes n'ayant pas ou peu d'expérience dans ce domaine. Ce sujet est donc **facultatif** est peut être passé en faveur du prochain laboratoire. +Cette partie du laboratoire va s'intéresser à la phase de test du cycle de développement d'une application. Par conséquent elle concernera un public plus restreint, celui ayant déjà une expérience dans le domaine. Ce sujet est donc entièrement **facultatif** est peut être passé en faveur du prochain laboratoire. -Pour commencer, nous allons poser quelques définitions pour cette partie de l'exercices : +Pour commencer, un certain vocabulaire sera utilisé dans cette partie: -- Une **application** est une réponse partielle ou totale à un problème métier. Les différentes sous-parties du problème sont des **besoins**. L'ensemble des besoins auxquels répond une application est appelé **couverture fonctionelle**. -- Un **service** est une partie d'une application distribuée orientée (micro)services. Chaque service répond à une partie plus ou moins importante d'un besoin. -- Un **module** est ici défini comme une partie du code service étant séparé logiquement du reste de l'implémentation via une encapsulation (classe, package, injection...) +- Une **application** est une réponse partielle ou totale à un problème métier. Les différentes sous-parties du problème sont des **besoins**. L'ensemble des besoins auquel répond une application est appelé **couverture fonctionelle**. +- Un **service** est une partie d'une application distribuée orientée (micro)services. Chaque service répond à une partie plus ou moins importante d'un ou plusieurs besoin(s). +- Un **module/package** est ici défini comme une partie du code d'un service étant séparé logiquement du reste de l'implémentation via une encapsulation (classe, package, injection...) -**Que tester** +### Que tester Avec toutes les parties précédentes, nous avons pu voir que Dapr est un outil qui vient se greffer facilement sur une application en cours de développement. Il reste cependant une question en suspend. @@ -55,7 +55,7 @@ Parmi les types de tests que nous pourrons effectuer sur cette application nous - Ex: L'utilisateur doit pouvoir effectuer des opérations sur la calculatrice **Note**: Il existe _beaucoup_ d'autres types de tests (acceptation, performance, mutation, static, A/B, scripts...) qui répondent à des exigences plus particulières de certaines applications. -Le domaine des tests évolue contamment, et au cours du temps, certains types de tests sont devenus obsolètes avec des langages répondant par conception à des problèmes comme la fuite mémoire (garbage collector, scoped mallocs...) ou les [_deadlocks/livelocks_](https://en.wikipedia.org/wiki/Deadlock) ([borrow checker de Rust](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)). Le tout est d'utiliser les bons types de tests au bon momment. +Le domaine des tests évolue contamment, et au cours du temps, certains types de tests sont devenus obsolètes avec des langages répondant par leur conception même à des problèmes comme la fuite mémoire (garbage collector, scoped mallocs...) ou les [_deadlocks/livelocks_](https://en.wikipedia.org/wiki/Deadlock) ([borrow checker de Rust](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)). {% endcollapsible %} @@ -67,14 +67,15 @@ Les tests end2end et fonctionnels sont donc concernés. Les tests unitaires au contraire ne devraient pas avoir de dépendance externe. -Il est cependant plus difficile d'avoir une réponse catégorique pour les tests d'intégration. Si l'intégration inclue la communication entre services, il peut cepdenant être judicieux dans certains cas de se laisser la liberté ou non d'injecter le sidecar afin de tester un échec de communication. +Il est cependant plus difficile d'avoir une réponse catégorique pour les tests d'intégration. Si l'intégration inclue la communication entre services, il peut parfois être judicieux de se laisser la liberté ou non d'injecter le sidecar afin de tester un échec de communication. {% endcollapsible %} -## Comment tester +### Comment tester + Pour ce laboratoire, nous allons proposer trois méthodologies pour tester une application avec Dapr. -### Méthode 1: Dapr partout +#### Méthode 1: Le middleware obligatoire La première méthode est la plus simple. Une fonctionnalité de Dapr est de pouvoir fonctionner indépendament d'un orchestrateur. Dans cette optique, il est alors possible de simplement considérer Dapr comme un pré-requis pour les tests **d'intégration**. @@ -82,21 +83,21 @@ Le pipeline de CI serait alors initié par l'installation de Dapr dans l'environ Cette méthode, si elle a l'avantage de se pas demander de structure de test particulière, peut cependant contraindre dans certains cas (injection d'un SDK dans une classe, subscription à un evènement dans le constructeur...) à également devoir utiliser Dapr dans les test **unitaires**, ce qui n'est pas forcément souhaitable. -### Méthode 2: L'interface localhost +#### Méthode 2: L'interface localhost -Une autre méthode est de simplement remplacer les appels aux sidecars par des mocks. Le port par défaut de Dapr est **3500**. Avant d'effectuer une batterie de tests, il est alors possible de démarrer un serveur (type [APItest](https://apitest.dev/) en Go) sur ce port et de _mocker_ les réponses du sidecar. +Une autre méthode est de simplement remplacer les appels aux sidecars par des _mocks_. Le port par défaut de Dapr est **3500**. Avant d'effectuer une batterie de tests, il est alors possible de démarrer un serveur (type [APItest](https://apitest.dev/) en Go) sur ce port et de _mocker_ les réponses du sidecar. -Cette méthode a l'avantange de donner le contrôle au développeur des réponses du sidecar, permettant des tests plus vastes dans les cas limites. Elle ne structure pas non plus le développement de l'application et peut être appliquée dans tous les cas. +Cette méthode a l'avantange de donner au développeur le contrôle des réponses du sidecar, permettant une exploration plus vaste des cas limites. Elle ne structure pas non plus le développement de l'application et peut être appliquée dans tous les cas. Les inconvénients principaux de cette méthode est qu'il faut connaître le format de réponse du sidecar, et que le serveur de test nécessite une attention particulière pour ne pas grandir de manière incontrolée. -### Méthode 3: Injection de dépendances +#### Méthode 3: Injection de dépendances La dernière méthode est la plus complexe à mettre en place mais aussi celle qui donne le plus de contrôle au développeur. Le principe de cette méthode est de considérer Dapr comme une classe/module injectable d'un conteneur d'[injection de dépendances](https://fr.wikipedia.org/wiki/Injection_de_d%C3%A9pendances). -L'injection de dépendances est une méthode de programmation qui consiste à déterminer à l'exécution la chaîne de dépendance entre les objets/classes d'un programme. +L'injection de dépendances est une méthode de programmation qui consiste à déterminer à l'exécution la chaîne de dépendances entre les objets/classes d'un programme. Ainsi, ces dépendances sont reconfigurables en fonction de l'environnement d'exécution de l'application, permettant une meilleure flexibilité quand cette chaîne de dépendance est complexe. -Appliquée au domaine des tests, cette méthode est une solution au problème de tester en isolation des [classes composées](). +Appliquée au domaine des tests, cette méthode permet de tester en isolation des [classes composées](). Un exemple pourrait être le suivant : @@ -225,9 +226,10 @@ function getDynamicExternalStore(startValue?: IRecordingState) { } ``` - -Ayant l'avantage de permettre un contrôle total sur la relation entre Dapr et le reste du service, cette méthode est cepedant structurante, elle demande que l'application utilise l'injection de dépendances. +Ayant l'avantage de permettre un contrôle total sur la relation entre Dapr et le reste du service, cette méthode est cepedant entièrement structurante, elle impose que l'application utilise l'injection de dépendances. ## Conclusion -Il est relativement facile de tester avec Dapr. Ne posant aucun problèmes dans les tests fonctionnels ou end2end, il est cependant à la charge du développeur de déterminer une implémentation cohérente avec la granularité du contrôle voulu sur l'intéraction entre un service et son sidecar lors des tests unitaires ou d'intégration. \ No newline at end of file +Il est relativement facile de tester avec Dapr dans une configuration micro-services, où chaque service effectue une tâche très simple. + +Dans le cas où les services évoluent et leurs responsabilités augmentent, le développeur devra choisir une implémentation de tests en fonction de la granularité de contrôle voulu.