Pourquoi OpenTelemetry ? Pourquoi se donner la peine de découvrir un nouveau monde dans l'univers de l'observabilité ? Qu'est-ce qu'OpenTelemetry de toute façon ?

Voici la définition de la communauté : OpenTelemetry est un framework et une boîte à outils d'observabilité conçus pour créer et gérer des données télémétriques telles que les traces, les métriques et les logs. Essentiellement, OpenTelemetry fonctionne avec tous les fournisseurs et outils, ce qui signifie que cette solution peut être utilisée avec un grand nombre de backends d'observabilité, y compris des outils open source, tels que Jaeger et Prometheus, ou commerciaux. OpenTelemetry est un projet cloud natif de la Computing Foundation (CNCF)

Pas mal, non? Mais si vous lisez la mission, la vision et les valeurs de la communauté, c'est encore mieux. Malgré cela, nous pouvons probablement encore trouver un grand nombre de projets sandbox CNCF avec des objectifs très similaires. Alors qu'est-ce qui fait d'OpenTelemetry (également appelé OTel) une solution si spéciale ?

Découvrez comment le projet a évolué dans le temps et quelles entreprises y contribuent activement ; vous pouvez voir sa croissance et apprécier ce qu'il sera capable d'accomplir dans les quelques prochaines années.

La vraie question est : pourquoi ne pas en faire partie maintenant ?

Bien comprendre Kubernetes

Le but de ce blog n'est pas de discuter de ce que nous savons quasiment tous sur Kubernetes, mais un peu de contexte peut s'avérer utile.

Kubernetes vise à être une plateforme hautement disponible. Pour y arriver, la solution a été conçue pour décharger différentes responsabilités vers de multiples composants évolutifs. Jetons un coup d'œil rapide sur le récapitulatif de la documentation officielle :

Il y a de nombreux rouages et ils doivent tous fonctionner parfaitement pour que vos workloads puissent avancer correctement. Heureusement, ces composants dévoilent leurs informations sur les performances de manière détaillée afin que puissiez obtenir une vue plus large de ce qui se passe dans le cluster. Mieux encore, elles utilisent un langage commun : Prometheus.

Collecte de métriques à l'échelle du cluster

Étant donné que Kubernetes nous parle dans Prometheus, pourquoi ne voudrions-nous pas lui répondre ? Bien que cela semble simple, c'est loin de l'être.

Pour commencer, Prometheus opère selon un mécanisme de traction, ce qui signifie que vous avez la responsabilité de définir les points de terminaison dont Prometheus a besoin pour trouver et récupérer (scraping) les métriques exposées. Il s'agit-là d'un défi de taille étant donné que Kubernetes est de par sa nature extrêmement dynamique en ce qui concerne la création et la suppression rapides des conteneurs.

Heureusement, Prometheus a intégré la découverte de service pour Kubernetes pour laquelle vous pouvez configurer différents projets de scraping afin que vos instances Prometheus puissent déterminer ce qu'elles doivent vérifier à l'avance.

Qu'en est-il de l'évolutivité ?

À mesure que le cluster devient de plus en plus gros, une instance de Prometheus peut exiger de nombreuses ressources et requérir une énorme machine sur laquelle opérer. Nous préférerions avoir de multiples instances plus petites qui tournent sur de plus petites machines. Cependant, comme nous tirons des métriques, le fait d'avoir de multiples instances signifie que le scraping des mêmes points de terminaison sera réalisé plusieurs fois.

Tout cela pour dire que le moment de vous présenter le collecteur OpenTelemetry est arrivé. En voici un résumé : le collecteur OTel comprend trois composants principaux : récepteurs, processeurs et exportateurs. En utilisant différentes options avec ces trois composants, vous pouvez développer plusieurs pipelines pour traiter les données télémétriques et les envoyer à différents backends selon vos besoins.

Comment pouvons-nous utiliser le collecteur OTel pour parler à Kubernetes ?

Il est fourni avec un récepteur Prometheus que nous pouvons configurer tout comme un serveur Prometheus. En d'autres termes, nous pouvons tout simplement utiliser les mêmes définitions pour la tâche de scraping. L'avantage de tout cela est qu'il n'est pas nécessaire de stocker les métriques récupérées localement (en dehors de la mémoire de l'application). C'est une sorte de Prometheus en mode agent.

Jusqu'à présent, tout va bien. Pourtant les problèmes de partitionnement (ou sharding) demeurent : nous ne pouvons toujours pas faire évoluer nos collecteurs OTel horizontalement. C'est là que Target Allocator vient nous sauver la mise. Target Allocator se trouve devant les collecteurs OTel d'état et manipule leurs configurations Prometheus, en fonction des cibles nécessitant le scraping, en les distribuant sur toutes les instances. Chaque point de terminaison fait l'objet d'un scraping par l'une des instances du collecteur OTel à ce moment-là. Pour en savoir plus sur le fonctionnement de l'évolutivité du scraping, reportez-vous à la documentation officielle.

Nous avons beaucoup parlé du fonctionnement de Prometheus, de la façon d'utiliser les collecteurs OTel et de comment les faire évoluer, mais nous n'avons pas encore parlé de ce que nous devons collecter. Voyons ce que Kubernetes nous propose.

Tout d'abord, chaque composant du Control Plane est visible dans son port dédié et nous fournit ses métriques sous le point de terminaison /metrics. Voici un exemple de configuration d'une tâche de scraping kube-api-server :

scrape_configs:
- job_name: 'kubernetes-apiservers'
  scrape_interval: 60s
  kubernetes_sd_configs:
    - role: endpoints
  scheme: https
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  relabel_configs:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep
      regex: default;kubernetes;https

Nous avons ensuite besoin d'avoir une visibilité sur les machines (les nœuds ou nodes) Un produit populaire et mature pour la collecte et la détection des métriques de nœuds est Node Exporter. Nous pouvons l'exécuter en tant que daemonset sur chaque nœud (Linux) et assurer le scraping de ce qu'il collecte à partir de la machine sous-jacente comme suit :

scrape_configs:
- job_name: 'kubernetes-node-exporter'
  scrape_interval: 60s
  honor_labels: true
  kubernetes_sd_configs:
    - role: endpoints
  relabel_configs:
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      action: keep
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
      action: drop
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      action: replace
      target_label: __scheme__
      regex: (https?)
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)
    - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      action: replace
      target_label: __address__
      regex: (.+?)(?::\d+)?;(\d+)
      replacement: $$1:$$2
    - source_labels: [__meta_kubernetes_service_name]
      action: keep
      regex: <NODE_EXPORTER_SERVICE_NAME>
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: namespace
    - source_labels: [__meta_kubernetes_service_name]
      action: replace
      target_label: service
    - source_labels: [__meta_kubernetes_pod_node_name]
      action: replace
      target_label: node

Maintenant que nous avons les métriques au niveau de la machine, nous pouvons passer à un niveau supérieur pour monitorer les conteneurs. Les métriques du conteneur sont collectées par l'outil cAdvisor (Container Advisor), qui est exécuté sur chaque nœud. Nous pouvons effectuer leur scraping comme suit :

scrape_configs:
- job_name: 'kubernetes-nodes-cadvisor'
  scrape_interval: 60s
  scheme: https
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  kubernetes_sd_configs:
    - role: node
  relabel_configs:
    - target_label: __address__
      replacement: kubernetes.default.svc:443
    - source_labels: [__meta_kubernetes_node_name]
      regex: (.+)
      target_label: __metrics_path__
      replacement: /api/v1/nodes/$$1/proxy/metrics/cadvisor

Enfin et surtout, nous avons besoin de connaître l'état des composants dans notre cluster. L'outil kube-state-metrics demande cette information à divers points de terminaison et génère des métriques que nous pouvons de nouveau soumettre au scraping avec le récepteur Prometheus des collecteurs OTel :

scrape_configs:
- job_name: 'kubernetes-kube-state-metrics'
  scrape_interval: 60s
  honor_labels: true
  kubernetes_sd_configs:
    - role: endpoints
  relabel_configs:
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      action: keep
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
      action: drop
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      action: replace
      target_label: __scheme__
      regex: (https?)
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)
    - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      action: replace
      target_label: __address__
      regex: (.+?)(?::\d+)?;(\d+)
      replacement: $$1:$$2
    - source_labels: [__meta_kubernetes_service_name]
      action: keep
      regex: <KUBE_STATE_METRICS_SERVICE_NAME>
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: namespace
    - source_labels: [__meta_kubernetes_service_name]
      action: replace
      target_label: service
    - source_labels: [__meta_kubernetes_pod_node_name]
      action: replace
      target_label: node

À ce stade, il est évident que nous pouvons simplement créer une tâche de scraping dédiée pour chaque composant que nous voulons monitorer.

Que pouvons-nous obtenir d'autre du cluster ?

Outre les métriques que nous avons collectées avec succès grâce au récepteur Prometheus, nous pouvons aussi collecter les événements et les logs de nos clusters. (Remarque : les traces ne sont pas couvertes dans ce billet de blog.)

Commençons par les événements. Kubernetes envoie des événements dès qu'il y a une création, suppression ou mutation dans le cluster. Ces événements peuvent être extraits en interrogeant kube-api-server. Heureusement, le collecteur OTel dispose d'un receveur pour cela : le récepteur k8sevents. (Remarque : des discussions sont actuellement en cours concernant l'obsolescence de ce récepteur et son remplacement par le récepteur k8sobject à l'avenir.)

Vous pouvez exécuter une seule instance de collecteur pour extraire les événements Kubernetes et les transférer à New Relic sous la forme de logs. Attention : plusieurs instances du récepteur k8sevent seront extraites et enverront les mêmes événements à New Relic.

Qu'en est-il des logs ? Le collecteur OTel comprend un récepteur filelog, que vous pouvez exécuter en tant que daemonset sur lequel vous pouvez monter le répertoire de log du nœud. Vous pouvez utiliser différentes expressions régulières (regex) pour collecter, analyser, filtrer et enrichir les logs à partir de n'importe quel composant dans votre cluster.

Déploiement et monitoring des collecteurs OTel avec New Relic

Nous savons où trouver les données télémétriques requises et comment les collecter. Nous avons maintenant besoin de :

  1. Créer une stratégie pour déployer les instances de notre collecteur OTel avec les configurations nécessaires.
  2. Créer des dashboards et alertes adéquates avec les vastes requêtes NRQL (le langage de requête de New Relic) pour le monitoring des clusters.

Bonne nouvelle ! Il existe un référentiel qui contient tout ce dont nous avons parlé jusqu'à présent :

  • Un graphique Helm public que vous pouvez utiliser pour déployer vos collecteurs OTel.
  • Un déploiement Terraform que vous pouvez utiliser pour l'amorçage (bootstrap) d'un monitoring prédéveloppé dans votre compte New Relic.

Pour plus d'information, consultez les ressources suivantes :

  • Lisez cette documentation pour comprendre pourquoi nous avons besoin de différents types (daemonset, deployment, statefulset, singleton) de collecteurs.
  • Reportez-vous à cette documentation pour déployer la solution de monitoring sur votre cluster.
  • Sachez comment interroger et donner du sens aux données Prometheus collectées en consultant cette documentation.

Cette documentation vous aidera à créer des dashboards et alertes dans votre compte New Relic.