Dans le passé, nous avons examiné les composants de base de Service Mesh Istio, nous nous sommes familiarisés avec le système et avons répondu à des questions essentielles qui surgissent généralement au début de l'utilisation d'Istio. Dans cette partie, nous allons voir comment organiser la collecte des informations de traçage sur le réseau.

La première chose qui vient à l'esprit de nombreux développeurs et administrateurs systèmes lorsqu'ils entendent les mots Service Mesh est le traçage. En effet, nous intégrons dans chaque nœud du réseau un proxy spécial, par lequel passe tout le trafic TCP. Il semble alors facile d'envoyer des informations sur toutes les interactions réseau. Malheureusement, en réalité, de nombreux détails doivent être pris en compte. Examinons-les.
Idée reçue numéro un : nous pouvons obtenir gratuitement des données sur le trafic du réseau.
En réalité, nous pouvons obtenir relativement gratuitement uniquement des nœuds de notre système reliés par des flèches et le taux de données qui passe entre les services (en somme, uniquement le nombre d'octets par unité de temps). Cependant, dans la plupart des cas, nos services communiquent selon un protocole de niveau applicatif tel que HTTP, gRPC, Redis, etc. Et bien sûr, nous souhaitons voir les informations de traçage précisément selon ces protocols, nous voulons voir le taux de requêtes et non le taux de données. Nous voulons comprendre la latence des requêtes selon notre protocole. Enfin, nous voulons voir le chemin complet parcouru par la requête depuis l'entrée dans notre système jusqu'à la réception de la réponse par l'utilisateur. Cette tâche devient alors beaucoup plus complexe.
Pour commencer, examinons à quoi ressemble l'envoi de spans de traçage du point de vue de l'architecture dans Istio. Comme nous l'avons vu dans la première partie, Istio dispose d'un composant distinct dédié à la collecte de télémétrie, appelé Mixer. Cependant, dans la version actuelle 1.0.*, l'envoi se fait directement à partir des serveurs proxy, à savoir, du proxy Envoy. Le proxy Envoy supporte nativement l'envoi de spans de traçage via le protocole Zipkin. D'autres protocoles peuvent être intégrés, mais uniquement via un plugin. Avec Istio, nous obtenons directement un proxy Envoy configuré et assemblé, qui ne prend en charge que le protocole Zipkin. Si nous souhaitons utiliser, par exemple, le protocole Jaeger et envoyer des spans de traçage via UDP, nous devrons créer notre propre image istio-proxy. Le support des plugins personnalisés pour istio-proxy est présent, cependant il est encore en version alpha. Donc, si nous voulons éviter un grand nombre de configurations personnalisées, le choix des technologies pour stocker et recevoir des spans de traçage se réduit. Parmi les systèmes principaux, nous pouvons essentiellement utiliser Zipkin lui-même, ou Jaeger, mais envoyer tout cela via le protocole compatible Zipkin (ce qui est beaucoup moins efficace). Le protocole Zipkin lui-même suppose l'envoi de toutes les informations de traçage aux collecteurs via le protocole HTTP, ce qui est assez coûteux.
Comme je l'ai déjà mentionné, nous souhaitons tracer les protocoles de niveau application. Cela signifie que les serveurs proxy, qui se trouvent à côté de chaque service, doivent comprendre quelle interaction se déroule actuellement. Par défaut, Istio configure tous les ports avec le type TCP simple, ce qui signifie qu'aucun traçage ne sera envoyé. Pour que les traces soient envoyées, il faut, d'une part, activer une telle option dans la configuration principale du mesh et, ce qui est très important, nommer tous les ports des entités de service Kubernetes conformément au protocole utilisé dans le service. Par exemple, cela pourrait ressembler à ceci :
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: nginxOn peut aussi utiliser des noms composés, par exemple http-magic (Istio détectera http et reconnaîtra ce port comme un point de terminaison http). Le format est le suivant : proto-extra.
Pour éviter de patcher un grand nombre de configurations pour déterminer le protocole, on peut utiliser une solution de contournement peu élégante : patcher le composant Pilot au moment où il exécute la logique de détermination du protocole. En fin de compte, il sera bien sûr nécessaire de modifier cette logique pour passer à la convention de nommage de tous les ports.
Pour comprendre si le protocole est bien défini, il faut entrer dans l'un des conteneurs sidecar avec envoy proxy et faire une requête sur le port de l'interface admin d'envoy avec l'emplacement /config_dump. Dans la configuration résultante, il faut vérifier le champ 'operation' du service concerné. Il est utilisé dans Istio comme un identifiant de la destination de la requête. Pour personnaliser la valeur de ce paramètre dans Istio (que nous verrons ensuite dans notre système de traçage), il est nécessaire de spécifier le drapeau serviceCluster lors du démarrage du conteneur sidecar. Par exemple, il peut être calculé à partir des variables obtenues de l'API downward de kubernetes :
--serviceCluster ${POD_NAMESPACE}.$(echo ${POD_NAME} | sed -e 's/-[a-z0-9]*-[a-z0-9]*$//g')
Un bon exemple pour comprendre comment fonctionne le traçage dans envoy est .
Le point d'extrémité pour l'envoi des spans de traçage doit également être spécifié dans les drapeaux de démarrage de l'envoy proxy, par exemple : --zipkinAddress tracing-collector.tracing:9411
Erreur numéro deux : nous pouvons obtenir des traces complètes des requêtes à travers le système à bas prix par défaut.
Malheureusement, ce n'est pas le cas. La complexité de l'implémentation dépend de la manière dont vous avez déjà réalisé l'interaction entre les services. Pourquoi ?
La raison est qu'il ne suffit pas de simplement intercepter tout le trafic pour que l'istio-proxy puisse comprendre la correspondance entre les requêtes entrantes dans un service et celles sortantes de ce même service. Un identifiant de liaison est nécessaire. Dans HTTP, l'envoy proxy utilise des en-têtes spécifiques, selon lesquels envoy comprend quelle requête vers un service génère des requêtes spécifiques vers d'autres services. La liste de ces en-têtes est :
- x-request-id,
- x-b3-traceid,
- x-b3-spanid,
- x-b3-parentspanid,
- x-b3-sampled,
- x-b3-flags,
- x-ot-span-context.
Si vous avez un point unique, par exemple, un client de base où vous pouvez ajouter cette logique, c'est parfait, il ne vous restera plus qu'à attendre que cette bibliothèque soit mise à jour chez tous les clients. Mais si vous avez un système très hétérogène et qu'il n'y a pas d'unification dans le chemin des services à travers le réseau, cela posera probablement un grand problème. Sans l'ajout d'une telle logique, toutes les informations de traçage seront simplement "unidimensionnelles". Cela signifie que nous obtiendrons toutes les interactions inter-services, mais elles ne seront pas liées en chaînes uniques traversant le réseau.
Conclusion
Istio fournit un outil pratique pour la collecte d'informations de traçage à travers le réseau, mais il est important de comprendre que sa mise en œuvre nécessitera d'adapter votre système et de tenir compte des spécificités de l'implémentation d'Istio. Au final, il faut résoudre deux questions principales : la définition du protocole de niveau applicatif (qui doit être pris en charge par le proxy envoy) et la configuration du transfert des informations sur la liaison des requêtes entre les services via les en-têtes, dans le cas du protocole HTTP. Une fois ces questions résolues, nous obtenons un puissant outil qui permet de collecter des informations à travers le réseau même dans des systèmes très hétérogènes, écrits dans de nombreux langages et frameworks différents.
Dans le prochain article sur Service Mesh, nous examinerons l'un des plus grands problèmes d'Istio : la forte consommation de mémoire vive par chaque conteneur proxy sidecar et discuterons des solutions possibles.
Source : habr.com
