CNCF KI-Konformität

Die CNCF Kubernetes KI-Konformität definiert eine Reihe zusätzlicher Fähigkeiten, APIs und Konfigurationen, die ein Kubernetes-Cluster zusätzlich zur standardmäßigen CNCF Kubernetes-Konformität bieten MUSS, um KI/ML-Workloads zuverlässig und effizient auszuführen.

Diese Seite zeigt, wie man diese Anforderungen mit RKE2 v1.34.1+rke2r1 erfüllt.

Unterstützung der dynamischen Ressourcenallokation (DRA)

DRA ist eine neue API, die flexiblere, feinere Ressourcenanforderungen über einfache Zählungen hinaus ermöglicht und seit v1.34 allgemein verfügbar (GA) ist.

Überprüfen Sie, ob alle resource.k8s.io/v1 DRA-API-Ressourcen aktiviert sind, indem Sie Folgendes ausführen:

kubectl api-resources --api-group=resource.k8s.io

Erwartete Ausgabe:

NAME                     SHORTNAMES   APIVERSION           NAMESPACED   KIND
deviceclasses                         resource.k8s.io/v1   false        DeviceClass
resourceclaims                        resource.k8s.io/v1   true         ResourceClaim
resourceclaimtemplates                resource.k8s.io/v1   true         ResourceClaimTemplate
resourceslices                        resource.k8s.io/v1   false        ResourceSlice

Unterstützung der Gateway-API

Gateway-API stellt die nächste Generation von Kubernetes-Ingress-, Lastausgleichs- und Service-Mesh-APIs dar.

Um die Gateway-API in RKE2 zu aktivieren, muss der Cluster mit aktiviertem Traefik bereitgestellt und der KubernetesGateway-Anbieter konfiguriert werden, wie in den Ingress-Controller-Dokumenten erklärt.

Überprüfen Sie, ob alle gateway.networking.k8s.io/v1 Gateway-API-Ressourcen aktiviert sind, indem Sie Folgendes ausführen:

kubectl api-resources --api-group=gateway.networking.k8s.io/v1

Erwartete Ausgabe:

NAME              SHORTNAMES   APIVERSION                          NAMESPACED   KIND
gatewayclasses    gc           gateway.networking.k8s.io/v1        false        GatewayClass
gateways          gtw          gateway.networking.k8s.io/v1        true         Gateway
grpcroutes                     gateway.networking.k8s.io/v1        true         GRPCRoute
httproutes                     gateway.networking.k8s.io/v1        true         HTTPRoute
referencegrants   refgrant     gateway.networking.k8s.io/v1beta1   true         ReferenceGrant

Um zu überprüfen, ob Traefik Gateway-API-Ressourcen verwendet:

  1. Erstellen Sie eine GatewayClass:

    apiVersion: gateway.networking.k8s.io/v1
    kind: GatewayClass
    metadata:
      name: traefik
    spec:
      controllerName: traefik.io/gateway-controller
  2. Überprüfen Sie den Status:

    kubectl get gatewayclass traefik -o jsonpath='{.status}'

    Erwartete Ausgabe:

    "message":"Handled by Traefik controller","observedGeneration":1,"reason":"Handled","status":"True","type":"Accepted"

Gang-Scheduling

Eine Gang-Scheduling-Lösung (z. B. Kueue oder Volcano) muss zur Installation verfügbar sein, um ein All-or-Nothing-Scheduling für verteilte KI-Workloads sicherzustellen.

Wir werden Volcano in RKE2 für diesen Verifizierungstest verwenden.

helm repo add volcano-sh https://volcano-sh.github.io/helm-charts
helm repo update
helm install volcano volcano-sh/volcano -n volcano-system --create-namespace

Die Installation erstellt drei Deployments im volcano-system Namespace:

NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/volcano-admission     1/1     1            1           130m
deployment.apps/volcano-controllers   1/1     1            1           130m
deployment.apps/volcano-scheduler     1/1     1            1           130m

Die Überprüfung ist abgeschlossen, aber wir werden einen Funktionstest durchführen. Der folgende Schritt erstellt einen Gang-Job mit zwei Aufgaben (jeweils mit einer NVIDIA-GPU) auf einem Zwei-GPU-Cluster:

apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: gpu-nbody-gang-job
  namespace: default
spec:
  minAvailable: 2
  schedulerName: volcano

  tasks:
    - name: nbody-task-1
      replicas: 1
      template:
        spec:
          restartPolicy: OnFailure
          runtimeClassName: nvidia
          containers:
            - name: cuda-container-1
              image: nvcr.io/nvidia/k8s/cuda-sample:nbody
              command: ["/bin/bash", "-c"]
              args:
                - "while true; do sleep 5 && cuda-samples/nbody -gpu -benchmark; done"
              resources:
                limits:
                  nvidia.com/gpu: 1

    - name: nbody-task-2
      replicas: 1
      template:
        spec:
          restartPolicy: OnFailure
          runtimeClassName: nvidia
          containers:
            - name: cuda-container-2
              image: nvcr.io/nvidia/k8s/cuda-sample:nbody
              command: ["/bin/bash", "-c"]
              args:
                - "while true; do sleep 5 && cuda-samples/nbody -gpu -benchmark; done"
              resources:
                limits:
                  nvidia.com/gpu: 1

Beide Pods sollten nach wenigen Sekunden laufen.

Um einen Gang-Scheduling-Fehler zu testen, ändern Sie das Manifest, um minAvailable: 3 zu verwenden, und fügen Sie eine dritte Aufgabe hinzu. Reichen Sie den Job erneut ein:

    - name: nbody-task-3
      replicas: 1
      template:
        spec:
          restartPolicy: OnFailure
          runtimeClassName: nvidia
          containers:
            - name: cuda-container-3
              image: nvcr.io/nvidia/k8s/cuda-sample:nbody
              command: ["/bin/bash", "-c"]
              args:
                - "while true; do sleep 5 && cuda-samples/nbody -gpu -benchmark; done"
              resources:
                limits:
                  nvidia.com/gpu: 1

Beobachten Sie, dass die drei Pods im Status "Ausstehend" bleiben. Dies zeigt, dass das Gang-Scheduling wie erwartet funktioniert.

default          gpu-nbody-gang-job-nbody-task-1-0                             0/1     Pending     0          50s
default          gpu-nbody-gang-job-nbody-task-2-0                             0/1     Pending     0          50s
default          gpu-nbody-gang-job-nbody-task-3-0                             0/1     Pending     0          50s

Cluster-Autoskalierer

Wenn die Plattform einen Cluster-Autoskalierer oder einen gleichwertigen Mechanismus bereitstellt, muss er in der Lage sein, Beschleuniger-spezifische Knoten-Gruppen basierend auf ausstehenden Pods zu skalieren. Da RKE2 als Kubernetes-Distribution fungiert, bietet es keinen integrierten Cluster-Autoskalierer.

Zur Referenz erklären wir, wie man den Upstream-Autoskalierer autoscaler mit Azure als Beispiel verwendet.

  1. Erstellen Sie ein Virtual Machine Scale Set (VMSS) mit GPU-ausgestatteten VMs.

  2. Stellen Sie RKE2 mit den folgenden Optionen bereit:

    disable-cloud-controller: true # Only in rke2-server
    kubelet-arg: # On both rke2-server and rke2-agent
    - --cloud-provider=external
  3. Installieren Sie den Azure CCM:

    helm install --repo https://raw.githubusercontent.com/kubernetes-sigs/cloud-provider-azure/master/helm/repo cloud-provider-azure --generate-name --set cloudControllerManager.imageRepository=mcr.microsoft.com/oss/kubernetes --set cloudControllerManager.imageName=azure-cloud-controller-manager --set cloudNodeManager.imageRepository=mcr.microsoft.com/oss/kubernetes --set cloudNodeManager.imageName=azure-cloud-node-manager --set cloudControllerManager.configureCloudRoutes=false --set cloudControllerManager.allocateNodeCidrs=false
  4. Erstellen Sie die azure.json-Datei und speichern Sie sie unter /etc/kubernetes/azure.json. Stellen Sie sicher, dass sie die folgenden zwei Optionen enthält:

      "useManagedIdentityExtension": false,
      "useInstanceMetadata": true

    Die bereitgestellten Knoten sollten eine ProviderID enthalten. Überprüfen Sie dies mit:

    kubectl get nodes -o yaml | grep ProviderID

    Die ProviderID wird aus den Metadaten der Instanz abgerufen. Überprüfen Sie dies mit:

    curl -H Metadata:true "http://169.254.169.254/metadata/instance?api-version=2021-02-01"
  5. Installieren Sie den Upstream-Autoskalierer.

    1. Erstellen Sie zunächst eine values.yaml-Konfigurationsdatei, in der das VMSS aus Schritt 1 und andere notwendige Azure-Details angegeben sind.

    2. Führen Sie die folgenden helm Befehle aus:

      helm repo add autoscaler https://kubernetes.github.io/autoscaler
      helm repo update
      helm install cluster-autoscaler autoscaler/cluster-autoscaler -f values.yaml
  6. Wenn korrekt bereitgestellt, überwacht der Autoscaler Pods, die eine GPU-Ressource anfordern. Wenn der Cluster die Anfrage nicht erfüllen kann, kontaktiert der Autoscaler Azure, um automatisch einen neuen GPU-Knoten zum Cluster bereitzustellen und hinzuzufügen.

Horizontaler Pod-Autoscaler

Die Fähigkeit, Pods basierend auf benutzerdefinierten Metriken, die für AI/ML-Workloads relevant sind, zu skalieren, wird mit dem HorizontalPodAutoscaler (HPA) erreicht, der standardmäßig in Kubernetes enthalten ist.

Um diese Anforderung zu demonstrieren, installieren Sie eine Ollama-Implementierung in RKE2. Das folgende Manifest wird dann zur Überprüfung verwendet:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ollama-hpa
spec:
  scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: ollama
  minReplicas: 1
  maxReplicas: 3
  metrics:
  - type: Object
    object:
      describedObject:
        apiVersion: v1
        kind: Namespace
        name: suse-private-ai
      metric:
        name: gpu_utilization
      target:
        type: AverageValue
        averageValue: "70"

Eine Erhöhung der Last auf Ollama wird die GPU-Auslastung auf 70 % erhöhen, was die Implementierung neuer Ollama-Pods auslöst.

Leistungsmetriken des Beschleunigers

Diese Anforderung verlangt eine funktionale Lösung für Beschleuniger-Metriken, die feingranulare Leistungsmetriken über einen standardisierten, maschinenlesbaren Metrik-Endpunkt bereitstellt. Diese Lösung muss einen Kernsatz von Metriken für die Nutzung pro Beschleuniger und den Speicherverbrauch enthalten.

Wenn der NVIDIA GPU Operator installiert ist (wie in der Dokumentation zu GPU-Operatoren beschrieben), werden ein nvidia-dcgm-exporter DaemonSet und ein Service bereitgestellt. Abfragen Sie diesen Service, um die erforderlichen GPU-Metriken zu sammeln, wie z. B. die Nutzung des Beschleunigers, den Speicherverbrauch, die Temperatur, den Stromverbrauch usw.

Wenn Sie beispielsweise über SSH in einen Cluster-Knoten innerhalb des Clusters zugreifen, werden die Metriken angezeigt, die im OpenMetrics-Textformat bereitgestellt werden. Der folgende Abschnitt beschreibt, wie Prometheus und Grafana bereitgestellt werden, um diese zu konsumieren.

# Get the clusterIP
svcIP=$(kubectl get svc nvidia-dcgm-exporter -n gpu-operator -o jsonpath='{.spec.clusterIP}')
# Get the port
svcPort=$(kubectl get svc nvidia-dcgm-exporter -n gpu-operator -o jsonpath='{.spec.ports[0].port}')
# Output the metrics
curl -sL http://${svcIP}:${svcPort}/metrics

Metriken für AI-Jobs und Inferenzdienste

Diese Anforderung verlangt ein System, das in der Lage ist, Metriken zu entdecken und zu sammeln, die von Workloads in einem standardisierten Format bereitgestellt werden.

Prometheus und Grafana erfüllen diese Anforderung. Zuerst installieren Sie sie:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install prometheus-stack prometheus-community/kube-prometheus-stack \
>   --namespace monitoring \
>   --create-namespace

Nach der Installation erstellen Sie einen ServiceMonitor, um Metriken von Workloads zu sammeln. Als Beispiel konfiguriert das folgende Manifest Prometheus, um DCGM-Metriken vom NVIDIA GPU Operator zu sammeln:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: nvidia-dcgm-monitor
  namespace: monitoring
  labels:
    release: prometheus-stack
spec:
  selector:
    matchLabels:
      app: nvidia-dcgm-exporter
  namespaceSelector:
    matchNames:
      - gpu-operator
  endpoints:
  - port: gpu-metrics
    path: /metrics
    interval: 15s

Nach einigen Minuten zeigt das Grafana-Dashboard die DCGM-Metriken, wie DCGM_FI_DEV_GPU_UTIL.

Sicheren Zugriff auf Beschleuniger

Diese Anforderung schreibt vor, dass der Zugriff auf Beschleuniger aus Containern ordnungsgemäß isoliert und von Kubernetes vermittelt werden muss. Um dies zu erreichen, installieren Sie den NVIDIA GPU Operator, wie in der Dokumentation zum GPU Operator beschrieben docs.

Überprüfen Sie nach der Installation, ob die Toolkit-Konfiguration bei /usr/local/nvidia/toolkit/.config/nvidia-container-runtime/config.toml Folgendes enthält:

accept-nvidia-visible-devices-as-volume-mounts = true
accept-nvidia-visible-devices-envvar-when-unprivileged = false

Stellen Sie sicher, dass das device-plugin DaemonSet die folgende Umgebungsvariable enthält:

DEVICE_LIST_STRATEGY:        volume-mounts

Wenn die Konfiguration korrekt ist, überprüfen Sie die Isolationsanforderung, indem Sie die folgenden drei Pods in einem Cluster mit nur einer GPU ausführen:

apiVersion: v1
kind: Pod
metadata:
  name: nbody-gpu-benchmark1
  namespace: default
spec:
  restartPolicy: OnFailure
  runtimeClassName: nvidia
  containers:
  - name: cuda-container
    image: nvcr.io/nvidia/k8s/cuda-sample:nbody
    command: ["/bin/bash", "-c"]
    args:
      - "while true; do sleep 5 && cuda-samples/nbody -gpu -benchmark; done"
    resources:
      limits:
        nvidia.com/gpu: 1
apiVersion: v1
kind: Pod
metadata:
  name: nbody-gpu-benchmark2
  namespace: default
spec:
  restartPolicy: OnFailure
  runtimeClassName: nvidia
  containers:
  - name: cuda-container2
    image: nvcr.io/nvidia/k8s/cuda-sample:nbody
    command: ["/bin/bash", "-c"]
    args:
      - "while true; do sleep 5 && cuda-samples/nbody -gpu -benchmark; done"
    resources:
      limits:
        nvidia.com/gpu: 1
apiVersion: v1
kind: Pod
metadata:
  name: nbody-gpu-benchmark3
  namespace: default
spec:
  restartPolicy: OnFailure
  runtimeClassName: nvidia
  containers:
  - name: cuda-container3
    image: nvcr.io/nvidia/k8s/cuda-sample:nbody
    command: ["/bin/bash", "-c"]
    args:
      - "while true; do sleep 5 && cuda-samples/nbody -gpu -benchmark; done"

Erwartete Ergebnisse (Isolation bestätigt):

  • Pod 1 läuft erfolgreich und nutzt die GPU.

  • Pod 2 wird von Kubernetes nicht geplant, da die einzige im Cluster verfügbare GPU bereits von Pod 1 genutzt wird.

  • Pod 3 läuft, kann jedoch keine verfügbare GPU finden, wie in den Protokollen zu sehen ist.

Dieses Ergebnis zeigt, dass die Isolierung der Beschleuniger korrekt funktioniert.

Robuster Betrieb von CRDs und Controllern

Diese Anforderung schreibt die Installation und zuverlässige Funktion von mindestens einem komplexen KI-Operator mit CRDs vor. Die Überprüfung erfordert die Bestätigung, dass CRDs registriert sind und dass ein Admission Webhook ungültige Konfigurationen ablehnt.

Um diese Anforderung zu überprüfen, installieren Sie den Kubeflow Training Operator in RKE2. Da kein Helm-Chart verfügbar ist, verwenden Sie den folgenden kubectl Befehl als Workaround:

kubectl apply -k "github.com/kubeflow/training-operator/manifests/overlays/standalone?ref=v1.8.0"

Überprüfen Sie, ob die CRDs installiert sind und der Webhook registriert ist:

$> kubectl get crds | grep kubeflow
mpijobs.kubeflow.org                                       2025-10-24T13:04:27Z
mxjobs.kubeflow.org                                        2025-10-24T13:04:27Z
paddlejobs.kubeflow.org                                    2025-10-24T13:04:28Z
pytorchjobs.kubeflow.org                                   2025-10-24T13:04:28Z
tfjobs.kubeflow.org                                        2025-10-24T13:04:29Z
xgboostjobs.kubeflow.org                                   2025-10-24T13:04:29Z

$> kubectl get validatingwebhookconfigurations
validator.training-operator.kubeflow.org   5          10m

$> kubectl get pods -n kubeflow
NAME                                READY   STATUS    RESTARTS   AGE
training-operator-f7d4b59f6-vdnh9   1/1     Running   0          9m54s

Testen Sie die Ablehnungsfähigkeit des Admission Webhooks, indem Sie versuchen, das folgende ungültige TFJob-Manifest anzuwenden (das erforderliche Bildfeld fehlt):

# saved as invalid-tfjob.yaml
apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
  name: tfjob-invalid-test
spec:
  tfReplicaSpecs:
    Chief:
      replicas: 1
      template:
        spec:
          containers:
            - name: tensorflow
              # INTENTIONAL ERROR: Missing the 'image' field
              # image: tensorflow/tensorflow:latest
              # command: ["/bin/bash", "-c"]
              # args: ["echo 'Chief running'; sleep 10;"]

Der Admission Webhook gibt den erwarteten Fehler zurück und bestätigt damit seine Funktion:

Error from server (Forbidden): error when creating "invalid-tfjob.yaml": admission webhook "validator.tfjob.training-operator.kubeflow.org" denied the request: spec.tfReplicaSpecs[Chief].template.spec.containers[0].image: Required value: must be required

Entfernen Sie die Kommentare im vorherigen Beispiel und versuchen Sie den Job erneut, um eine erfolgreiche Bereitstellung zu sehen.