Monitoraggio di vLLM su Kubernetes

Monitorare i pod di vLLM in esecuzione nei cluster di Kubernetes con Instana, implementando un Collector di OpenTelemetry come StatefulSet gestito da Helm. Il collector estrae le metriche di Prometheus dai pod di vLLM, le arricchisce con i metadati di Kubernetes e le inoltra al backend di Instana.

Procedura

  1. Ispezionare un pod vLLM :
    kubectl describe pod <vllm-pod-name> -n <namespace>
  2. Si notino i seguenti valori nell'output:
    Campo di ricerca Descrizione della posizione nel pod Valore di esempio
    Spazio dei nomi Namespace: text-generation
    Etichetta dell'app Labels: app= vllm-server
    Etichetta componente Labels: component= huggingface-vllm
    Porta delle metriche Port: nella sezione "Contenitori" 8000/TCP
  3. Prima di implementare il collector, verificare che vLLM stia rendendo disponibili le metriche:
    kubectl exec -n <namespace> <vllm-pod-name> -- \
      curl http://localhost:<metrics-port>/metrics

    L'output contiene metriche in formato " Prometheus ", quali vllm:*, http_*, e process_*. Se l'endpoint delle metriche non risponde, verificare che vLLM sia stato avviato correttamente e che il numero di porta corrisponda a quello indicato nella descrizione del pod.

  4. Recuperare il nome del cluster:
    kubectl config current-context

    Il collettore associa a ogni metrica i metadati del cluster. Raccogli le seguenti informazioni relative al tuo cluster.

  5. Recupera la versione di Kubernetes :
    kubectl version --short
  6. Recuperare l'UID del cluster, che deriva dall'UID kube-system dello spazio dei nomi:
    kubectl get namespace kube-system -o jsonpath='{.metadata.uid}'
  7. Crea un values.yaml file basandoti sul seguente modello. Sostituisci ogni segnaposto (contrassegnato con <…>) con i valori che hai raccolto nei passaggi precedenti.
    mode: statefulset
    replicaCount: 1
    image:
      repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s
    extraEnvs:
      - name: K8S_NODE_NAME
        valueFrom:
          fieldRef:
            fieldPath: spec.nodeName
    presets:
      kubernetesAttributes:
        enabled: true
        extractAllPodLabels: true
        extractAllPodAnnotations: true
      kubeletMetrics:
        enabled: false
      logsCollection:
        enabled: false
      hostMetrics:
        enabled: false
      kubernetesEvents:
        enabled: true
      clusterMetrics:
        enabled: true
    config:
      extensions:
        health_check:
          endpoint: ${env:MY_POD_IP}:13133
    
      receivers:
        k8s_cluster:
          collection_interval: 10s
        kubeletstats:
          collection_interval: 10s
          auth_type: serviceAccount
          endpoint: "https://${env:K8S_NODE_NAME}:10250"
          insecure_skip_verify: true
          metric_groups:
            - pod
            - node
            - container
        prometheus:
          config:
            scrape_configs:
              - job_name: "prometheus-scrape"
                scrape_interval: 10s
                metrics_path: /metrics
                tls_config:
                  insecure_skip_verify: true
                kubernetes_sd_configs:
                  - role: pod
                    namespaces:
                     names:
                      - <vllm-namespace-name>     # your vLLM namespace, e.g. text-generation
                relabel_configs:
                  - source_labels: [__meta_kubernetes_pod_label_component]
                    regex: <component-label-value> # your component label, e.g. huggingface-vllm
                    action: keep
                  - source_labels: [__meta_kubernetes_pod_phase]
                    regex: Running
                    action: keep
                  - source_labels: [__meta_kubernetes_pod_ip]
                    regex: (.+)
                    target_label: __address__
                    replacement: $1:<vllm-metrics-port>  # your metrics port, e.g. 8000
                  - source_labels: [__meta_kubernetes_pod_name]
                    target_label: k8s_pod
                  - source_labels: [__meta_kubernetes_namespace]
                    target_label: k8s_namespace
    
      processors:
        resource/vllm:
          attributes:
            - key: service.name
              value: vllm
              action: upsert
            - key: service.namespace
              from_attribute: k8s.namespace.name
              action: upsert
            - key: service.instance.id
              from_attribute: k8s.pod.uid
              action: insert
            - key: INSTANA_PLUGIN
              value: vllm
              action: upsert
            - key: vllm.entity.type
              value: vllm
              action: upsert
        resource/k8s:
          attributes:
            - key: k8s.cluster.name
              value: <cluster-name>            # e.g. prod-cluster-01
              action: insert
            - key: k8s.cluster.distribution
              value: <cluster-distribution>    # openshift | eks | gke | aks | kubernetes
              action: insert
            - key: k8s.cluster.managedBy
              value: <cluster-managed-by>      # e.g. CNF, EKS, GKE, AKS
              action: insert
            - key: k8s.cluster.shortName
              value: <cluster-short-name>
              action: insert
            - key: k8s.cluster.fullName
              value: <cluster-full-name>
              action: insert
            - key: k8s.cluster.version
              value: <cluster-version>         # e.g. v1.29.0
              action: insert
            - key: k8s.cluster.uid
              value: <cluster-uid>             # kube-system namespace UID
              action: insert
            - key: INSTANA_PLUGIN
              value: k8s
              action: upsert
        memory_limiter:
          check_interval: 1s
          limit_percentage: 50
          spike_limit_percentage: 10
        k8sattributes:
          auth_type: serviceAccount
          passthrough: false
          extract:
            metadata:
              - k8s.namespace.name
              - k8s.pod.name
              - k8s.pod.uid
              - k8s.deployment.name
              - k8s.node.name
            labels:
              - tag_name: k8s.pod.labels.app
                key: app
                from: pod
              - tag_name: k8s.pod.labels.component
                key: component
                from: pod
        resourcedetection/env:
          detectors:
            - env
        filter/cluster:
          metrics:
            metric:
              - 'resource.attributes["k8s.cluster.uid"] == nil'
        filter/vllm:
          metrics:
            include:
              match_type: regexp
              resource_attributes:
                - key: k8s.pod.labels.component
                  value: <component-label-value>  # same value as the Prometheus relabel_configs regex
        batch: {}
    
      exporters:
        otlphttp:
          endpoint: <otlp-endpoint>  # e.g. https://otlp-grpc-<tenant>.instana.io:4318
          tls:
            insecure: false
          headers:
            x-instana-key: <your-instana-agent-key>
        debug:
          verbosity: detailed
    
      service:
        extensions:
          - health_check
        pipelines:
          metrics:
            receivers:
              - prometheus
            processors:
              - k8sattributes
              - filter/vllm
              - resource/k8s
              - resource/vllm
              - batch
            exporters:
              - debug
              - otlphttp
          metrics/k8s:
            receivers:
              - k8s_cluster
              - kubeletstats
            processors:
              - k8sattributes
              - resource/k8s
              - memory_limiter
              - batch
              - filter/cluster
            exporters:
              - debug
              - otlphttp
    
    clusterRole:
      rules:
        - apiGroups: ['']
          resources:
            - pods
            - namespaces
            - nodes
            - nodes/stats
            - nodes/proxy
            - nodes/metrics
            - endpoints
            - services
            - events
            - resourcequotas
            - replicationcontrollers
          verbs: ['get', 'list', 'watch']
  8. Consultare il manuale di riferimento alla configurazione per verificare di disporre di tutti i valori richiesti. Per l'elenco completo dei segnaposto e per sapere come ottenere ciascun valore, consultare vLLM Kubernetes, la guida di riferimento alla configurazione.
  9. Verifica che il tuo values.yaml file venga visualizzato correttamente:
    helm template my-otel-collector open-telemetry/opentelemetry-collector \
      -f values.yaml \
      --validate

    Prima di continuare, correggi eventuali errori di sintassi segnalati in YAML.

  10. Installare il collettore:
    helm install my-otel-collector open-telemetry/opentelemetry-collector \
      -f values.yaml \
      -n monitoring \
      --create-namespace
  11. Verificare che il pod del collettore sia in esecuzione:
    kubectl get pods -n monitoring -l app.kubernetes.io/name=opentelemetry-collector
  12. Controllare i log del collettore per verificare che quest'ultimo stia acquisendo ed esportando le metriche relative all' vLLM :
    kubectl logs -n monitoring -l app.kubernetes.io/name=opentelemetry-collector --tail=100

    Cerca le voci di log che contengonoScrape succeededoppureMetrics exported successfullySe riscontri errori, consulta la sezione Risoluzione dei problemi relativi al monitoraggio vLLM su Kubernetes.

Risultati

Il Collector di OpenTelemetry è stato implementato e sta raccogliendo le metriche Prometheus dai tuoi pod vLLM. I dati di monitoraggio vengono ora inoltrati al backend di Instana.

Operazioni successive

Una volta che il collector è in esecuzione ed esporta i dati, visualizza le metriche di “ vLLM ” su Instana :

  1. Nell'interfaccia utente di Instana, vai su Infrastruttura > Analizza infrastruttura.
  2. Seleziona OTel vLLMonitor dall'elenco dei tipi di entità.
  3. Fai clic su un'istanza di OTel vLLMonitor per aprire la relativa dashboard.

Il dashboard mostra il throughput dei token, le richieste in esecuzione e in attesa, nonché altre metriche relative all' vLLM e raccolte dai tuoi pod.

Go al pod " Kubernetes " per visualizzare l'utilizzo delle risorse. Il riepilogo del pod mostra l'utilizzo della CPU, la memoria e le metriche del filesystem.

Utilizza la funzione "Upstream/Downstream" sul pod per esaminare i servizi a monte che chiamano il pod " vLLM " e le applicazioni a cui appartengono.