Zum Hauptinhalt springen

Application Monitoring

Application Monitoring ist ein Dienst von nine Managed GKE, der es erlaubt Ihre Kubernetes Applikationen zu überwachen.

Video Guide

Schauen Sie unseren Guide zu Application Monitoring.

Details

Mit Application Monitoring stellt nine eine komplette Monitoring Lösung mit den folgenden Merkmalen zur Verfügung:

  • von nine verwaltete Prometheus Instanz
  • vorintegrierte Metriken Exporter
  • zu überwachende Dienste und Prometheus Regeln können selbst verwaltet werden
  • von nine verwaltete Alertmanager Instanz um Benachrichtigungen zu senden
  • die Konfiguration von Alertmanager kann selbst verändert werden
  • vorkonfigurierte Prometheus Datenquelle in Grafana

Verfügbarkeit

Application Monitoring wird als zusätzlicher Dienst zu nine Managed GKE angeboten und abgerechnet. Application Monitoring kann mittels der Erstellung eines Support Tickets angefragt werden.

Voraussetzungen

Nine Nodes müssen auf n1-standard-2 migriert werden, da die n1-standard-1 Nodes nicht genug Leistung besitzen. Wenn Sie Application Monitoring bestellen, werden wir die Nodes auf n1-standard-2 upgraden.

Nutzung

In den folgenden Abschnitten finden Sie alle Informationen über die Benutzung und Konfiguration von Application Monitoring.

Generelle Informationen über den Aufbau

Die Application Monitoring Lösung basiert auf der Nutzung des prometheus-operator Projektes. Nine wird, im Zuge der Bestellung des Produktes, folgende Tätigkeiten ausführen:

  • Erstellung einer (oder mehrerer) Prometheus Instanzen (welche den regionalen Speicher von GCP nutzen) auf dem nine Node Pool
  • Erstellung einer Instanz des prometheus-operators auf dem nine Node Pool
  • Erstellung von 2 Alertmanager Instanzen auf dem nine Node Pool
  • Anbindung von existierenden Metrik Datenquellen in der erstellten Prometheus Instanz
  • Erstellung einer Grafana Datenquelle, mit welcher die von Prometheus gesammelten Metriken angezeigt werden können

Da alle Monitoring Komponenten auf dem nine Node Pool laufen, stehen Ihren Applikationen die vollen Ressourcen Ihrer Node Pools zur Verfügung. Zusätzlich bietet der Einsatz von GCP regionalem Speicher die Möglichkeit die Prometheus Instanz im Fehlerfall in eine andere Compute Zone zu verschieben. Dadurch ergibt sich eine hohe Verfügbarkeit der Instanz.

Mithilfe des prometheus-operator Projektes können Sie die folgenden Ressourcen verwenden um Dienste und Regeln in Prometheus zu konfigurieren:

  • ServiceMonitors
  • PodMonitors
  • PrometheusRules

Falls Sie mehrere Prometheus Instanzen benötigen, so können wir diese für Sie erstellen. Jede Instanz bekommt einen eindeutigen Namen zugewiesen, welchen sie auf runway einsehen können. Dieser muss dann mittels eines Labels namens nine.ch/prometheus jeder oben stehenden Ressourcen hinzugefügt werden. Auf diese Weise erfolgt eine Zuordnung zur jeweiligen Prometheus Instanz.

Weitere Informationen über die Ressourcen finden Sie unter "Hinzufügen von Applikations Metriken zu Prometheus" und "Hinzufügen von Prometheus Regeln".

Sollte Prometheus aufgrund der konfigurierten Regeln einen Alarm auslösen, so übernimmt der verwaltete Alertmanager das Senden von Benachrichtigungen an Benutzer. Die Konfiguration dieser Instanz kann durch ein speziell benanntes Kubernetes Secret in einem vordefinierten Kubernetes Namespace erfolgen. Weitere Informationen finden Sie unter "Konfiguration von Alertmanager".

Zugriff via Web UI

Die URLs für das Web UI von Prometheus und Alertmanager können Sie auf runway einsehen.

Metriken in Applikationen einbinden

Bevor Prometheus Metriken von Ihren Applikationen abfragen kann, müssen diese zuerst eingebunden bzw. implementiert werden. Prometheus erwartet die Metriken in einem speziellen Format. Sie können weitere Informationen darüber in der offiziellen Prometheus Dokumentation finden.

Einbinden von Applikationen in Prometheus

Sobald ihre Applikation selbst Metriken im Prometheus Format exportiert, können sie ServiceMonitor und PodMonitor Ressourcen nutzen, um Prometheus diese Metriken in regelmässigen Abständen sammeln zu lassen.

Durch die Nutzung einer ServiceMonitor Ressource können Sie alle hinter einem Kubernetes Service stehenden Pods automatisch auf Metriken abfragen. Diese Ressource sollte in den meisten Fällen Anwendung finden. Um die gewünschten Kubernetes Services zu selektieren müssen Sie einen Label Selektor im ServiceMonitor definieren. Der ServiceMonitor sollte dabei im selben Namespace wie die Kubernetes Services selbst erstellt werden. Neben dem Label Selektor, sollte der ServiceMonitor zusätzlich selbst das Label nine.ch/prometheus besitzen. Der zugewiesene Wert des Labels muss dabei dem Namen der eingesetzten Prometheus Instanz (kann auf runway eingesehen werden) entsprechen. Zur Verdeutlichung hier ein Beipiel:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
namespace: my-app
labels:
nine.ch/prometheus: myPrometheus
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: web
kind: Service
apiVersion: v1
metadata:
name: my-app-service
namespace: my-app
labels:
app: my-app
spec:
selector:
application: example-app
ports:
- name: web
port: 8080

Die definierte ServiceMonitor Ressource selektiert den Kubernetes Service "my-app-service", da dieser das Label "app: my-app" besitzt. Prometheus wird daraufhin alle Pods auf Metriken überprüfen, welche wiederum von diesem Kubernetes Service selektiert werden. Dabei werden die Metriken auf Port 8080 abgefragt, da der ServiceMonitor diesen in seinem endpoint Feld definiert.

Durch den Einsatz von PodMonitor Objekten, kann erreicht werden, dass alle Pods welche durch einen definierten Label Selektor selektiert werden, auf Metriken abgefragt werden. Die Funktionsweise ist der der ServiceMonitor Ressource sehr ähnlich (es wird lediglich kein Kubernetes Service dabei genutzt). Sie sollten PodMonitor Objekte dann einsetzen, wenn Ihre Applikation keinen Kubernetes Service für ihre Funktionsweise benötigt. Dies ist beispielsweise bei einigen Metrik Exportern der Fall. Die selektierten Pods sollten sich dabei im selben Namespace wie die PodMonitor Ressource befinden.

Hier ein Beispiel zur Verwendung:

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: my-pods
namespace: my-app
labels:
nine.ch/prometheus: myPrometheus
spec:
selector:
matchLabels:
application: my-app
endpoints:
- port: web
apiVersion: v1
kind: Pod
metadata:
labels:
application: my-app
name: my-app
namespace: my-app
spec:
containers:
- image: mycompany/example-app
name: app
ports:
name: web
containerPort: 8080

Anhand dieses definierten PodMonitor Objektes wird der prometheus-operator eine Konfiguration für Prometheus generieren, welche den Pod namens "my-app" auf dem Port 8080 auf Metriken überprüft.

Prometheus erstellt für jeden definierten ServiceMonitor oder PodMonitor einen sogenannten job. Es wird zusätzlich auch ein job Label an alle abgefragten Metriken des jeweiligen Jobs hinzugefügt. Dadurch kann ermittelt werden, von welchen Services bzw. Pods die entsprechende Metrik stammt.

Darstellen und Abfragen von Metriken aus Prometheus

Um die von Prometheus gesammelten Metriken darzustellen kann die Sprache PromQL genutzt werden. Sie können einige Beispiele zur Nutzung in der offiziellen Prometheus Dokumentation finden. Metriken können entweder im Prometheus Web UI oder innerhalb von Grafana (explore Modus) dargestellt werden. Bitte stellen Sie sicher, dass bei der Verwendung von Grafana, die korrekte Datenquelle ausgewählt ist. Der Name der Datenquelle sollte "prometheus-<Prometheus Instanz Name>" entsprechen.

Hinzufügen von Prometheus Regeln

Prometheus unterstützt die Verwendung zweier Arten von Regeln: recording rules und alerting rules. Beide haben eine sehr ähnliche Syntax, dienen jedoch unterschiedlichen Einsatzzwecken.

Recording rules können dazu genutzt werden, anhand bereits vorhandener Metriken, neue Metriken in Intervallen zu berechnen und zu speichern. Dies ist vor allem in komplexen Queries nützlich, welche periodisch durchgeführt werden und für die Prometheus bei jeder Ausführung erhöhte Ressourcen (und Zeit) benötigt. Ein Beispiel dafür sind Queries welche via Grafana auf Dashboards angezeigt werden.

Alerting rules erlauben es Bedingungen (mittels PromQL) zu definieren bei deren Erfüllung Prometheus einen Alarm auslöst. Dieser Alarm kann dann wiederum eine Benachrichtigung via Alertmanager auslösen.

Wenn sie recording rules oder alerting rules definieren, müssen sie das Label nine.ch/prometheus zur jeweiligen Ressource hinzufügen. Der Wert des Labels sollte dem Namen der Prometheus Instanz entsprechen. Auf diese Weise kann die Regel einer Prometheus Instanz zugewiesen werden.

Hier ein Beispiel für eine alerting rule:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
nine.ch/prometheus: myPrometheus
role: alert-rules
name: jobs-check
spec:
groups:
- name: ./example.rules
rules:
- alert: InstanceDown
expr: up == 0
for: 5m
labels:
severity: Critical
annotations:
summary: "Instance {{ $labels.instance }} down"
description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."

Die oben definierte Regel löst einen Alarm aus sobald die up Metrik den Wert 0 annimmt. Die up Metrik is dabei eine spezielle Metrik, welche von Prometheus für jedes Job Ziel (also einen Metriken exportierenden Pod) erzeugt wird. Sobald der entsprechende Pod nicht mehr auf Metriken abgefragt werden kann, wird die up Metrik auf 0 gesetzt. Bleibt die Metrik für mehr als 5 Minuten in dem entsprechenden Zustand, so wird ein Alarm ausgelöst. Die zusätzlich definierten Labels und Annotations können später im Alertmanager in Benachrichtigungen und für Routing Entscheidungen genutzt werden.

Die volle Spezifikation für die PrometheusRule Ressource kann hier eingesehen werden.

Zur Vervollständigung noch ein Beispiel für eine recording rule:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
nine.ch/prometheus: myPrometheus
role: recording-rules
name: cpu-per-namespace-recording
spec:
groups:
- name: ./example.rules
rules:
- record: namespace:container_cpu_usage_seconds_total:sum_rate
expr: sum(rate(container_cpu_usage_seconds_total{job="kubelet", metrics_path="/metrics/cadvisor", image!="", container!="POD"}[5m])) by (namespace)

Hier wird eine neue Metrik namens namespace:container_cpu_usage_seconds_total:sum_rate erzeugt. Diese Metrik zeigt die Summe der genutzten CPU Zeit aller Container von allen Pods eines Namespaces an und vereinfacht damit die Darstellung genutzter CPU Zeit pro Namespace in Grafana.

Das kubernetes-mixins Projekt enthält nützliche Regeln welche für verschiedene Exporter genutzt werden können. Einige der dort vorhandenen Regeln wurden bereits in ihre Prometheus Instanz integriert.

Website Checks

Sie können sehr einfach die Verfügbarkeit von Websites, welche sie durch einen Kubernetes Ingress verfügbar machen, periodisch überprüfen lassen. Dazu müssen Sie lediglich das Label nine.ch/prometheus mit dem Namen ihrer Prometheus Instanz zur Ingress Resource hinzufügen. Den Namen Ihrer Instanz können Sie auf runway einsehen. Nachdem das Label hinzugefügt wurde, wird Prometheus den HTTP Endpunkt welcher im Ingress definiert wurde, anfangen periodisch abzufragen. Dies geschieht mit Hilfe des blackbox exporters, welchen wir als GCP Cloud Function in jedem GCP Projekt betreiben. Diese Instanz ist lediglich vom nine Managed GKE Cluster heraus zugänglich.

Um die durchgeführten Checks noch weiter anpassen zu können, bieten wir die folgenden Annotations an, welche Sie ihrem Ingress Objekt hinzufügen können:

AnnotationBeschreibungBeispiel
blackbox-exporter.nine.ch/valid_status_codesDer durchgeführte Check wird dann als erfolgreich gemeldet, wenn der HTTP Status Code der Antwort mit einem hier definierten Code übereinstimmt. Die Codes sind Komma separiert. Komplette Bereiche können abgekürzt geschrieben werden (bspw. 2xx für den Range 200-299)blackbox-exporter.nine.ch/valid_status_codes: 2xx, 3xx, 401
blackbox-exporter.nine.ch/expect_regexpDer durchgeführte Check wird als erfolgreich markiert, wenn die angegebene Regular Expression auf einen String im Body der Antwort zutrifft.blackbox-exporter.nine.ch/expect_regexp: status=[oO][kK]
blackbox-exporter.nine.ch/fail_on_regexpDer durchgeführte Check wird als erfolgreich markiert, wenn die angegebene Regular Expression nicht auf einen String im Body der Antwort zutrifft.blackbox-exporter.nine.ch/fail_on_regexp: status=([fF]ailed|[eE]rror)

Die Metriken welche Sie durch den Check zur Verfügung gestellt bekommen, können Sie mittels des folgenden Prometheus Queries abfragen:

 {job="ingress-check"}

Um den HTTP Status Code der Checks zu erhalten, nutzen Sie den folgenden Query:

probe_http_status_code{job="ingress-check",namespace=<namespace of your ingress>,ingress=<name of your ingress>}

Der generelle Status des Checks kann über die Metrik "probe_success" bezogen werden:

probe_success{job="ingress-check",namespace=<namespace of your ingress>,ingress=<name of your ingress>}

Die Metrik "probe_duration_seconds" zeigt wie lang die Abfrage des HTTP Endpunktes dauerte. Die Metrik enthält dafür ein Label namens "phase", welches die jeweilige Verbindungsphase identifiziert.

Konfiguration von Alertmanager

Die Alertmanager Komponente ist für das Senden von Benachrichtigungen, im Falle von ausgelösten Prometheus Alarmen, zuständig. Dafür werden verschiene Benachrichtigungsarten (wie beispielsweise Slack, Email, Hipchat, PagerDuty, etc) unterstützt. Detaillierte Informationen über die Konfiguration von Alertmanager befinden sich auf der offiziellen Prometheus Website. Eventuell helfen auch unsere Beispielkonfigurationen um das geeignete Setup zu finden.

Die von uns erstellten Alertmanager Instanzen, haben von Haus aus keine Benachrichtigungsempfänger konfiguriert. Damit sie dies anpassen können, existiert die Möglichkeit eine komplette Alertmanager Konfiguration via eines Kubernetes Secrets zu definieren. Erstellen Sie dazu einen Kubernetes Namespace namens alertmanager-config in dem sie dann ein Kubernetes Secret namens alertmanager anlegen. Dieses Secret benötigt mindestens einen Data key namens alertmanager.yaml welcher eine komplette Alertmanager Konfiguration beinhaltet. Weiterhin sollten spezielle Annotations gesetzt werden. Die somit erstelle Konfiguration wird beim Anlegen und Updaten des Secrets auf Validität geprüft. Sollten Fehler bei der Validierung festgestellt werden, so wird die Annahme des Secrets verweigert und eine entsprechende Fehlermeldung ausgegeben.

Da die Konfiguration als Secret angelegt werden kann, empfehlen wir Sealed Secrets in Kombination mit gitops Techniken zur Verwaltung zu nutzen. Dadurch werden keine geheimen Informationen in git gespeichert.

Benötigte Annotations

Bitte stellen sie sicher das ihr alertmanager Secret die folgenden Annotations beinhaltet:

replicator.v1.mittwald.de/replication-allowed: "true"
replicator.v1.mittwald.de/replication-allowed-namespaces: "nine-alertmanager-customer"

Schritte zur Erstellund der Konfiguration

  1. Erstellen des Namespace alertmanager-config
$> kubectl create namespace alertmanager-config
  1. Erzeugen sie ein lokales Verzeichnis in dem alle benötigten Dateien gespeichert werden können. Dieses Verzeichnis sollte zumindest eine Datei mit dem Namen alertmanager.yaml beinhalten. In dieser Datei muss sich eine valide Alertmanager Konfiguration befinden. Beispiele befinden sich hier. Sie können auch template Dateien in diesem Verzeichnis abspeichern (die Dateierweiterung sollte dabei .tmpl sein).

  2. Erstellen sie im oben definierten Namespace alertmanager-config ein Kubernetes Secret namens alertmanager welches die benötigten Annotations enthält.

$> export AMDIR=<path-to-your-directory>
$> kubectl create secret generic alertmanager --from-file=$AMDIR --dry-run -o yaml -n alertmanager-config | \
kubectl annotate -f- --dry-run --local -o yaml \
replicator.v1.mittwald.de/replication-allowed=true \
replicator.v1.mittwald.de/replication-allowed-namespaces=nine-alertmanager-customer | \
kubectl apply -f-

Falls sie template Dateien benutzen wollen, stellen Sie bitte sicher dass sich die folgende Direktive in Ihrer alertmanager.yaml Datei befindet:

templates:
- "/etc/alertmanager/config/*.tmpl"

Benutzen von sealed secrets für die Konfiguration

Falls sie ihre Alertmanager Konfiguration mittels gitops verwalten wollen, so empfehlen wir die Nutzung von Sealed Secrets.

Sie können den Secrets Generator auf runway verwenden um ein entsprechendes alertmanager Secret im Namespace alertmanager-config zu erstellen. Das Secret sollte mindestens einen Data key namens alertmanager.yaml beinhalten, welcher eine valide Alertmanager Konfiguration als Wert besitzt. Zusätzliche Data keys können für die Benutzung von template Dateien (bspw. 'slack.tmpl') benutzt werden. Um sicherzustellen, dass der sealed secrets controller die benötigten Annotations hinzufügt, sollte eine 'template' Sektion zum generierten Secret beigefügt werden:

Hier ein Beispiel Secret welches mittels runway erstellt wurde:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: alertmanager
namespace: alertmanager-config
spec:
encryptedData:
alertmanager.yaml: <encrypted data>

Diesem Secret sollten Sie nun noch eine template Sektion hinzufügen:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: alertmanager
namespace: alertmanager-config
spec:
encryptedData:
alertmanager.yaml: <encrypted data>
template:
metadata:
annotations:
replicator.v1.mittwald.de/replication-allowed: "true"
replicator.v1.mittwald.de/replication-allowed-namespaces: "nine-alertmanager-customer"
Úberschreiben von bereits bestehenden Secrets

Falls bereits ein normales Kubernetes Secret namens alertmanager händisch angelegt wurde und dieses nun von einem sealed secret überschrieben werden soll, so muss noch die folgende Annotation an das bereits bestehende Secret angefügt werden:

sealedsecrets.bitnami.com/managed: "true"

Diese können sie mit dem folgenden Befehl anfügen:

kubectl annotate secret alertmanager sealedsecrets.bitnami.com/managed="true" -n alertmanager-config

Falls diese Annotation fehlt, verweigert der Sealed Secrets Controller das Überschreiben des bereits existierenden Secrets.

Alertmanager Beispiel Konfigurationen

1. Senden aller Benachrichtigungen via Email

global:
resolve_timeout: 5m
route:
receiver: "email"
group_by: ["alertname"]
group_wait: 30s
group_interval: 5m
repeat_interval: 1h
routes: []
receivers:
- name: "email"
email_configs:
- to: "monitoring-alerts-list@your-domain.ch"
send_resolved: true
# when using STARTTLS (port 587) this needs to be 'true'
require_tls: false
from: "Alertmanager@your-domain.ch"
smarthost: smtp.your-domain.ch:465
auth_username: "Alertmanager@your-domain.ch"
auth_password: "verysecretsecret"
headers: { Subject: "[Alert] Prometheus Alert Email" }

2. Senden aller kritisch eingestuften Benachrichtigungen via slack. Alle anderen Nachrichten werden via Email versandt. Bitte stellen Sie, bei der Verwendung dieser Konfiguration, sicher, dass alle Ihre Prometheus alerting rules ein severity Label besitzen.

global:
resolve_timeout: 5m
route:
# this specifices the default receiver which will be used if no route matches
receiver: "email"
group_by: ["alertname"]
group_wait: 30s
group_interval: 5m
repeat_interval: 1h
routes:
- receiver: "slack"
match_re:
severity: "[cC]ritical"
receivers:
- name: "email"
email_configs:
- to: "monitoring-alerts-list@your-domain.ch"
send_resolved: true
# when using STARTTLS (port 587) this needs to be 'true'
require_tls: false
from: "alertmanager@your-domain.ch"
smarthost: smtp.your-domain.ch:465
auth_username: "alertmanager@your-domain.ch"
auth_password: "verysecretsecret"
headers: { Subject: "[Alert] Prometheus Alert Email" }
- name: "slack"
slack_configs:
- send_resolved: true
api_url: https://hooks.slack.com/services/s8o3m2e0r8a8n2d/8snx2X983
channel: "#alerts"

3. Senden aller Nachrichten, welche die Produktionsumgebung betreffen via slack. Alle Nachrichten anderer Umgebungen werden verworfen. Bitte stellen Sie hierbei sicher, dass all ihre Prometheus alerting rules ein Label namens environment besitzen.

global:
resolve_timeout: 5m
route:
# this specifices the default receiver which will be used if no route matches
receiver: "devnull"
group_by: ["alertname"]
group_wait: 30s
group_interval: 5m
repeat_interval: 1h
routes:
- receiver: "slack"
match:
environment: production
receivers:
- name: "slack"
slack_configs:
- send_resolved: true
api_url: https://hooks.slack.com/services/s8o3m2e0r8a8n2d/8snx2X983
channel: "#alerts"
- name: devnull

4. Nutzung von Templates um den Inhalt und das Aussehen von Benachrichtigungen anzupassen. Hierzu werden templates in einer Datei namens 'slack.tmpl' definiert und dann in der Konfiguration mittels der template Funktion aufgerufen. Alle Nachrichten werden via slack versandt.

Dateiname: alertmanager.yaml

global:
resolve_timeout: 5m
# THIS LINE IS VERY IMPORTANT AS OTHERWISE YOUR TEMPLATES WILL NOT BE LOADED
templates:
- "/etc/alertmanager/config/*.tmpl"
route:
receiver: "slack"
group_by: ["alertname"]
group_wait: 30s
group_interval: 5m
repeat_interval: 1h
routes: []
receivers:
- name: "slack"
slack_configs:
- send_resolved: true
api_url: https://hooks.slack.com/services/s8o3m2e0r8a8n2d/8snx2X983
channel: "#alerts"
pretext: "{{ .CommonAnnotations.description }}"
text: '{{ template "slack.myorg.text" . }}'

Dateiname: slack.tmpl

{{ define "slack.myorg.text" -}}
{{ range .Alerts -}}
*Alert:* {{ .Labels.alertname }} - `{{ .Labels.severity }}`
*Description:* {{ .Annotations.description }}
*Details:*
{{ range .Labels.SortedPairs -}}
• *{{ .Name }}:* `{{ .Value }}`
{{ end -}}
{{ template "slack.default.text" . }}
{{ end -}}
{{ end -}}