Warum überhaupt OpenTelemetry? Warum sollten wir uns mit noch einem weiteren neuen Konzept in Sachen Observability herumschlagen? Was ist OpenTelemetry eigentlich?

Die Definition der Community lautet wie folgt: OpenTelemetry ist ein Observability-Framework und -Toolkit, das zur Erstellung und Verwaltung von Telemetriedaten wie Traces, Metriken und Logs dient. Vor allem ist OpenTelemetry anbieter- und toolagnostisch und kann daher mit zahlreichen verschiedenen Observability-Backends verwendet werden, und zwar sowohl Open-Source-Tools wie Jaeger und Prometheus als auch Tools kommerzieller Anbieter. OpenTelemetry ist ein Projekt der Cloud Native Computing Foundation (CNCF).

Klingt cool. Die Mission, Vision und Werte der Community klingen sogar noch cooler. Allerdings gibt es wahrscheinlich CNCF-Sandbox-Projekte wie Sand am Meer, die alle Ähnliches versprechen. Was ist also an OpenTelemetry oder OTel so besonders?

Sehen Sie sich an, wie sich das Projekt über die Jahre entwickelt hat und welche Unternehmen aktiv dazu beitragen. Es wird schnell offensichtlich, was in ein paar Jahren daraus werden könnte.

Die brennende Frage ist also: Warum nicht gleich mitmachen?

Was ist Kubernetes?

In diesem Blogpost soll es nicht um all das gehen, was die meisten von uns ohnehin schon über Kubernetes wissen, aber ein wenig Kontext ist wahrscheinlich schon hilfreich.

Kubernetes ist als hochverfügbare Plattform konzipiert. Dazu überträgt es verschiedene Aufgaben an mehrere skalierbare Komponenten. Sehen wir uns am besten einmal die Zusammenfassung in der offiziellen Dokumentation an:

Wie wir sehen, sind das ziemlich viele Komponenten, die alle einwandfrei funktionieren müssen, damit Ihre Workloads ebenfalls reibungslos ausgeführt werden. Zum Glück liefern diese Komponenten detaillierte Performance-Einblicke, sodass Sie ein besseres Verständnis der Abläufe in Ihrem Cluster erhalten. Und sie sprechen alle die gleiche Sprache: Prometheus.

Sammeln Cluster-weiter Metriken

Kubernetes spricht mit uns in Prometheus, sollten wir dann nicht auch in Prometheus antworten? Das klingt zwar ziemlich offensichtlich, ist es aber nicht.

Zunächst einmal funktioniert Prometheus auf Basis eines Pull-Mechanismus, d. h. Sie müssen selbst festlegen, welche Endpunkte Prometheus benötigt, um die von ihm freigegebenen Metriken zu finden und zu scrapen. Das ist eine ziemlich anspruchsvolle Aufgabe, da Kubernetes sehr dynamisch ist und Container sehr schnell erstellt, aber auch wieder entfernt werden können.

Zum Glück hat Prometheus eine integrierte Service-Discovery für Kubernetes, für die Sie verschiedene Scrape-Jobs konfigurieren können, sodass Ihre Prometheus-Instanzen im Voraus ermitteln können, wo die Suche stattfinden soll.

Und was ist mit der Skalierbarkeit?

Mit zunehmender Cluster-Größe würde eine Prometheus-Instanz Unmengen an Ressourcen verschlingen und einen enormen Rechner benötigen. In diesem Fall wäre es sinnvoller, mehrere kleine Instanzen auf kleineren Rechnern laufen zu lassen. Aber da wir die Metriken per Pull-Mechanismus abrufen, hätten wir bei mehreren Instanzen das Problem, dass es zu einem mehrfachen Scraping derselben Endpunkte käme.

Jetzt ist wahrscheinlich ein guter Zeitpunkt, um uns den OpenTelemetry Collector genauer anzusehen. Kurz gesagt, besteht der OTel Collector aus drei Hauptkomponenten: Empfängern, Prozessoren und Exportern. Mit Varianten dieser drei Komponenten können Sie verschiedene Pipelines erstellen, um die Telemetriedaten zu handhaben und an die jeweils relevanten Backends zu senden.

Wie können wir den OTel Collector dazu nutzen, mit Kubernetes zu kommunizieren?

Er umfasst einen Prometheus-Empfänger, den wir genauso wie einen Prometheus-Server konfigurieren können, also mit denselben Scrape-Jobdefinitionen. Das Gute daran ist, dass die abgerufenen Metriken nicht lokal gespeichert werden müssen (außer im Anwendungsspeicher). Das Ganze können Sie sich quasi als Prometheus im Agent-Modus vorstellen.

So weit, so gut. Das Sharding-Problem haben wir aber weiterhin: Wir können unsere OTel Collectors noch immer nicht horizontal skalieren. Hier kommt der Target Allocator ins Spiel. Der Target Allocator ist Ihren zustandsbehafteten OTel Collectors vorgelagert und manipuliert deren Prometheus-Konfigurationen (abhängig von den Scraping-Zielen), indem er sie über die Instanzen verteilt. Jeder Endpunkt wird jeweils von einer OTel-Collector-Instanz gescrapet. Um mehr zur Scraper-Skalierung zu erfahren, sehen Sie sich die offizielle Dokumentation an.

Bisher haben wir uns damit befasst, wie Prometheus funktioniert und wie wir OTel Collectors einsetzen und skalieren, aber was wir da eigentlich sammeln, haben wir noch nicht gesagt. Sehen wir uns als Nächstes an, was Kubernetes zu bieten hat.

Erstens wird jede Komponente auf der Kontrollebene in ihrem jeweiligen Port angezeigt und liefert uns unter dem Endpunkt /metrics ihre Metriken. Sehen wir uns zum Beispiel eine Scraping-Jobkonfiguration des kube-api-Servers an:

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

Zweitens brauchen wir Einsicht in die Maschinen (Knoten). Ein beliebtes und zuverlässiges Tool zum Sammeln und Freigeben von Knotenmetriken ist Node Exporter. Wir können ihn als Daemonset auf jedem (Linux-)Knoten ausführen und das, was er von der jeweiligen Maschine sammelt, folgendermaßen scrapen:

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

Nachdem wir nun die Maschinen-Metriken haben, können wir eine Stufe hochgehen und unsere Container überwachen. Container-Metriken werden vom Tool cAdvisor (Container Advisor) gesammelt, das auf jedem Knoten ausgeführt wird. Das Scraping erfolgt folgendermaßen:

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

Als Letztes möchten wir den Zustand der Komponenten in unserem Cluster ermitteln. Das Tool kube-state-metrics fragt diese Informationen von verschiedenen Endpunkten ab und generiert dann Metriken, die wir wiederum mit dem Prometheus-Empfänger unserer OTel Collectors scrapen können:

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

Es erklärt sich von selbst, dass wir einfach für jede einzelne Komponente, die wir überwachen wollen, einen separaten Scrape-Job erstellen können.

Was können wir noch aus dem Cluster ziehen?

Zusätzlich zu den Metriken, die wir mit dem Prometheus-Empfänger gesammelt haben, können wir aus unseren Clustern Events und Logs erfassen. (Hinweis: Mit Traces befassen wir uns in diesem Blog nicht.)

Sehen wir uns als Erstes die Events an. Kubernetes erstellt Events jedes Mal, wenn im Cluster eine Erstellung, Löschung oder Mutation stattfindet. Diese Events lassen sich durch Abfrage des Kube-api-Servers abrufen. Und der OTel Collector hat zum Glück einen Empfänger dafür, nämlich den k8sevents-Empfänger. (Hinweis: Es gibt zurzeit Überlegungen, diesen Empfänger einzustellen und zukünftig durch den k8sobject-Empfänger zu ersetzen.)

Sie können eine einzige Collector-Instanz ausführen, um die Kubernetes-Events abzurufen und als Logs an New Relic weiterzuleiten. Achtung: Wenn Sie mehrere Instanzen des k8sevent-Empfängers verwenden, rufen diese dieselben Events ab und senden sie an New Relic.

Und was ist mit Logs? Der OTel Collector umfasst einen filelog-Empfänger, den Sie als daemonset ausführen können. Das Logverzeichnis des Knotens können Sie daran mounten. Mit verschiedenen regulären Ausdrücken (RegEx) können Sie die Logs aus allen Komponenten in Ihrem Cluster sammeln, parsen, filtern und anreichern.

Bereitstellen von OTel Collectors und Monitoring mit New Relic

Wir wissen jetzt, wo wir die erforderlichen Telemetriedaten finden und wie wir sie erfassen. Jetzt müssen wir noch Folgendes tun:

  1. Eine Strategie zum Bereitstellen unserer OTel-Collector-Instanzen mit den nötigen Konfigurationen entwickeln.
  2. Zum Monitoring unserer Cluster eigene Dashboards und Alerts mit umfassenden Abfragen in New Relic Query Language (NRQL) erstellen.

Good news: Es gibt ein Repository, das alles enthält, was wir bisher besprochen haben:

  • Ein öffentlich zugängliches Helm-Chart, mit dem Sie Ihre OTel Collectors ausrollen können.
  • Ein Terraform-Deployment, mit dem Sie eine einsatzbereite Monitoring-Lösung in Ihrem New Relic Konto bootstrappen können.

Weitere Informationen finden Sie in den folgenden Ressourcen:

  • In dieser Dokumentation erfahren Sie, warum wir verschiedene Collector-Typen benötigen (Daemonset, Deployment, Statefulset, Singleton).
  • Eine Anleitung zum Bereitstellen der Monitoring-Lösung in Ihrem Cluster finden Sie in dieser Dokumentation.
  • Wenn Sie wissen möchten, wie Sie die erfassten Prometheus-Daten korrekt abfragen und interpretieren, sehen Sie sich diese Dokumentation an.

Infos zum Erstellen von Dashboards und Alerts in Ihrem New Relic Konto finden Sie in dieser Dokumentation.