Obciążenia AI i GPU w Kubernetes: wtyczki do urządzeń i zadania szkoleniowe
W 2026 r. 66% klastrów wnioskowania AI będzie działać na platformie Kubernetes (badanie CNCF 2026). Powód To proste: Kubernetes rozwiązuje najtrudniejsze problemy operacyjne obciążeń AI — planowanie inteligentne skalowanie GPU, elastyczne skalowanie zadań szkoleniowych, integracja z rozproszoną pamięcią masową w przypadku zbiorów danych automatyczna ponowna próba w przypadku awarii węzła. Ale skonfigurowanie Kubernetes dla i Obciążenie procesora graficznego wymaga określonych umiejętności, które znacznie wykraczają poza zwykłe wdrożenie aplikacja internetowa.
W tym artykule zobaczymy, jak skonfigurować Wtyczki do urządzeń NVIDIA dla udostępnianie procesorów graficznych w klastrze, jak planować Rozproszone zadania szkoleniowe z PyTorch i TensorFlow, jak używać Stolarz wykonać skalowanie punktowe GPU (obniżenie kosztów o 40-70%) oraz wzorce optymalizacji wykorzystania GPU w obciążeniach wnioskowania o produkcji.
Czego się nauczysz
- Instalacja i konfiguracja wtyczki urządzenia NVIDIA dla Kubernetes
- Planowanie podów z zapotrzebowaniem na GPU (zasoby nvidia.com/gpu)
- Szkolenia rozproszone z PyTorchJob i TFJob (operator szkoleniowy Kubeflow)
- Karpenter NodePool do automatycznego udostępniania dodatkowych węzłów GPU
- Dzielenie czasu GPU w celu udostępniania procesorów graficznych pomiędzy wieloma Podami
- MIG (Multi-Instance GPU) dla partycji GPU A100/H100
- Monitorowanie GPU za pomocą DCGM Exporter i Grafana
- Wzorzec wnioskowania o dużej przepustowości za pomocą TorchServe na K8
Architektura GPU na Kubernetesie
Kubernetes nie obsługuje natywnie procesorów graficznych. Procesory graficzne są udostępniane klastrowi poprzez Struktura wtyczek urządzeń: zestaw DaemonSet działający na każdym węźle z procesorem graficznym, rejestruje się w kubelecie i zarządza przydziałem procesorów graficznych do kontenerów. The Wtyczka NVIDIA Device Plugin jest najpopularniejszą implementacją tego frameworka.
Instalowanie wtyczki urządzenia NVIDIA
# 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
Instalowanie operatora GPU NVIDIA (zalecane podejście)
W przypadku klastrów w produkcji, Operator GPU firmy NVIDIA zarządza automatycznie wszystkie niezbędne komponenty: sterowniki, wtyczki urządzeń, środowisko wykonawcze kontenerów, Eksporter DCGM do monitorowania:
# 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
Planowanie podów za pomocą procesora graficznego
Po aktywowaniu wtyczki urządzenia możesz żądać procesorów graficznych w manifestach takich jak dowolne inny zasób Kubernetes. Różnica: nie używasz żądań, tylko ograniczenia dla procesorów graficznych (Kubernetes zawsze gwarantuje dokładnie taką liczbę wymaganych procesorów graficznych).
# 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"
Szkolenie dystrybuowane za pomocą operatora szkoleniowego Kubeflow
Trenowanie dużych modeli często wymaga wielu procesorów graficznych w wielu węzłach. The Operator szkoleń Kubeflow zarządza rozproszonymi zadaniami szkoleniowymi za pomocą PyTorchJob, TFJob, MXJob i MPIJob. Najpierw zainstaluj operator:
# 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 do szkolenia z wieloma węzłami graficznymi i wieloma węzłami graficznymi
# 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 do punktowego udostępniania węzłów GPU
Procesory graficzne są najdroższym zasobem w chmurze. Instancje Spot GPU kosztują 60-70% mniej w porównaniu z usługami na żądanie. Stolarz zarządza automatycznym udostępnianiem punktowych węzłów GPU z możliwością powrotu do pracy na żądanie w przypadku awarii:
# 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
Dzielenie czasu GPU: Udostępnij procesor graficzny pomiędzy wieloma kapsułami
W przypadku niewielkich obciążeń związanych z wnioskowaniem lub programowaniem często marnuje się cały procesor graficzny. The Dzielenie czasu GPU umożliwia współdzielenie fizycznego procesora graficznego pomiędzy wieloma Podami, z których każdy widzi „wirtualny procesor graficzny” z wycinkiem czasu obliczeń:
# 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: wieloinstancyjny procesor graficzny dla A100 i H100
Obsługa procesorów graficznych NVIDIA A100 i H100 MIG (procesor graficzny z wieloma instancjami), to podziel procesor graficzny na izolowane instancje sprzętowe (nie tylko z podziałem czasu). Każda instancja MIG ma gwarantowaną pamięć i obliczenia i nie koliduje z innymi:
# 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
Monitorowanie GPU za pomocą DCGM Exporter
Monitorowanie procesora graficznego jest niezbędne, aby zrozumieć, czy zadania szkoleniowe są wydajne i dla FinOps. DCGM Exporter udostępnia Prometheusowi wskaźniki GPU:
# 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)
Wdrażanie modeli do wnioskowania za pomocą TorchServe
Do wnioskowania produkcyjnego potrzebny jest serwer modelowy obsługujący równoważenie obciążenia w tym replikację wielu modeli, grupowanie żądań i wersjonowanie. Serwis Pochodni i oficjalne rozwiązanie 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"})
Najlepsze praktyki dotyczące obciążeń AI w Kubernetes
Optymalizacja kosztów procesora graficznego
- Miejsce do szkolenia, na żądanie do wnioskowania: Szkolenie może obsługiwać przerwy z punktami kontrolnymi; wnioskowanie musi być zawsze dostępne
- Częste punkty kontrolne: Zapisuj punkty kontrolne co 30 minut, aby wznowić trening po chwilowej przerwie
- Podział czasu na rozwój: Używaj procesorów graficznych z podziałem czasu dla programistów, MIG lub pełnych procesorów graficznych do produkcji
- Skala do zera: Karpenter usuwa dodatkowe węzły GPU po zakończeniu szkolenia — nie płacisz za bezczynne procesory graficzne
- Grupowanie w wnioskowaniu: TorchServe z partii_size=32 zwiększa przepustowość 10-20x w porównaniu do pojedynczych żądań
- Profil przed wdrożeniem: Użyj NVIDIA Nsight, aby sprofilować swoje zadanie szkoleniowe i zidentyfikować nieefektywności
Typowe błędy GPU w Kubernetes
- Pojemniki bez tolerancji na skażenie: Węzły GPU mają skażenie
nvidia.com/gpu=true:NoSchedule; bez tolerancji Pod nie jest zaplanowany w węźle GPU - Brak izolacji pamięci: Procesor graficzny nie izoluje pamięci pomiędzy kontenerami, tak jak robi to procesor. Jeśli przydzielisz 1 procesor graficzny, ale model zużywa więcej pamięci niż jest dostępna, zadanie ulega awarii z CUDA OOM
- NCCL bez pamięci współdzielonej: Szkolenie rozproszone PyTorch wykorzystuje NCCL, które wymaga dużego /dev/shm (zwykle 10-60 GB); zawsze konfiguruj pusty katalog z nośnikiem: Pamięć
- Nie monitoruj wykorzystania procesora graficznego: GPU przy 20% obciążeniu to ogromne marnotrawstwo. Pulpit nawigacyjny DCGM powinien być pierwszym miejscem, w którym sprawdzasz każde wdrożenie
Wnioski i dalsze kroki
Kubernetes nie przez przypadek stał się standardową platformą dla obciążeń AI/ML: abstrakcja zasobów, zaawansowany system planowania i ekosystem operatorów (Kubeflow, Training Operator) sprawiają, że jest to idealny kontekst do koordynowania obu szkoleń to wnioskowanie o skali. Dzięki Karpenterowi automatycznie zarządzasz udostępnianiem węzłów Spot GPU, koszt zadania szkoleniowego można zmniejszyć o 40-70% w porównaniu do zużycia instancji na żądanie.
Następnym krokiem jest zintegrowanie tych obciążeń z kompletnym potokiem MLOps: rejestrowanie modeli z MLflow, zarządzanie zbiorami danych za pomocą DVC, CI/CD do automatycznego przekwalifikowania. W artykule FinOps for Kubernetes (artykuł 9 z tej serii) szczegółowo opisano, jak mierzyć i zoptymalizuj całkowity koszt obciążeń GPU w klastrze.
Nadchodzące artykuły z serii Kubernetes at Scale
Powiązane serie
- MLOps i uczenie maszynowe w produkcji — Rurociąg CI/CD dla ML, rejestr modelowy
- Głębokie uczenie się i sieci neuronowe — teoretyczne podstawy uczenia modeli na procesorach graficznych
- Autoskalowanie w Kubernetesie — KEDA do skalowania w oparciu o niestandardowe metryki







