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:
- Eine Strategie zum Bereitstellen unserer OTel-Collector-Instanzen mit den nötigen Konfigurationen entwickeln.
- 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.
Nächste Schritte
Dieses Repository ist als öffentliches Gemeinschaftswerk gedacht. Sehen Sie sich an, was es zu bieten hat, und scheuen Sie sich nicht, Fragen zu stellen, neue Features vorzuschlagen und vor allem mitzumachen!
Die in diesem Blog geäußerten Ansichten sind die des Autors und spiegeln nicht unbedingt die Ansichten von New Relic wider. Alle vom Autor angebotenen Lösungen sind umgebungsspezifisch und nicht Teil der kommerziellen Lösungen oder des Supports von New Relic. Bitte besuchen Sie uns exklusiv im Explorers Hub (discuss.newrelic.com) für Fragen und Unterstützung zu diesem Blogbeitrag. Dieser Blog kann Links zu Inhalten auf Websites Dritter enthalten. Durch die Bereitstellung solcher Links übernimmt, garantiert, genehmigt oder billigt New Relic die auf diesen Websites verfügbaren Informationen, Ansichten oder Produkte nicht.