Kubernetes
Kubernetes (K8s) esegue container su un cluster, mantiene integro il numero dichiarato di repliche e pianifica i job di addestramento e inferenza su GPU.
Kubernetes, spesso abbreviato in K8s, è un sistema open source che esegue applicazioni containerizzate su un cluster di macchine. Gli utenti dichiarano lo stato desiderato di un carico di lavoro, per esempio quale immagine container eseguire, quante copie mantenere e quanta capacità di CPU, memoria e GPU serve a ciascuna copia; Kubernetes avvia, riavvia, sposta e ridimensiona continuamente i container per adeguarvisi. Google ha annunciato il progetto nel giugno 2014, basandosi sul proprio gestore di cluster interno Borg, e con la versione 1.0, nel luglio 2015, lo ha proposto come progetto fondatore della neonata Cloud Native Computing Foundation. Il nome deriva dal greco e significa timoniere; K8s sostituisce le otto lettere tra K e s. Nelle operazioni di machine learning (MLOps), Kubernetes è il livello comune che esegue lavori di addestramento distribuito, inferenza batch e serving dei modelli su hardware condiviso.
Architettura e ciclo di controllo#
Un cluster è composto da un piano di controllo e nodi worker. Il piano di controllo contiene il server API a cui si rivolgono tutti i client, l'archivio etcd dello stato del cluster, lo scheduler che assegna i nuovi pod ai nodi e i controller, ciascuno dei quali monitora un tipo di oggetto. Ogni nodo worker, sia esso un server on-premise o una macchina virtuale cloud, esegue un agente kubelet e un runtime per container come containerd o CRI-O. L'unità più piccola pianificata da Kubernetes è un pod: uno o più container che condividono un indirizzo di rete e volumi di archiviazione.
I carichi di lavoro vengono dichiarati come oggetti, solitamente scritti in YAML e applicati con kubectl. Un Deployment mantiene in esecuzione un numero definito di pod identici e li sostituisce gradualmente quando cambia l'immagine; un Service assegna a quei pod un unico indirizzo stabile e distribuisce le richieste tra loro; un Job esegue i pod fino al completamento di un'attività. I controller confrontano lo stato dichiarato con quello effettivamente in esecuzione e intervengono su ogni discrepanza:
Lo stesso ciclo rende Kubernetes autoriparante. Quando un nodo si guasta, i suoi pod escono dallo stato di esecuzione e il controller ne crea di sostitutivi sui nodi integri. Anche un pod che rimane in stato Pending per mancanza di capacità segnala agli autoscaler del cluster di aggiungere nodi.
Kubernetes per il machine learning#
Le GPU vengono rese disponibili ai pod tramite plugin di dispositivo, che le pubblicizzano come risorse numerabili, per esempio nvidia.com/gpu, e tramite Dynamic Resource Allocation, stabile dalla versione 1.34 di Kubernetes, che permette a un pod di richiedere dispositivi in base ad attributi quali modello o memoria della GPU. GPU Operator di NVIDIA installa driver e plugin sui nodi GPU e può suddividere una GPU in istanze Multi-Instance GPU o condividerne il tempo tra i pod. Nel 2021 OpenAI ha riferito di aver scalato singoli cluster Kubernetes fino a 7.500 nodi per addestrare modelli come GPT-3 e CLIP.
I progetti open source aggiungono livelli specifici per il ML:
- Kubeflow: esegue addestramento distribuito PyTorch, pipeline di ML e notebook su un cluster.
- Kueue: mette in coda i lavori batch e di addestramento e applica quote per i team, così le costose GPU restano occupate senza che un team le monopolizzi.
- KServe: serve i modelli tramite endpoint con scalabilità automatica, compresa la riduzione a zero per i modelli inattivi.
- Horizontal Pod Autoscaler: aggiunge o rimuove repliche di inferenza in base all'utilizzo della CPU o a metriche personalizzate come la lunghezza della coda, mantenendo costante la latenza al variare del traffico.
Un Job è il modo più semplice per eseguire un'attività GPU una tantum, come l'inferenza in batch. L'immagine Docker ufficiale di Ultralytics contiene già il comando yolo e i pesi YOLO26 nano, quindi questo Job imposta solo un comando e richiede una GPU:
apiVersion: batch/v1
kind: Job
metadata:
name: yolo26-predict
spec:
backoffLimit: 2 # retry a failed pod at most twice
template:
spec:
restartPolicy: Never
containers:
- name: yolo
image: ultralytics/ultralytics:latest
command: ["yolo", "predict", "model=yolo26n.pt", "source=https://ultralytics.com/images/bus.jpg"]
resources:
limits:
nvidia.com/gpu: 1 # schedule only onto a node with a free GPUkubectl apply -f job.yaml lo invia, lo scheduler colloca il pod su un nodo con una GPU libera e kubectl logs job/yolo26-predict stampa i risultati del rilevamento degli oggetti dalla modalità predict. Un Job di addestramento segue lo stesso schema e aggiunge un volume persistente per i checkpoint, oltre a un volume in memoria in /dev/shm per i worker del data loader PyTorch.
Kubernetes a confronto con Docker e il serverless#
- Docker: crea immagini ed esegue container su una sola macchina. Kubernetes distribuisce i container su più macchine e, dalla versione 1.24, esegue le immagini create con Docker tramite containerd o CRI-O invece che con Docker Engine.
- Elaborazione serverless: servizi come Google Cloud Run e AWS Lambda nascondono completamente il cluster e applicano un costo per richiesta; Knative porta lo stesso modello con riduzione a zero nei cluster Kubernetes.
- Kubernetes gestito: Google Kubernetes Engine (GKE), Amazon Elastic Kubernetes Service (EKS) e Azure Kubernetes Service (AKS) gestiscono il piano di controllo per i clienti; GKE Autopilot gestisce anche i nodi worker.










