Selbstgehostetes Prometheus und Grafana
Wenn Sie große Sprachmodelle (LLMs) auf GPU-Clustern einsetzen, ist ein detaillierter Einblick in die Leistung Ihres Systems entscheidend. Ein lokaler Überwachungsstack ist für dieses Szenario ideal, insbesondere wenn Sie mit sensiblen Anwendungen arbeiten, bei denen Sie nicht möchten, dass Protokollierungs- und Überwachungsdaten über das Internet an Server von Drittanbietern gesendet werden.
Eine beliebte Kombination von Open-Source-Tools für Observability ist Prometheus und Grafana. Prometheus eignet sich hervorragend zum Sammeln, Speichern und Abfragen von Metriken eines Systems. Grafana kann verwendet werden, um leistungsstarke Dashboards zur Visualisierung dieser Metriken zu erstellen. Dieser Blogbeitrag beschreibt, wie wir beide für einen lokalen Kubernetes-Cluster eingesetzt haben.
Konfiguration
Dieser Abschnitt beschreibt, wie Sie Prometheus und Grafana mit Helm und Kustomize einsetzen. Prometheus kann mit Community Helm Charts bereitgestellt werden. Grafana hingegen bietet
Wir beginnen mit der Erstellung von zwei Ordnern, einen für jede Anwendung: prometheus/
und grafana/
.
Prometheus
Im Ordner prometheus/
erstellen wir eine Datei zum Anpassen der Community Helm Charts, prometheus/kustomize.yml
:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: prometheus
helmCharts:
- name: prometheus
releaseName: prometheus
version: "27.0"
repo: https://prometheus-community.github.io/helm-charts/
Namespace
Um den Namensraum zu erstellen, wird unter dem Ordner prometheus/resources/
eine Datei namens namespace.yml
erstellt:
apiVersion: v1
kind: Namespace
metadata:
name: prometheus
Darauf wird in der prometheus/kustomize.yml
verwiesen:
...
resources:
- resources/namespace.yml
URL
Da das Prometheus Helm-Diagramm prometheus-server als Standarddienstnamen verwendet, können Sie intern über http://prometheus-server.prometheus.svc.cluster.local
darauf zugreifen.
Grafana
Im Ordner grafana/
wird eine Kustomize-Datei für Grafana erstellt, grafana/kustomize.yml
. Hier verweisen wir auf die offiziellen Helm Charts:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: grafana
helmCharts:
- name: grafana
releaseName: grafana
version: "8.13.1"
repo: https://grafana.github.io/helm-charts
Namespace
Um einen Namensraum zu erstellen, wird unter dem Ordner grafana/resources/
eine Datei namens namespace.yml
erstellt:
apiVersion: v1
kind: Namespace
metadata:
name: grafana
Auf diese Datei wird in der Datei grafana/kustomization.yml
verwiesen:
...
resources:
- resources/namespace.yml
Geheimnisse
Grafana erfordert einen Admin-Benutzer und ein Passwort, um konfiguriert zu werden. Natürlich wollen wir nicht, dass diese sensiblen Informationen in unserer Git-Historie auftauchen, also verwenden wir Sealed Secrets, um verschlüsselte Werte zu erstellen. Stellen Sie zunächst sicher, dass Sealed Secrets auf Ihrem Server und auf Ihrem lokalen Gerät installiert ist:
brew install kubeseal yq
Führen Sie dann den folgenden Befehl aus:
kubectl create secret generic admin-password --namespace grafana --dry-run=client -o json --from-literal=username=<your_username_value> --from-literal=password=<your_password_value> | kubeseal --controller-namespace sealed-secrets --controller-name sealed-secrets | yq -p json
Fügen Sie das Ergebnis in grafana/resources/secrets.yml
ein:
kind: SealedSecret
apiVersion: bitnami.com/v1alpha1
metadata:
name: admin-password
namespace: grafana
creationTimestamp: null
spec:
template:
metadata:
name: admin-password
namespace: grafana
creationTimestamp: null
encryptedData:
password: ...
username: ...
Beachten Sie, dass das Passwort und der Benutzername jetzt verschlüsselte Geheimnisse sind.
Dann verweisen Sie auf die Geheimnisse in grafana/kustomization.yml
:
helmCharts:
...
valuesInline:
admin:
existingSecret: admin-password
userKey: username
passwordKey: password
resources:
...
- resources/secrets.yml
Konfigurieren Sie die Datenquelle Prometheus
Um die Daten von Prometheus zu übernehmen, konfigurieren Sie Prometheus als Datenquelle in grafana/kustomization.yml
:
...
helmCharts:
...
valuesInline:
...
datasources:
datasources.yml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus-server.prometheus.svc.cluster.local
Eindringen
Um innerhalb des Clusters auf Grafana zuzugreifen, aktivieren Sie den Ingress und konfigurieren den Host:
helmCharts:
...
valuesInline:
...
ingress:
enabled: true
hosts:
- grafana.my-server.internal
Dauerhafte Speicherung
Um Daten (wie z.B. Dashboards, Benutzerdaten und -konfigurationen, Warnmeldungen und Snapshots) nach einem Neustart der Pods zu erhalten, konfigurieren Sie einen persistenten Speicher. Erstellen Sie zunächst ein Persistent Volume, indem Sie eine Datei grafana/resources/pv.yml
erstellen:
apiVersion: v1
kind: PersistentVolume
metadata:
name: grafana-pv
labels:
model: grafana-pv
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/mnt/data/grafana"
Der Persistent Volume Claim wird in Grafana's Helm Chart grafana/kustomization.yml
konfiguriert:
helmCharts:
...
valuesInline:
...
persistence:
enabled: true
storageClassName: manual
volumeName: grafana-pv
accessModes:
- ReadWriteOnce
size: 1Gi
Beide sind gemäß den minimalen Hardwareanforderungen von Grafana auf 1Gi eingestellt.
Vollständiges Beispiel
Zusammengefasst ergibt dies die folgenden Dateien:
prometheus/
├── kustomization.yml
└── resources
└── namespace.yml
grafana/
├── kustomization.yml
└── resources
├── namespace.yml
├── pv.yml
└── secrets.yml
Prometheus
prometheus/kustomization.yml
:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: prometheus
helmCharts:
- name: prometheus
releaseName: prometheus
version: "27.0"
repo: https://prometheus-community.github.io/helm-charts/
resources:
- resources/namespace.yml
Ressourcen
prometheus/resources/namespace.yml
:
apiVersion: v1
kind: Namespace
metadata:
name: prometheus
Grafana
grafana/kustomization.yml
:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: grafana
helmCharts:
- name: grafana
releaseName: grafana
version: "8.13.1"
repo: https://grafana.github.io/helm-charts
valuesInline:
ingress:
enabled: true
hosts:
- grafana.my-server.internal
admin:
existingSecret: admin-password
userKey: username
passwordKey: password
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus-server.prometheus.svc.cluster.local
persistence:
enabled: true
storageClassName: manual
volumeName: grafana-pv
accessModes:
- ReadWriteOnce
size: 1Gi
resources:
- resources/namespace.yml
- resources/secrets.yml
- resources/pv.yml
Ressourcen
grafana/resources/namespace.yml
:
apiVersion: v1
kind: Namespace
metadata:
name: grafana
grafana/resources/pv.yml
:
apiVersion: v1
kind: PersistentVolume
metadata:
name: grafana-pv
labels:
model: grafana-pv
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/mnt/data/grafana"
grafana/resources/secrets.yml
:
kind: SealedSecret
apiVersion: bitnami.com/v1alpha1
metadata:
name: admin-password
namespace: grafana
creationTimestamp: null
spec:
template:
metadata:
name: admin-password
namespace: grafana
creationTimestamp: null
encryptedData:
password: ...
username: ...
Zugang und Test
In diesem Abschnitt zeigen wir Ihnen, wie Sie den Einsatz von Prometheus und Grafana testen und nutzen können.
Endpunkte für Prometheus
Prometheus funktioniert, indem es Metriken von Endpunkten abruft, die Anwendungen bereitstellen. Woher weiß Prometheus, wo es scrapen soll?
Einige Anwendungen stellen standardmäßig Metadaten über ihre metrischen Endpunkte in ihren Helm Charts bereit. Nehmen Sie zum Beispiel den
Für andere Anwendungen müssen Sie dies selbst konfigurieren. Wir verwenden vLLM, um große Sprachmodelle (LLMs) auf unserem GPU-Cluster einzusetzen. Damit Prometheus weiß, wo vLLM-Metriken abgerufen werden sollen, muss das Helm Chart von vLLM mit den folgenden Metadaten gepatcht werden:
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: vllm
name: vllm-deployment-router
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/metrics"
prometheus.io/port: "8000"
Eine Alternative wäre, auf der Seite von Prometheus zu konfigurieren, wo das Scrapen stattfinden soll. Für vLLM müsste dies zu Ihrer Prometheus-Konfiguration hinzugefügt werden.
Wir haben uns für das Hinzufügen von Metadaten auf der Anwendungsseite entschieden, da es so einfach ist, Scraping hinzuzufügen, wenn eine neue Anwendung bereitgestellt wird. Da die Konfigurationen zentral in Bezug auf die Anwendungen gespeichert werden.
Alternativ können Sie die testFramework
auch erweitern, zum Beispiel mit Lasttests über k6.
Erweiterungen
Um diese Einrichtung zu professionalisieren, können Sie die Prometheus- und Grafana-Server um Folgendes erweitern:
- Erkunden Sie die Prometheus-Konfiguration
- Alerting in Prometheus einrichten
- Konfigurieren Sie CA-Zertifikate für Grafana
- CI/CD für Grafana Dashboards
- Zur Überwachung des LLM-Hostings stellt vLLM seinem Router-Pod nützliche Metriken (wie Token pro Sekunde) zur Verfügung. Diese werden jedoch nicht in Prometheus angezeigt. Eine Möglichkeit, sie offenzulegen, besteht darin, einen Observability-Pod zu erstellen, wie hier vorgeschlagen. Wir empfehlen außerdem, die Bemühungen von vLLM um Beobachtbarkeit zu verfolgen, um zu sehen, ob dieses Problem behoben ist.
Referenzen
Verfasst von

Jetze Schuurmans
Machine Learning Engineer
Jetze is a well-rounded Machine Learning Engineer, who is as comfortable solving Data Science use cases as he is productionizing them in the cloud. His expertise includes: AI4Science, MLOps, and GenAI. As a researcher, he has published papers on: Computer Vision and Natural Language Processing and Machine Learning in general.
Contact