Retour aux microservices avec Istio. Partie 1



Remarque perev. : Les maillages de service sont définitivement devenus une solution pertinente dans l'infrastructure moderne pour les applications qui suivent l'architecture de microservice. Bien qu'Istio puisse être entendu par de nombreux ingénieurs DevOps, il s'agit d'un produit assez nouveau qui, étant complet en termes de fonctionnalités fournies, peut nécessiter un temps considérable pour se connaître. L'ingénieur allemand Rinor Maloku, responsable du cloud computing pour les grands clients de la société de télécommunications Orange Networks, a écrit une remarquable série de documents qui vous permettent de plonger rapidement et en profondeur dans Istio. Il commence son histoire par ce qu'Istio peut faire et comment vous pouvez le voir rapidement de vos propres yeux.

Istio est un projet Open Source développé en collaboration avec des équipes de Google, IBM et Lyft. Il résout les difficultés qui se posent dans les applications basées sur des microservices, par exemple, telles que:

  • Gestion du trafic : délais d'attente, tentatives, équilibrage de charge;
  • Sécurité : authentification et autorisation de l'utilisateur final;
  • Observabilité : trace, surveillance, diagraphie.

Tous peuvent être résolus au niveau de l'application, mais après cela, vos services cesseront d'être «micro». Tous les efforts supplémentaires pour résoudre ces problèmes sont un gaspillage supplémentaire des ressources de l'entreprise qui pourraient être utilisées directement pour les valeurs commerciales. Prenons un exemple:
Chef de projet: combien de temps pour ajouter des commentaires?
Développeur: Two sprints.

MP: Quoi? .. C'est juste CRUD!
R: La création de CRUD est une partie simple de la tâche, mais nous devons encore authentifier et autoriser les utilisateurs et les services. Étant donné que le réseau n'est pas fiable, vous devrez implémenter des demandes répétées, ainsi que le modèle de disjoncteur dans les clients. Pourtant, pour vous assurer que tout le système n'est pas tombé, vous aurez besoin de délais d'attente et de cloisons (pour plus de détails sur les deux modèles mentionnés, voir plus loin dans l'article - environ la traduction) , et afin de détecter les problèmes, la surveillance, le traçage, [...]

MP: Oh, alors insérons simplement cette fonctionnalité dans le service Produit.
Je pense que l'idée est claire: le volume des étapes et des efforts nécessaires pour ajouter un service est énorme. Dans cet article, nous verrons comment Istio élimine toutes les difficultés mentionnées ci-dessus (qui ne sont pas ciblées pour la logique métier) des services.



Remarque : Cet article suppose que vous avez une connaissance pratique de Kubernetes. Sinon, je vous recommande de lire mon introduction à Kubernetes et ce n'est qu'après cela de continuer à lire ce matériel.

Idea Istio


Dans un monde sans Istio, un service fait des requêtes directes à un autre, et en cas de panne, le service doit le traiter lui-même: refaire une tentative, prévoir un timeout, ouvrir un disjoncteur, etc.


Trafic réseau dans Kubernetes

Istio propose également une solution spécialisée, complètement distincte des services et fonctionnant en interférant avec l'interaction du réseau. Et donc il implémente:

  • Tolérance aux pannes : en fonction du code d'état dans la réponse, il comprend si la demande a échoué et l'exécute à nouveau.
  • Déploiements Canary : redirige vers la nouvelle version du service uniquement un pourcentage fixe du nombre de demandes.
  • Surveillance et métriques : combien de temps le service a-t-il répondu?
  • Traçage et observabilité : ajoute des en-têtes spéciaux à chaque demande et les trace dans le cluster.
  • Sécurité : extrait le jeton JWT, authentifie et autorise les utilisateurs.

Ce ne sont là que quelques-unes des possibilités (vraiment seulement quelques-unes!) De vous intriguer. Plongeons-nous maintenant dans les détails techniques!

Architecture Istio


Istio intercepte tout le trafic réseau et lui applique un ensemble de règles, en insérant un proxy intelligent dans chaque module sous la forme d'un sidecar-container. Les proxys qui activent toutes les fonctionnalités forment un plan de données et peuvent être configurés dynamiquement à l'aide du plan de contrôle .

Plan de données


Les proxys insérés dans les pods permettent à Istio de répondre facilement aux exigences dont nous avons besoin. Par exemple, vérifiez les fonctions de nouvelle tentative et de disjoncteur.


Comment les nouvelles tentatives et les coupures de circuit sont implémentées dans Envoy

Pour résumer:

  1. Envoy (parle d'un proxy dans un conteneur de sidecar qui est distribué en tant que produit séparé - environ Transl.) Envoie une demande à la première instance du service B et une défaillance se produit.
  2. L'envoyé Sidecar réessaye . (1)
  3. La demande ayant échoué est renvoyée au proxy qui l'a appelée.
  4. Cela ouvre le disjoncteur et appelle le service suivant pour les demandes suivantes. (2)

Cela signifie que vous n'avez pas à utiliser la prochaine bibliothèque Retry, vous n'avez pas à faire votre propre implémentation de Circuit Breaking and Service Discovery dans le langage de programmation X, Y ou Z. Tout cela et bien plus est disponible dès le départ dans Istio et ne nécessite aucune modification du code.

Super! Maintenant, vous voudrez peut-être partir en voyage avec Istio, mais il y a encore des doutes, des questions ouvertes. S'il s'agit d'une solution universelle pour toutes les occasions de la vie, alors vous avez un soupçon légitime: après tout, toutes ces décisions s'avèrent en réalité inadaptées à toute occasion.

Et enfin, vous demandez: "Est-il personnalisable?"

Vous êtes maintenant prêt pour un voyage en mer - et familiarisons-nous avec le plan de contrôle.

Avion de contrôle


Il se compose de trois composants: Pilot , Mixer et Citadel , qui travaillent ensemble pour configurer les Envoys pour acheminer le trafic, appliquer des politiques et collecter des données de télémétrie. Schématiquement, tout cela ressemble à ceci:


Interaction du plan de contrôle avec le plan de données

Les envoyés (c'est-à-dire le plan de données) sont configurés à l'aide de Kubernetes CRD (définitions de ressources personnalisées) définies par Istio et spécialement conçues à cet effet. Pour vous, cela signifie qu'ils semblent être la prochaine ressource de Kubernetes avec une syntaxe familière. Après sa création, cette ressource sera récupérée par le plan de contrôle et appliquée aux Envoyés.

Ratio de service pour Istio


Nous avons décrit l'attitude d'Istio envers les services, mais pas l'inverse: comment les services sont-ils liés à Istio?

Honnêtement, Istio connaît la présence des services ainsi que des poissons - de l'eau, quand ils se demandent: «Qu'est-ce que l'eau en général?».


Illustration de Victoria Dimitrakopoulos : - Comment aimez-vous l'eau? - Qu'est-ce que l'eau en général?

Ainsi, vous pouvez prendre un cluster fonctionnel et après le déploiement des composants Istio, les services qui y sont situés continueront de fonctionner, et après la suppression de ces composants, tout ira à nouveau correctement. Il est clair que ce faisant, vous perdrez les opportunités offertes par Istio.

Assez de théorie - mettons ces connaissances en pratique!

Istio en pratique


Istio nécessite un cluster Kubernetes dans lequel au moins 4 vCPU et 8 Go de RAM sont disponibles. Pour augmenter rapidement le cluster et suivre les instructions de l'article, je recommande d'utiliser la plate-forme Google Cloud, qui offre aux nouveaux utilisateurs gratuitement 300 $ .

Après avoir créé un cluster et configuré l'accès à Kubernetes via l'utilitaire de console, vous pouvez installer Istio via le gestionnaire de packages Helm.

Installation du casque


Installez le client Helm sur votre ordinateur, comme on dit dans la documentation officielle . Nous l'utiliserons pour générer des modèles pour l'installation d'Istio dans la section suivante.

Installer Istio


Téléchargez les ressources Istio à partir de la dernière version (le lien de l'auteur d'origine vers la version 1.0.5 est remplacé par celui actuel, c'est-à-dire 1.0.6 - environ la traduction) , extrayez le contenu dans un répertoire, que j'appellerai à l'avenir [istio-resources] .

Pour faciliter l'identification des ressources Istio, créez l'espace de noms istio-system dans le cluster K8s:

 $ kubectl create namespace istio-system 

Terminez l'installation en allant dans le [istio-resources] et en exécutant la commande:

 $ helm template install/kubernetes/helm/istio \ --set global.mtls.enabled=false \ --set tracing.enabled=true \ --set kiali.enabled=true \ --set grafana.enabled=true \ --namespace istio-system > istio.yaml 

Cette commande affichera les composants clés d'Istio dans le fichier istio.yaml . Nous avons changé le modèle standard pour nous-mêmes, en spécifiant les paramètres suivants:

  • global.mtls.enabled défini sur false (c'est-à-dire que l'authentification mTLS est désactivée - environ la traduction) pour simplifier notre processus de datation;
  • tracing.enabled active le traçage des requêtes à l'aide de Jaeger;
  • kiali.enabled installe Kiali dans un cluster pour visualiser les services et le trafic;
  • grafana.enabled définit Grafana pour visualiser les métriques collectées.

Nous appliquons les ressources générées avec la commande:

 $ kubectl apply -f istio.yaml 

L'installation d'Istio dans le cluster est terminée! Attendez que tous les pods de l'espace de noms istio-system soient en Running ou Completed en exécutant la commande ci-dessous:

 $ kubectl get pods -n istio-system 

Maintenant, nous sommes prêts à continuer dans la section suivante, où nous lèverons et lancerons l'application.

Architecture d'application de l'analyse des sentiments


Prenons un exemple de l'application de microservice Sentiment Analysis utilisée dans l' article d'introduction déjà mentionné dans Kubernetes . Il est suffisamment sophistiqué pour montrer les capacités d'Istio dans la pratique.

L'application se compose de quatre microservices:

  1. Service SA-Frontend , qui sert des applications frontales sur Reactjs;
  2. Un service SA-WebApp qui sert les demandes d'analyse de sentiment;
  3. Service SA-Logic , qui effectue une analyse sentimentale ;
  4. Service SA-Feedback , qui reçoit les commentaires des utilisateurs sur la précision de l'analyse.



Dans ce diagramme, en plus des services, nous voyons également le contrôleur d'entrée, qui dans Kubernetes achemine les demandes entrantes vers les services correspondants. Istio utilise un concept similaire dans la passerelle d'entrée, dont les détails suivront.

Lancement d'une application avec un proxy depuis Istio


Pour les autres opérations mentionnées dans l'article, clonez le référentiel istio-mastery . Il contient l'application et les manifestes pour Kubernetes et Istio.

Insert Sidecar


L'insertion peut se faire automatiquement ou manuellement . Pour insérer automatiquement des conteneurs sidecar, vous devez définir l' istio-injection=enabled sur l' istio-injection=enabled , ce qui se fait par la commande suivante:

 $ kubectl label namespace default istio-injection=enabled namespace/default labeled 

Désormais, chaque pod qui sera déployé dans l'espace de noms par défaut recevra son conteneur side-car. Pour vérifier cela, installons une application de test en allant dans le répertoire racine du [istio-mastery] et en exécutant la commande suivante:

 $ kubectl apply -f resource-manifests/kube persistentvolumeclaim/sqlite-pvc created deployment.extensions/sa-feedback created service/sa-feedback created deployment.extensions/sa-frontend created service/sa-frontend created deployment.extensions/sa-logic created service/sa-logic created deployment.extensions/sa-web-app created service/sa-web-app created 

Après avoir étendu les services, nous vérifierons que les pods ont deux conteneurs (avec le service lui-même et son side-car), en exécutant la commande kubectl get pods et en nous assurant que la valeur 2/2 indiquée sous la colonne READY , symbolisant que les deux conteneurs sont en cours d'exécution:

 $ kubectl get pods NAME READY STATUS RESTARTS AGE sa-feedback-55f5dc4d9c-c9wfv 2/2 Running 0 12m sa-frontend-558f8986-hhkj9 2/2 Running 0 12m sa-logic-568498cb4d-2sjwj 2/2 Running 0 12m sa-logic-568498cb4d-p4f8c 2/2 Running 0 12m sa-web-app-599cf47c7c-s7cvd 2/2 Running 0 12m 

Visuellement, cela ressemble à ceci:


Envoyé par procuration dans l'un des pods

Maintenant que l'application est opérationnelle, nous devons autoriser le trafic entrant à entrer dans l'application.

Passerelle d'entrée


La meilleure pratique pour y parvenir (pour autoriser le trafic dans le cluster) consiste à passer par la passerelle d'entrée à Istio, qui est située à la «frontière» du cluster et vous permet d'activer les fonctionnalités Istio telles que le routage, l'équilibrage de charge, la sécurité et la surveillance du trafic entrant.

Le composant Ingress Gateway et le service qui le transfère à l'extérieur ont été installés dans le cluster lors de l'installation d'Istio. Pour connaître l'adresse IP externe d'un service, procédez comme suit:

 $ kubectl get svc -n istio-system -l istio=ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP istio-ingressgateway LoadBalancer 10.0.132.127 13.93.30.120 

Nous continuerons à accéder à l'application sur cette IP (je vais l'appeler EXTERNAL-IP), donc pour plus de commodité, nous allons écrire la valeur dans une variable:

 $ EXTERNAL_IP=$(kubectl get svc -n istio-system \ -l app=istio-ingressgateway \ -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') 

Si vous essayez d'accéder à cette adresse IP via un navigateur maintenant, vous recevrez une erreur Service non disponible, car Par défaut, Istio bloque tout le trafic entrant jusqu'à ce qu'une passerelle soit définie.

Ressource de passerelle


La passerelle est un CRD (définition de ressource personnalisée) dans Kubernetes, défini après l'installation d'Istio dans un cluster et l'activation de la capacité de spécifier les ports, le protocole et les hôtes pour lesquels nous voulons autoriser le trafic entrant.

Dans notre cas, nous voulons autoriser le trafic HTTP vers le port 80 pour tous les hôtes. La tâche est implémentée par la définition suivante ( http-gateway.yaml ) :

 apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: http-gateway spec: selector: istio: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" 

Cette configuration n'a besoin d'aucune explication à l'exception du istio: ingressgateway . Avec ce sélecteur, nous pouvons indiquer à quelle passerelle d'entrée la configuration est appliquée. Dans notre cas, il s'agit du contrôleur Ingress Gateway, qui a été installé par défaut dans Istio.

La configuration est appliquée en appelant la commande suivante:

 $ kubectl apply -f resource-manifests/istio/http-gateway.yaml gateway.networking.istio.io/http-gateway created 

Maintenant, la passerelle permet d'accéder au port 80, mais n'a aucune idée où acheminer les demandes. Cela nécessitera des services virtuels .

Ressource VirtualService


VirtualService indique à Ingress Gateway comment acheminer les demandes autorisées dans le cluster.

Les demandes à notre application via la passerelle http doivent être envoyées aux services sa-frontend, sa-web-app et sa-feedback:


Itinéraires à configurer avec VirtualServices

Tenez compte des demandes qui doivent être envoyées à SA-Frontend:

  • Une correspondance exacte sur le chemin / doit être envoyée à SA-Frontend pour obtenir index.html;
  • Les chemins préfixés avec /static/* doivent être envoyés à SA-Frontend pour recevoir les fichiers statiques utilisés dans le frontend, tels que CSS et JavaScript;
  • Les chemins qui relèvent de l'expression régulière '^.*\.(ico|png|jpg)$' doivent être envoyés à SA-Frontend, car Ce sont les images affichées sur la page.

L'implémentation est réalisée par la configuration suivante ( sa-virtualservice-external.yaml ):

 kind: VirtualService metadata: name: sa-external-services spec: hosts: - "*" gateways: - http-gateway # 1 http: - match: - uri: exact: / - uri: exact: /callback - uri: prefix: /static - uri: regex: '^.*\.(ico|png|jpg)$' route: - destination: host: sa-frontend # 2 port: number: 80 

Points importants:

  1. Ce VirtualService fait référence aux demandes provenant de la passerelle http ;
  2. destination définit le service auquel les demandes sont envoyées.

Remarque : La configuration ci-dessus est stockée dans le fichier sa-virtualservice-external.yaml , qui contient également les paramètres de routage dans SA-WebApp et SA-Feedback, mais a été raccourci ici dans l'article par souci de concision.

Appliquez VirtualService en appelant:

 $ kubectl apply -f resource-manifests/istio/sa-virtualservice-external.yaml virtualservice.networking.istio.io/sa-external-services created 

Remarque : Lorsque nous utilisons des ressources Istio, le serveur API Kubernetes déclenche un événement qui reçoit le plan de contrôle Istio, puis la nouvelle configuration est appliquée aux proxys Envoy de chaque module. Et le contrôleur Ingress Gateway semble être le prochain Envoy configuré dans Control Plane. Tout cela sur le diagramme ressemble à ceci:


Configuration Istio-IngressGateway pour le routage des requêtes

L'analyse des sentiments est disponible sur http://{EXTERNAL-IP}/ . Ne vous inquiétez pas si vous obtenez le statut Introuvable: il faut parfois un peu plus de temps pour que la configuration prenne effet et les caches Envoy soient mis à jour .

Avant de continuer, travaillez un peu avec l'application pour générer du trafic (sa présence est nécessaire pour plus de clarté dans les prochaines étapes - environ Transl.) .

Kiali: observabilité


Pour accéder à l'interface d'administration de Kiali, exécutez la commande suivante:

 $ kubectl port-forward \ $(kubectl get pod -n istio-system -l app=kiali \ -o jsonpath='{.items[0].metadata.name}') \ -n istio-system 20001 

... et ouvrez http: // localhost: 20001 / , en vous connectant en tant qu'admin / admin. Vous trouverez ici de nombreuses fonctionnalités utiles, par exemple, pour vérifier la configuration des composants Istio, visualiser les services en fonction des informations collectées lors de l'interception des demandes réseau et recevoir des réponses aux questions «Qui contacte qui?», «Quelle version du service plante?» etc. En général, explorez les possibilités de Kiali avant de passer à la visualisation des métriques avec Grafana.



Grafana: visualisation des métriques


Les métriques collectées dans Istio entrent dans Prométhée et visualisées avec Grafana. Pour accéder à l'interface d'administration de Grafana, exécutez la commande ci-dessous, puis ouvrez http: // localhost: 3000 / :

 $ kubectl -n istio-system port-forward \ $(kubectl -n istio-system get pod -l app=grafana \ -o jsonpath={.items[0].metadata.name}) 3000 

En cliquant sur le menu Accueil en haut à gauche et en sélectionnant Istio Service Dashboard dans le coin supérieur gauche, commencez par le service sa-web-app pour consulter les métriques collectées:



Ici, nous attendons une performance vide et complètement ennuyeuse - la direction ne l'approuvera jamais. Créons une petite charge avec la commande suivante:

 $ while true; do \ curl -i http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}'; \ sleep .8; done 

Nous avons maintenant des graphiques beaucoup plus agréables, et en plus d'eux, de merveilleux outils Prometheus pour la surveillance et Grafana pour la visualisation des métriques, qui nous permettront d'en savoir plus sur les performances, l'état de santé, les améliorations / la dégradation des services au fil du temps.

Enfin, regardons la trace des demandes dans les services.

Jaeger: trace


Nous aurons besoin de recherches, car plus nous avons de services, plus il est difficile de trouver la cause de l'échec. Regardons un cas simple de l'image ci-dessous:


Un exemple typique d'une demande échouée au hasard

La demande vient, tombe - quelle est la raison? Premier service? Ou le second? Il y a des exceptions dans les deux - regardons les journaux de chacun. À quelle fréquence vous trouvez-vous en train de faire cela? Notre travail ressemble plus à des détectives de logiciels qu'à des développeurs ...

Il s'agit d'un problème répandu dans les microservices et il est résolu par des systèmes de trace distribués dans lesquels les services se transmettent un en-tête unique, après quoi ces informations sont redirigées vers le système de trace, où elles sont mappées aux données de demande. En voici une illustration:


TraceId est utilisé pour identifier la demande.

Istio utilise Jaeger Tracer, qui implémente une infrastructure API OpenTracing indépendante du fournisseur. Vous pouvez accéder à l'interface utilisateur Jaeger avec la commande suivante:

 $ kubectl port-forward -n istio-system \ $(kubectl get pod -n istio-system -l app=jaeger \ -o jsonpath='{.items[0].metadata.name}') 16686 

Allez maintenant sur http: // localhost: 16686 / et sélectionnez le service sa-web-app . Si le service n'est pas affiché dans le menu déroulant, affichez / générez l'activité sur la page et mettez à jour l'interface. Après cela, cliquez sur le bouton Rechercher les traces , qui affichera les dernières traces - sélectionnez-en une - des informations détaillées sur toutes les traces apparaîtront:



Cette trace montre:

  1. La demande est envoyée à istio-ingressgateway (il s'agit de la première interaction avec l'un des services, et l'ID de trace est généré pour la demande), après quoi la passerelle envoie la demande au service sa-web-app .
  2. Dans le service sa-web-app, la demande est récupérée par Envoy sidecar, un «enfant» est créé dans la plage (donc nous le voyons dans les traces) et redirigé vers le conteneur sa-web-app . (La portée est une unité de travail logique dans Jaeger qui a un nom, l'heure de début de l'opération et sa durée. Les portées peuvent être imbriquées et ordonnées. Un graphique acyclique dirigé à partir des portées forme une trace. - Env. Transl.)
  3. Ici, la demande est traitée par la méthode sentimentAnalysis . Ces traces sont déjà générées par l'application, c'est-à-dire ils ont exigé des changements au code.
  4. A partir de ce moment, une requête POST à sa-logic est initiée. L'ID de trace doit être transféré depuis sa-web-app .
  5. ...

Remarque : à l'étape 4, l'application doit voir les en-têtes générés par Istio et les transmettre aux demandes suivantes, comme indiqué dans l'image ci-dessous:


(A) Istio est responsable de la transmission des en-têtes; (B) Les services sont responsables des en-têtes.

Istio fait l'essentiel du travail, comme génère des en-têtes pour les demandes entrantes, crée de nouvelles étendues dans chaque sidecare et les transfère. Cependant, sans travailler avec les en-têtes à l'intérieur des services, le chemin de trace complet de la demande sera perdu.

Les rubriques suivantes doivent être prises en compte (transmises):

 x-request-id x-b3-traceid x-b3-spanid x-b3-parentspanid x-b3-sampled x-b3-flags x-ot-span-context 

C'est une tâche simple, cependant, pour simplifier sa mise en œuvre, de nombreuses bibliothèques existent déjà - par exemple, dans le service sa-web-app, le client RestTemplate transmet ces en-têtes si vous ajoutez simplement les bibliothèques Jaeger et OpenTracing en fonction de celui-ci .

Notez que l'application Sentiment Analysis illustre les implémentations sur Flask, Spring et ASP.NET Core.

Maintenant que nous savons ce que nous sortons de la boîte (ou presque «hors de la boîte»), considérons les problèmes de routage finement réglé, de gestion du trafic réseau, de sécurité, etc.!

Remarque perev. : Lisez à ce sujet dans le prochain épisode d'Istio de Rinor Maloku, qui sera disponible sur notre blog dans un proche avenir. MISE À JOUR (14 mars): La deuxième partie a déjà été publiée.

PS du traducteur


Lisez aussi dans notre blog:

Source: https://habr.com/ru/post/fr438426/


All Articles