Sarcini de lucru AI și GPU pe Kubernetes: Plugin de dispozitiv și joburi de instruire
În 2026, 66% dintre clusterele de inferență AI rulează pe Kubernetes (CNCF Survey 2026). Motivul Este simplu: Kubernetes rezolvă cele mai grele probleme operaționale ale sarcinilor de lucru AI - programarea scalare inteligentă a GPU, scalare elastică a joburilor de formare, integrare cu stocare distribuită pentru seturi de date, reîncercare automată în cazul eșecului nodului. Dar configurarea Kubernetes pentru i Sarcina de lucru GPU necesită abilități specifice care depășesc cu mult implementarea uneia normale aplicație web.
În acest articol vom vedea cum să configurați Plugin-uri pentru dispozitive NVIDIA pentru expuneți GPU-urile la cluster, cum să programați Joburi de instruire distribuite cu PyTorch și TensorFlow, cum se utilizează Karpenter pentru a face scalarea punctului de GPU (reducerea costurilor cu 40-70%) și modele pentru a optimiza utilizarea GPU în sarcinile de lucru de inferență în producție.
Ce vei învăța
- Instalarea și configurarea NVIDIA Device Plugin pentru Kubernetes
- Programarea podurilor cu cererea GPU (nvidia.com/gpu resource)
- Instruire distribuită cu PyTorchJob și TFJob (Kubeflow Training Operator)
- Karpenter NodePool pentru furnizarea automată a nodurilor GPU spot
- Time-slicing GPU pentru a partaja GPU-uri între mai multe poduri
- MIG (Multi-Instance GPU) pentru partiția GPU A100/H100
- Monitorizare GPU cu DCGM Exporter și Grafana
- Model pentru inferență cu randament ridicat cu TorchServe pe K8s
Arhitectura GPU pe Kubernetes
Kubernetes nu cunoaște în mod nativ GPU-urile. GPU-urile sunt expuse clusterului prin intermediul Cadrul de plugin pentru dispozitiv: un DaemonSet care rulează pe fiecare nod cu GPU, se înregistrează cu kubelet și gestionează alocarea GPU-urilor către containere. The NVIDIA Device Plugin este cea mai populară implementare a acestui cadru.
Instalarea NVIDIA Device Plugin
# Pre-requisiti: NVIDIA GPU drivers installati sui nodi
# Verifica driver sui nodi
kubectl get nodes -l accelerator=nvidia
kubectl describe node gpu-node-1 | grep -i nvidia
# Installa NVIDIA Device Plugin con Helm
helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo update
helm install nvdp nvdp/nvidia-device-plugin \
--namespace kube-system \
--version 0.16.0 \
--set failOnInitError=false
# Oppure con manifest diretto
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.16.0/deployments/static/nvidia-device-plugin.yml
# Verifica che le GPU siano visibili nel cluster
kubectl get nodes -o json | jq '.items[].status.allocatable | select(."nvidia.com/gpu" != null)'
# Output: { "nvidia.com/gpu": "8" } per un nodo con 8 GPU A100
Instalarea operatorului GPU NVIDIA (abordare recomandată)
Pentru clusterele aflate în producție, the Operator GPU de NVIDIA gestionează automat toate componentele necesare: drivere, pluginuri pentru dispozitive, rulare container, Exportator DCGM pentru monitorizare:
# Installa GPU Operator
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
helm install gpu-operator nvidia/gpu-operator \
--namespace gpu-operator \
--create-namespace \
--version v24.9.0 \
--set driver.enabled=true \
--set mig.strategy=single \
--set dcgmExporter.enabled=true \
--set dcgmExporter.serviceMonitor.enabled=true
# Verifica installazione
kubectl get pods -n gpu-operator
# Attendi che tutti i pod siano Running
kubectl wait --for=condition=ready pod -l app=nvidia-device-plugin-daemonset -n gpu-operator --timeout=300s
# Verifica GPU allocabili
kubectl describe node gpu-node-1 | grep -A 5 "Allocatable:"
# nvidia.com/gpu: 8
Programarea podurilor cu GPU
Odată ce pluginul dispozitivului este activ, puteți solicita GPU-uri în manifeste ca oricare altă resursă Kubernetes. Diferența: nu folosesti cereri, ci doar limite pentru GPU-uri (Kubernetes garantează întotdeauna exact numărul de GPU-uri necesare).
# pod-gpu-basic.yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-test
spec:
restartPolicy: OnFailure
containers:
- name: inference
image: nvcr.io/nvidia/pytorch:24.01-py3
command: ["python3", "-c"]
args:
- |
import torch
print(f"CUDA available: {torch.cuda.is_available()}")
print(f"GPU count: {torch.cuda.device_count()}")
print(f"GPU name: {torch.cuda.get_device_name(0)}")
x = torch.rand(1000, 1000).cuda()
print(f"Tensor on GPU: {x.device}")
resources:
limits:
nvidia.com/gpu: "1" # richiedi 1 GPU
memory: "16Gi"
cpu: "4"
requests:
memory: "16Gi"
cpu: "4"
volumeMounts:
- name: model-storage
mountPath: /models
volumes:
- name: model-storage
persistentVolumeClaim:
claimName: model-pvc
nodeSelector:
accelerator: "nvidia-a100" # schedule solo su nodi A100
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
Training distribuit cu Kubeflow Training Operator
Antrenarea modelelor mari necesită adesea mai multe GPU-uri pe mai multe noduri. The Operator de formare Kubeflow gestionează posturi de instruire distribuite cu PyTorchJob, TFJob, MXJob și MPIJob. Instalați mai întâi operatorul:
# Installa Training Operator
kubectl apply -k "github.com/kubeflow/training-operator/manifests/overlays/standalone?ref=v1.8.0"
# Verifica
kubectl get pods -n kubeflow
kubectl get crd | grep kubeflow
PyTorchJob pentru Multi-GPU Multi-Node Training
# pytorch-distributed-training.yaml
apiVersion: kubeflow.org/v1
kind: PyTorchJob
metadata:
name: llm-finetuning-job
namespace: ml-training
spec:
pytorchReplicaSpecs:
Master:
replicas: 1
restartPolicy: OnFailure
template:
spec:
containers:
- name: pytorch
image: company.registry.io/training:llm-v2.1
command:
- python3
- -m
- torch.distributed.run
- --nproc_per_node=8
- --nnodes=4
- --node_rank=$(RANK)
- --master_addr=$(MASTER_ADDR)
- --master_port=23456
- train_llm.py
- --model=llama-7b
- --dataset=/data/training_set
- --batch-size=32
- --epochs=3
- --output=/models/finetuned
env:
- name: NCCL_DEBUG
value: "INFO"
- name: NCCL_SOCKET_IFNAME
value: "eth0"
resources:
limits:
nvidia.com/gpu: "8"
memory: "120Gi"
cpu: "32"
requests:
memory: "120Gi"
cpu: "32"
volumeMounts:
- name: training-data
mountPath: /data
- name: model-output
mountPath: /models
- name: shm
mountPath: /dev/shm
volumes:
- name: training-data
persistentVolumeClaim:
claimName: training-dataset-pvc
- name: model-output
persistentVolumeClaim:
claimName: model-output-pvc
- name: shm
emptyDir:
medium: Memory
sizeLimit: "64Gi" # shared memory per NCCL
nodeSelector:
accelerator: "nvidia-a100-80gb"
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
Worker:
replicas: 3 # 3 worker + 1 master = 4 nodi, 32 GPU totali
restartPolicy: OnFailure
template:
spec: # stesso spec del Master...
containers:
- name: pytorch
image: company.registry.io/training:llm-v2.1
resources:
limits:
nvidia.com/gpu: "8"
memory: "120Gi"
cpu: "32"
Karpenter pentru Spot GPU Node Provisioning
GPU-urile sunt cea mai scumpă resursă din cloud. Instanțele GPU spot costă cu 60-70% mai puțin comparativ cu la cerere. Karpenter gestionează furnizarea automată de noduri GPU spot, cu revenire la cerere în caz de întrerupere:
# karpenter-gpu-nodepool.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-spot
spec:
template:
metadata:
labels:
role: gpu-worker
accelerator: nvidia
spec:
nodeClassRef:
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
name: gpu-nodeclass
requirements:
# Tipologie di istanze GPU AWS
- key: node.kubernetes.io/instance-type
operator: In
values:
- p4d.24xlarge # 8x A100 80GB
- p3.8xlarge # 4x V100
- g5.12xlarge # 4x A10G
- g4dn.12xlarge # 4x T4
# Preferisci spot
- key: karpenter.sh/capacity-type
operator: In
values:
- spot
- on-demand # fallback
- key: kubernetes.io/os
operator: In
values:
- linux
taints:
- key: nvidia.com/gpu
value: "true"
effect: NoSchedule
limits:
nvidia.com/gpu: 256 # max 256 GPU totali nel cluster
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30m # rimuovi nodi GPU spot quando il job finisce
---
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: gpu-nodeclass
spec:
amiFamily: AL2
role: KarpenterNodeRole
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "my-cluster"
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "my-cluster"
instanceStorePolicy: RAID0 # usa i dischi NVMe locali per storage temporaneo
userData: |
#!/bin/bash
# Installa NVIDIA drivers al primo boot
/etc/eks/bootstrap.sh my-cluster
nvidia-smi # verifica GPU disponibili
GPU Time-slicing: Partajați un GPU între mai multe poduri
Pentru sarcini ușoare de inferență sau dezvoltare, un întreg GPU este adesea irosit. The GPU time-slicing vă permite să partajați un GPU fizic între mai multe poduri, fiecare dintre ele vede un „GPU virtual” cu o porțiune din timpul de calcul:
# gpu-time-slicing-config.yaml
# Configura il Device Plugin per time-slicing
apiVersion: v1
kind: ConfigMap
metadata:
name: time-slicing-config
namespace: gpu-operator
data:
any: |-
version: v1
flags:
migStrategy: none
sharing:
timeSlicing:
renameByDefault: false
failRequestsGreaterThanOne: false
resources:
- name: nvidia.com/gpu
replicas: 4 # ogni GPU fisica diventa 4 "GPU" logiche
---
# Applica il config all'operator
kubectl patch clusterpolicy gpu-cluster-policy \
-n gpu-operator \
--type merge \
-p '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config"}}}}'
# Verifica: ogni nodo con 1 GPU A100 ora mostra 4 GPU allocabili
kubectl describe node gpu-node-1 | grep nvidia.com/gpu
# Allocatable:
# nvidia.com/gpu: 4
# Pod che usa 1/4 di GPU
apiVersion: v1
kind: Pod
metadata:
name: inference-small
spec:
containers:
- name: model-server
image: company.registry.io/inference:v1
resources:
limits:
nvidia.com/gpu: "1" # ottiene 1/4 della GPU fisica
MIG: GPU cu mai multe instanțe pentru A100 și H100
Suport pentru GPU-uri NVIDIA A100 și H100 MIG (GPU cu mai multe instanțe), că partiționați GPU-ul în instanțe hardware izolate (nu doar partajarea timpului). Fiecare instanță MIG are memorie și calcul garantate și nu interferează cu celelalte:
# Configura MIG sul nodo (eseguito sul nodo GPU, non da kubectl)
# Richiede: driver NVIDIA >= 525, GPU A100 o H100
# Abilita MIG mode sulla GPU
sudo nvidia-smi -mig 1
# Crea 7 istanze MIG da 1/7 di A100 (1g.10gb)
sudo nvidia-smi mig -cgip -p 0,9 # Profile 9 = MIG 1g.10gb
# Verifica istanze create
sudo nvidia-smi mig -lgi
# +-------------------------------------------------------+
# | GPU instances: |
# | GPU Name Profile Instance Placement |
# | ID ID Start:Size |
# |=======================================================|
# | 0 MIG 1g.10gb 9 1 0:1 |
# | 0 MIG 1g.10gb 9 2 1:1 |
# | 0 MIG 1g.10gb 9 3 2:1 |
# ... (7 istanze totali)
# Nel cluster Kubernetes, configurare MIG Strategy nel GPU Operator
kubectl patch clusterpolicy gpu-cluster-policy \
-n gpu-operator \
--type json \
-p '[{"op":"replace","path":"/spec/mig/strategy","value":"mixed"}]'
# Pod che richiede specifica istanza MIG
apiVersion: v1
kind: Pod
metadata:
name: inference-mig
spec:
containers:
- name: model
image: nvcr.io/nvidia/pytorch:24.01-py3
resources:
limits:
nvidia.com/mig-1g.10gb: "1" # richiedi 1 istanza MIG 1g.10gb
Monitorizare GPU cu DCGM Exporter
Monitorizarea GPU este esențială pentru a înțelege dacă joburile de formare sunt eficiente și pentru FinOps. DCGM Exporter expune valorile GPU lui Prometheus:
# DCGM Exporter viene installato automaticamente con GPU Operator
# Verifica che le metriche siano disponibili
kubectl port-forward svc/gpu-operator-dcgm-exporter 9400:9400 -n gpu-operator &
curl -s localhost:9400/metrics | grep DCGM_FI
# Metriche chiave da monitorare:
# DCGM_FI_DEV_GPU_UTIL - utilizzo GPU (0-100%)
# DCGM_FI_DEV_MEM_COPY_UTIL - utilizzo memoria GPU
# DCGM_FI_DEV_FB_USED - memoria GPU usata (MB)
# DCGM_FI_DEV_POWER_USAGE - consumo energetico (W)
# DCGM_FI_DEV_SM_CLOCK - clock streaming multiprocessor
# DCGM_FI_DEV_GPU_TEMP - temperatura GPU
# Alert: GPU sottoutilizzata (< 50% per 30 minuti = spreco)
- alert: GPUUnderutilized
expr: DCGM_FI_DEV_GPU_UTIL < 50
for: 30m
labels:
severity: warning
annotations:
summary: "GPU {{ $labels.gpu }} sul nodo {{ $labels.Hostname }} utilization < 50%"
description: "Valuta se il job puo essere terminato o ottimizzato"
# Dashboard Grafana: importa ID 12239 (NVIDIA DCGM Exporter Dashboard)
Implementarea modelelor pentru inferență cu TorchServe
Pentru deducerea producției, aveți nevoie de un server model care se ocupă de echilibrarea sarcinii inclusiv replicarea modelelor multiple, loturile de solicitări și versiunea. TorchServe și soluția oficială PyTorch:
# torchserve-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: model-inference
namespace: ml-inference
spec:
replicas: 3 # 3 replica per alta disponibilita
selector:
matchLabels:
app: model-inference
template:
metadata:
labels:
app: model-inference
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8082" # TorchServe metrics port
spec:
containers:
- name: torchserve
image: pytorch/torchserve:0.11.0-gpu
args:
- torchserve
- --start
- --model-store=/models
- --models=text-classifier=bert-classifier.mar
- --ts-config=/config/config.properties
ports:
- containerPort: 8080 # inference API
- containerPort: 8081 # management API
- containerPort: 8082 # metrics
resources:
limits:
nvidia.com/gpu: "1"
memory: "16Gi"
cpu: "4"
requests:
memory: "8Gi"
cpu: "2"
readinessProbe:
httpGet:
path: /ping
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
livenessProbe:
httpGet:
path: /ping
port: 8080
initialDelaySeconds: 120
periodSeconds: 30
volumeMounts:
- name: model-store
mountPath: /models
- name: ts-config
mountPath: /config
volumes:
- name: model-store
persistentVolumeClaim:
claimName: model-store-pvc
- name: ts-config
configMap:
name: torchserve-config
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: torchserve-config
namespace: ml-inference
data:
config.properties: |
inference_address=http://0.0.0.0:8080
management_address=http://0.0.0.0:8081
metrics_address=http://0.0.0.0:8082
number_of_gpu=1
batch_size=32
max_batch_delay=100 # ms: attendi fino a 100ms per fare batching
max_response_size=6553500
install_py_dep_per_model=true
---
# HPA basato su latenza con KEDA (event-driven autoscaling)
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: inference-scaler
namespace: ml-inference
spec:
scaleTargetRef:
name: model-inference
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring.svc:9090
metricName: torchserve_queue_latency_microseconds
threshold: "100000" # 100ms di coda = scala up
query: avg(torchserve_queue_latency_microseconds{model_name="bert-classifier"})
Cele mai bune practici pentru sarcinile de lucru AI pe Kubernetes
Optimizarea costurilor GPU
- Loc pentru antrenament, la cerere pentru inferență: Antrenamentul poate gestiona întreruperile cu puncte de control; inferența trebuie să fie întotdeauna disponibilă
- Puncte de control frecvente: Salvați punctele de control la fiecare 30 de minute pentru a relua antrenamentul după o întrerupere la fața locului
- Time-slicing pentru dezvoltare: Utilizați GPU-uri segmentate în timp pentru dezvoltatori, MIG sau GPU-uri complete pentru producție
- Scalare la zero: Karpenter elimină nodurile GPU spot când antrenamentul se termină - nu plătiți pentru GPU-urile inactive
- Loturi în inferență: TorchServe cu batch_size=32 crește debitul de 10-20 ori în comparație cu cererile individuale
- Profil înainte de implementare: Utilizați NVIDIA Nsight pentru a vă profila jobul de formare și pentru a identifica ineficiențele
Erori GPU obișnuite pe Kubernetes
- Recipiente fără toleranță la pată: Nodurile GPU au pată
nvidia.com/gpu=true:NoSchedule; fără toleranță, Podul nu este programat pe nodul GPU - Eșecul izolării memoriei: GPU-ul nu izolează memoria între containere, așa cum o face CPU. Dacă alocați 1 GPU, dar modelul folosește mai multă memorie decât cea disponibilă, jobul se blochează cu CUDA OOM
- NCCL fără memorie partajată: Antrenamentul distribuit PyTorch folosește NCCL care necesită /dev/shm mare (de obicei 10-60 GB); configurați întotdeauna un emptyDir cu mediu: Memorie
- Nu monitorizați utilizarea GPU: Un GPU cu o utilizare de 20% este o risipă imensă. Tabloul de bord DCGM ar trebui să fie primul loc de care aveți grijă după fiecare implementare
Concluzii și pașii următori
Kubernetes a devenit nu întâmplător platforma standard pentru sarcinile de lucru AI/ML: the abstracția de resurse, sistemul avansat de programare și ecosistemul operatorului (Kubeflow, Training Operator) îl fac contextul ideal pentru a orchestra ambele antrenamente acea inferență la scară. Cu Karpenter gestionând automat furnizarea nodurilor Spot GPU, costul unui job de antrenament poate fi redus cu 40-70% în comparație cu utilizare a instanțelor la cerere.
Următorul pas este să integrați aceste sarcini de lucru cu o conductă MLOps completă: înregistrarea în jurnal de modele cu MLflow, management de set de date cu DVC, CI/CD pentru recalificare automată. Articolul FinOps pentru Kubernetes (articolul 9 din această serie) analizează modul de măsurare și optimizați costul total al sarcinilor de lucru GPU din cluster.
Articole viitoare din seria Kubernetes la scară
Serii înrudite
- MLOps și Machine Learning în producție — Conductă CI/CD pentru ML, model de registru
- Învățare profundă și rețele neuronale — fundamentele teoretice ale antrenării modelelor pe GPU-uri
- Autoscaling în Kubernetes — KEDA pentru scalare bazată pe valori personalizate







