Conformidad de IA de CNCF
La Conformidad de IA de CNCF Kubernetes define un conjunto de capacidades adicionales, APIs y configuraciones que un clúster de Kubernetes DEBE ofrecer, además de la conformidad estándar de CNCF Kubernetes, para ejecutar cargas de trabajo de IA/ML de manera fiable y eficiente.
Esta página muestra cómo cumplir con estos requisitos utilizando RKE2 v1.34.1+rke2r1.
Soporte para la Asignación Dinámica de Recursos (DRA)
DRA es una nueva API que permite solicitudes de recursos más flexibles y detalladas más allá de simples conteos y ha estado disponible de manera general (GA) desde v1.34.
Verifica que todos los recursos de la API resource.k8s.io/v1 DRA estén habilitados ejecutando:
kubectl api-resources --api-group=resource.k8s.io
Salida Esperada:
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
Soporte para la API Gateway
API Gateway representa la próxima generación de APIs de ingreso, balanceo de carga y malla de servicios de Kubernetes.
Para habilitar la API Gateway en RKE2, el clúster debe ser desplegado con Traefik habilitado y su proveedor KubernetesGateway configurado, como se explica en la documentación del Controlador de Ingreso.
Verifica que todos los recursos de la API gateway.networking.k8s.io/v1 Gateway estén habilitados ejecutando:
kubectl api-resources --api-group=gateway.networking.k8s.io/v1
Salida Esperada:
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
Para verificar que Traefik está consumiendo recursos de la API Gateway:
-
Crea una GatewayClass:
apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: traefik spec: controllerName: traefik.io/gateway-controller -
Verifica el estado:
kubectl get gatewayclass traefik -o jsonpath='{.status}'Salida Esperada:
"message":"Handled by Traefik controller","observedGeneration":1,"reason":"Handled","status":"True","type":"Accepted"
Programación en grupo
Una solución de programación en grupo (por ejemplo, Kueue o Volcano) debe estar disponible para su instalación para garantizar una programación de todo o nada para cargas de trabajo de IA distribuidas.
Usaremos Volcano en RKE2 para esta prueba de verificación.
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
La instalación crea tres ampliaciones en el espacio de nombres volcano-system:
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
La verificación está completa, pero realizaremos una prueba funcional. El siguiente paso crea un trabajo de grupo con dos tareas (cada una requiriendo una GPU NVIDIA) en un clúster de dos GPUs:
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
Ambos pods deberían estar en ejecución después de unos segundos.
Para probar la falla de la programación en grupo, modifica el manifiesto para usar minAvailable: 3 y añade una tercera tarea. Reenvía el trabajo:
- 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
Observa que los tres pods permanecen en estado Pendiente. Esto demuestra que la programación en grupo está funcionando como se esperaba.
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 autoscaler
Si la plataforma proporciona un cluster autoscaler o un mecanismo equivalente, debe ser capaz de escalar grupos de nodos específicos de acelerador basándose en pods pendientes. Dado que RKE2 es una distribución de Kubernetes, no proporciona un cluster autoscaler integrado.
A modo de referencia, explicamos cómo usar el autoscaler upstream autoscaler con Azure como ejemplo.
-
Crea un Conjunto de Escala de Máquinas Virtuales (VMSS) con VMs equipadas con GPU.
-
Despliega RKE2 con las siguientes opciones:
disable-cloud-controller: true # Only in rke2-server kubelet-arg: # On both rke2-server and rke2-agent - --cloud-provider=external -
Instala el CCM de Azure:
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 -
Crea el archivo
azure.jsony guárdalo en/etc/kubernetes/azure.json. Asegúrate de que contenga las siguientes dos opciones:"useManagedIdentityExtension": false, "useInstanceMetadata": trueLos nodos desplegados deberían incluir un ProviderID. Verifica esto con:
kubectl get nodes -o yaml | grep ProviderIDEl ProviderID se obtiene de los Metadatos de la instancia. Verifica esto con:
curl -H Metadata:true "http://169.254.169.254/metadata/instance?api-version=2021-02-01" -
Instala el autoscaler upstream.
-
Primero, crea un archivo de configuración
values.yaml, especificando el VMSS del Paso 1 y otros detalles necesarios de Azure. -
Luego, ejecute los siguientes
helmcomandos:helm repo add autoscaler https://kubernetes.github.io/autoscaler helm repo update helm install cluster-autoscaler autoscaler/cluster-autoscaler -f values.yaml
-
-
Cuando se despliega correctamente, el escalador automático supervisa los pods que solicitan un recurso GPU. Si el clúster no puede satisfacer la solicitud, el escalador automático contacta a Azure para aprovisionar automáticamente y añadir un nuevo nodo GPU al clúster.
Escalador automático de pods horizontal
La capacidad de escalar Pods basándose en métricas personalizadas relevantes para cargas de trabajo de IA/ML se logra utilizando el EscaladorAutomáticoDePodsHorizontales (HPA), que se incluye por defecto en Kubernetes.
Para demostrar este requisito, instala una ampliación de Ollama en RKE2. El siguiente manifiesto se utiliza para la verificación:
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"
Aumentar la carga en Ollama elevará la utilización de la GPU al 70%, lo que desencadenará la ampliación de nuevos pods de Ollama.
Métricas de rendimiento del acelerador
Este requisito exige una solución de métricas de acelerador funcional que exponga métricas de rendimiento detalladas a través de un endpoint de métricas estandarizado y legible por máquina. Esta solución debe incluir un conjunto básico de métricas para la utilización por acelerador y el uso de memoria.
Cuando se instala el Operador de GPU de NVIDIA (como se describe en la documentación de Operadores de GPU), se despliegan un nvidia-dcgm-exporter DaemonSet y un Servicio. Consulta este servicio para recopilar las métricas de GPU requeridas, como la utilización del acelerador, el uso de memoria, la temperatura, el uso de energía, etc.
Por ejemplo, si accedes por SSH a un nodo del clúster desde dentro del clúster, mostrará las métricas expuestas utilizando el formato de texto OpenMetrics. La siguiente sección detalla cómo desplegar Prometheus y Grafana para consumirlas.
# 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
Métricas del Servicio de Trabajo e Inferencia de IA
Este requisito exige un sistema capaz de descubrir y recopilar métricas expuestas por cargas de trabajo en un formato estandarizado.
Prometheus y Grafana cumplen con este requisito. Primero, instálalos:
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
Una vez instalados, crea un ServiceMonitor para recopilar métricas de las cargas de trabajo. Como ejemplo, el siguiente manifiesto configura Prometheus para recopilar métricas de DCGM del Operador de GPU de NVIDIA:
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
Después de unos minutos, el panel de Grafana mostrará las métricas de DCGM, como DCGM_FI_DEV_GPU_UTIL.
Acceso seguro a aceleradores
Este requisito exige que el acceso a los aceleradores desde dentro de los contenedores esté debidamente aislado y mediado por Kubernetes. Para lograr esto, instala el Operador de GPU de NVIDIA como se describe en la documentación del Operador de GPU docs.
Después de la instalación, verifica que la configuración del kit de herramientas en /usr/local/nvidia/toolkit/.config/nvidia-container-runtime/config.toml contenga:
accept-nvidia-visible-devices-as-volume-mounts = true
accept-nvidia-visible-devices-envvar-when-unprivileged = false
Asegúrate de que el DaemonSet device-plugin incluya la siguiente variable de entorno:
DEVICE_LIST_STRATEGY: volume-mounts
Si la configuración es correcta, verifica el requisito de aislamiento ejecutando los siguientes tres Pods en un clúster con solo una GPU:
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"
Resultados Esperados (Aislamiento Confirmado):
-
El Pod 1 se ejecuta con éxito y consume la GPU.
-
El Pod 2 no es programado por Kubernetes porque la única GPU disponible en el clúster ya está siendo consumida por el Pod 1.
-
El Pod 3 se ejecuta pero no logra encontrar una GPU disponible, como se ve en los registros.
Este resultado demuestra que el aislamiento de aceleradores está funcionando correctamente.
Operación robusta de CRD y Controlador
Este requisito exige la instalación y el funcionamiento fiable de al menos un Operador de IA complejo con CRDs. La verificación requiere confirmar que los CRDs están registrados y que un Webhook de Admisión rechaza configuraciones inválidas.
Para verificar este requisito, instala el Operador de Entrenamiento de Kubeflow en RKE2. Dado que no hay un gráfico de Helm disponible, utiliza el siguiente comando kubectl como solución alternativa:
kubectl apply -k "github.com/kubeflow/training-operator/manifests/overlays/standalone?ref=v1.8.0"
Verifica que los CRDs estén instalados y que el webhook esté registrado:
$> 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
Prueba la capacidad de rechazo del webhook de admisión intentando aplicar el siguiente manifiesto TFJob inválido (falta el campo de imagen requerido):
# 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;"]
El Webhook de Admisión devuelve el error esperado, confirmando su función:
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
Elimina los comentarios en el ejemplo anterior y vuelve a intentar el trabajo para ver la ampliación exitosa.