Blog

Einrichten eines lokalen Langfuse-Servers mit Kubernetes zur Verfolgung von Agentic-Systemen

Jetze Schuurmans

Aktualisiert Oktober 14, 2025
5 Minuten

Selbst-Hosting von Langfuse mit Kubernetes

Ein lokaler GPU-Cluster ist ideal für die Entwicklung sensibler LLM-Anwendungen. Wenn Sie an sensiblen Anwendungen arbeiten, möchten Sie nicht, dass die Protokollierung und Überwachung über das Internet an einen von einer dritten Partei verwalteten Server gesendet wird.

Langfuse ist ein großartiges Open-Source-Framework für die Verwaltung von Traces, Evals, Prompt-Management und Metriken zur Fehlersuche und Verbesserung Ihrer LLM-Anwendung. Dieser Blogbeitrag beschreibt, wie wir unseren selbst gehosteten Langfuse-Server für einen lokalen GPU-Cluster eingerichtet haben.

Unser Stapel

Bevor wir einsteigen, möchten wir Ihnen die Tools vorstellen, die wir für die Einrichtung eines lokalen Langfuse-Servers verwenden:

  • Helm: Diagramme für die Kubernetes-Konfiguration
  • Anpassen: So ändern Sie die Diagramme
  • Geheimnis-Generator: Zum Erstellen und Verwalten von Geheimnissen
  • Traefik: Eingehenden Verkehr umleiten
  • Pihole: DNS-Server für Filterung auf DNS-Ebene

Konfiguration

Langfuse stellt in seinem Repo ein Helm-Diagramm und ein minimales Installationsbeispiel zur Verfügung. In diesem Abschnitt erfahren Sie, wie Sie diese anpassen, um mit dem oben erwähnten Stack zu arbeiten.

Anpassen

Wir beginnen mit dem Verweis auf die Steuerkarte in unserem kustomization.yml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: langfuse

helmCharts:
  - name: langfuse
    releaseName: langfuse
    version: "1.2.5"
    repo: https://langfuse.github.io/langfuse-k8s
    namespace: langfuse

Namespace

Um einen Namensraum zu erstellen, wird unter dem Ordner resources/ eine Datei namens namespace.yml erstellt:

apiVersion: v1
kind: Namespace
metadata:
  name: langfuse

Diese Datei wird referenziert, indem Sie folgendes an die kustomization.yml anhängen:

...
resources:
  - resources/namespace.yml

Geheimnisse

Als nächstes legen wir obligatorische Geheimnisse für langfuse und die Dienstleistungen langfuse hängt ab von (postgresql, redis, clickhouse und minio) im kustomization.yml:

...
helmCharts:
  - name: langfuse
    ...
    valuesInline: 
      langfuse:
        ...
        salt:
          secretKeyRef:
            name: langfuse-salt
            key: salt
        nextauth:
          secret:
            secretKeyRef:
              name: langfuse-nextauth
              key: encryption-key
      postgresql:
        auth:
          existingSecret: langfuse-postgresql
          secretKeys:
            userPasswordKey: postgres-password
            adminPasswordKey: postgres-password
      redis:
        auth:
          existingSecret: langfuse-redis
          existingSecretPasswordKey: password
      clickhouse:
        auth:
          existingSecret: langfuse-clickhouse
          existingSecretKey: password
      s3:
        deploy: true
        bucket: langfuse
        endpoint: http://langfuse-s3:9000
        forcePathStyle: true
        auth:
          existingSecret: langfuse-minio
          rootUserSecretKey: user
          rootPasswordSecretKey: password
    ...

Wir verwenden kubernetes-secret-generator, um Geheimnisse in resources/secrets.yml zu verwalten:

apiVersion: v1
kind: Secret
metadata:
  name: langfuse-postgresql
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: postgres-password
    secret-generator.v1.mittwald.de/encoding: hex
    secret-generator.v1.mittwald.de/length: "32"
---
...

Dies wird für alle Geheimnisse wiederholt, auf die in kustomization.yml verwiesen wird, wobei ein Benutzer für minio hinzugefügt wird:

...
---
apiVersion: v1
kind: Secret
metadata:
  name: langfuse-minio
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: password
    secret-generator.v1.mittwald.de/encoding: base64
    secret-generator.v1.mittwald.de/length: "32"
data:
  user: bWluaW8=

Die Datei secrets wird unter resources in der kustomization.yml referenziert, ähnlich wie die Namespaces:

resources:
  ...
  - resources/secrets.yml 

Ingress konfigurieren - Traefik

Damit der lokale Datenverkehr unseren selbst gehosteten Langfuse-Server erreichen kann, wird die Ingress-Konfiguration an langfuse in der kustomization.yml übergeben:

      langfuse:
        ingress: 
          enabled: true
          classname: traefik
          hosts:
            - host: langfuse.my-server.internal
              paths:
                - path: /
                  pathType: Prefix
      ...

Traefik konfiguriert den Ingress so, dass er von langfuse.my-server.internal zu langfuse.langfuse.svc.cluster.local führt.

Vollständiges Beispiel

Zusammengefasst ergibt dies die folgenden Dateien:

langfuse/
├── kustomization.yml
└── resources
    ├── namespace.yml
    └── secrets.yml

kustomization.yml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: langfuse

helmCharts:
  - name: langfuse
    releaseName: langfuse
    version: "1.2.5"
    repo: https://langfuse.github.io/langfuse-k8s
    namespace: langfuse
    valuesInline:
      langfuse:
        ingress:
          enabled: true
          classname: traefik
          hosts:
            - host: langfuse.my-server.internal
              paths:
                - path: /
                  pathType: Prefix
        salt:
          secretKeyRef:
            key: salt
            name: langfuse-salt
        nextauth:
          secret:
            secretKeyRef:
              key: key
              name: langfuse-nextauth
      postgresql:
        port: 5432
        auth:
          existingSecret: langfuse-postgresql
          secretKeys:
            userPasswordKey: postgresql-password
            adminPasswordKey: postgresql-password
      redis:
        auth:
          existingSecret: langfuse-redis
          existingSecretPasswordKey: redis-password
      clickhouse:
        auth:
          existingSecret: langfuse-clickhouse
          existingSecretKey: clickhouse-password
      s3:
        deploy: true
        bucket: langfuse
        endpoint: http://langfuse-s3:9000
        forcePathStyle: true
        auth:
          existingSecret: langfuse-minio
          rootUserSecretKey: user
          rootPasswordSecretKey: minio-password

resources:
  - resources/namespace.yml
  - resources/secrets.yml

resources/namespace.yml:

apiVersion: v1
kind: Namespace
metadata:
  name: langfuse

resources/secrets.yml:

apiVersion: v1
kind: Secret
metadata:
  name: langfuse-salt
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: salt
    secret-generator.v1.mittwald.de/encoding: base64
    secret-generator.v1.mittwald.de/length: "32"
---
apiVersion: v1
kind: Secret
metadata:
  name: langfuse-nextauth
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: key
    secret-generator.v1.mittwald.de/encoding: base64
    secret-generator.v1.mittwald.de/length: "32"
---
apiVersion: v1
kind: Secret
metadata:
  name: langfuse-postgresql
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: postgresql-password
    secret-generator.v1.mittwald.de/encoding: hex
    secret-generator.v1.mittwald.de/length: "32"
---
apiVersion: v1
kind: Secret
metadata:
  name: langfuse-redis
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: redis-password
    secret-generator.v1.mittwald.de/encoding: base64
    secret-generator.v1.mittwald.de/length: "32"
---
apiVersion: v1
kind: Secret
metadata:
  name: langfuse-clickhouse
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: clickhouse-password
    secret-generator.v1.mittwald.de/encoding: base64
    secret-generator.v1.mittwald.de/length: "32"
---
apiVersion: v1
kind: Secret
metadata:
  name: langfuse-minio
  annotations:
    secret-generator.v1.mittwald.de/autogenerate: minio-password
    secret-generator.v1.mittwald.de/encoding: base64
    secret-generator.v1.mittwald.de/length: "32"
data:
  user: bWluaW8=

Zugang und Test

Dank Traefik kann auf Langfuse über das interne Netzwerk des Kubernetes-Clusters zugegriffen werden: http://langfuse.my-server.internal

App

Wenn Sie sich mit Langfuse verbinden, z.B. wenn Sie Traces von Ihrer Agentic-App protokollieren möchten, setzen Sie die env-Variable auf dieselbe URL:

LANGFUSE_HOST="http://langfuse.my-server.internal"

UI

In der Benutzeroberfläche von Langfuse können Sie eine Organisation, ein Projekt und API-Schlüssel erstellen. Um von Ihrem lokalen Gerät aus auf die Benutzeroberfläche zuzugreifen, nutzen wir einen vorhandenen DNS-Server(Pihole) und eine VPN-Einrichtung(Tailscale). Um auf Langfuse zuzugreifen, müssen Sie lediglich einen DNS-Eintrag hinzufügen.

DNS-Eintrag

Der DNS-Eintrag wird zu kustomize.yml von Pihole hinzugefügt:

helmCharts:
  - name: pihole
    releaseName: pihole
    version: "v2.24.0"
    repo: https://mojo2600.github.io/pihole-kubernetes/
    valuesInline:
      dnsmasq:
        customDnsEntries:
          ...
          - address=/langfuse.my-server.internal/100.74.16.73
          ...

Jetzt kann auf Langfuse von einem lokalen Gerät aus zugegriffen werden: http://langfuse.my-server.internal. Nachdem Sie eine Organisation und ein Projekt erstellt haben, können Sie die API-Schlüssel (LANGFUSE_SECRET_KEY, LANGFUSE_PUBLIC_KEY) in der Benutzeroberfläche erstellen.

Test über Python

Um die Bereitstellung zu testen, starten Sie einen temporären Container:

kubectl run langfuse-test --image=python:3.12-slim-bookworm -n langfuse --rm -it -- /bin/bash

Innerhalb dieses Containers installieren Sie das Python-Paket langfuse:

pip install langfuse

Exportieren Sie die Umgebungsvariablen:

export LANGFUSE_HOST=http://langfuse.my-server.internal
export LANGFUSE_SECRET_KEY=sk-lf-...
export LANGFUSE_PUBLIC_KEY=pk-lf-...

Führen Sie den folgenden Python-Code aus:

from langfuse import observe

@observe()
def fn():
    pass

@observe()
def main():
    fn()

main()

⚠️ Beachten Sie, dass es ab v3 einfach from langfuse heißt, statt from langfuse.decorators in v2.

Wenn alles erfolgreich verlaufen ist, sollten die Spuren jetzt in der Benutzeroberfläche erscheinen: ./images/langfuse-ui-traces.png

Erweiterungen

Um diese Einrichtung zu professionalisieren, kann der Langfuse-Server um folgende Funktionen erweitert werden:

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

Let’s discuss how we can support your journey.