Kubernetes에서 ML 확장: 프로덕션에서의 배포 및 조정
기계 학습 모델이 모든 오프라인 테스트를 통과했으며 측정항목이 훌륭합니다. FastAPI를 통한 서비스는 로컬에서 완벽하게 작동합니다. 그런 다음 중요한 순간이 옵니다. 관리해야 합니다. 초당 10,000개 요청, 로드에 따라 동적으로 확장, 고가용성 보장 업데이트 중에 가동 중지 시간이 없습니다. 단일 컨테이너로는 더 이상 충분하지 않습니다.
쿠버네티스 ML 워크로드를 조정하기 위한 사실상의 표준이 되었습니다. 프로덕션(기업 조직의 78%가 모델 배포에 이를 사용함) CNCF Survey 2025에 따르면. 그러나 모델을 Pod에 넣는 것만으로는 충분하지 않으며 관리가 필요합니다. GPU 스케줄링, 이벤트 기반 자동 확장, 리소스 할당량, 카나리아 배포 및 모니터링 추론에 특화되어 있습니다. MLOps 시장은 2026년에 43억 8천만 달러 규모로 성장할 것이며 CAGR은 39.8%는 Kubernetes에 주요 확장 엔진을 가지고 있습니다.
이 기사에서는 ML 모델을 Kubernetes로 가져오기 위한 전체 아키텍처를 살펴봅니다. 프로덕션: 추론 서비스를 위한 KServe 및 Seldon Core부터 NVIDIA 장치를 사용한 GPU 스케줄링까지 HPA, VPA 및 KEDA를 통한 지능형 자동 확장부터 Prometheus 및 Grafana를 통한 모니터링까지의 플러그인입니다.
무엇을 배울 것인가
- Kubernetes가 프로덕션에서 ML의 표준인 이유와 이를 사용해야 하는 경우
- NVIDIA 장치 플러그인 및 MIG를 통한 GPU 예약 및 공유
- KServe: 카나리아 출시 및 0으로 축소를 통한 InferenceService 배포
- Seldon Core v2: 구성 가능 및 다중 모델 제공 파이프라인
- 고급 자동 확장: 이벤트 중심 ML 워크로드를 위한 HPA, VPA 및 KEDA
- 리소스 관리: 요청, 제한, 우선 순위 클래스 및 노드 선호도
- ML 추론에 특화된 Prometheus + Grafana를 사용한 모니터링
- GPU 클러스터의 비용 최적화 및 모범 사례
프로덕션에서 ML을 위해 Kubernetes를 사용하는 이유
기술 구성을 살펴보기 전에 Kubernetes가 왜 사용되는지 이해하는 것이 중요합니다. 다음과 같은 솔루션을 능가하며 ML 워크로드의 참조 플랫폼으로 자리매김했습니다. 베어메탈, 전용 VM 또는 독점 클라우드 서비스.
ML 워크로드는 기존 웹 애플리케이션에 비해 고유한 특성을 가지고 있습니다. 훈련 몇 시간 또는 며칠 동안 대규모 GPU가 필요하며 리소스가 해제되어야 합니다. 추론은 예측할 수 없는 최대치와 심각한 대기 시간. 가동 중지 시간 없이 모델을 업데이트해야 합니다. 데이터 세트 규모가 클 수 있으며 특수한 스토리지가 필요할 수 있습니다. Kubernetes는 이러한 모든 시나리오를 해결합니다. 기본 프리미티브 포함: 특정 GPU 노드의 포드 예약, 데이터 세트당 영구 볼륨, 작업 일괄 훈련의 경우 추론 확장의 경우 HorizonPodAutoscaler입니다.
Kubernetes와 클라우드 관리 대안
Kubernetes 자체 관리형 또는 관리형(EKS, GKE, AKS): 완전한 통제,
다중 클라우드 이식성, 최적화 가능한 비용, 그러나 높은 운영 복잡성.
SageMaker/Vertex AI/Azure ML: 빠른 설정, 클라우드 기반 통합,
그러나 벤더 종속, 장기 비용 증가, 맞춤형 아키텍처에 대한 유연성 저하 등의 문제가 있습니다.
경험 법칙: 팀 <5명 또는 예산이 제한되어 있나요? 관리형 ML을 시작해보세요.
여러 모델을 생산 중인 Team >5? Kubernetes는 6~12개월 안에 투자금을 회수합니다.
참조 아키텍처
프로덕션 중인 ML을 위한 Kubernetes 클러스터는 일반적으로 3개의 개별 레이어로 구성됩니다. 잘 정의된 책임이 있는 경우:
- 인프라 계층: 가벼운 서비스 및 오케스트레이션을 위한 CPU 노드, GPU 노드 훈련 및 강력한 추론을 위한 데이터세트 및 아티팩트용 스토리지 노드. GPU 풀은 다음과 같습니다. 특정 노드 레이블로 구분됩니다.
- 플랫폼 레이어: 추론 제공을 위한 KServe 또는 Seldon Core, 추론 제공을 위한 Kubeflow 훈련 파이프라인, 실험 추적을 위한 MLflow(문서 4 참조), Argo 워크플로 복잡한 오케스트레이션.
- 관찰 가능성 계층: 측정항목용 Prometheus, 대시보드용 Grafana, Jaeger 분산 추적의 경우 Loki, 로그 집계의 경우 Loki.
# Namespace structure per ML cluster
# Separare ambienti e responsabilità
kubectl create namespace ml-training # Job di training
kubectl create namespace ml-serving # Inference services
kubectl create namespace ml-monitoring # Prometheus, Grafana
kubectl create namespace mlflow # Experiment tracking
kubectl create namespace kubeflow # Pipeline orchestration
# Label nodi per GPU scheduling
kubectl label nodes gpu-node-1 accelerator=nvidia-a100
kubectl label nodes gpu-node-2 accelerator=nvidia-t4
kubectl label nodes cpu-node-1 workload=inference-cpu
GPU 스케줄링 및 공유
GPU는 ML 클러스터에서 가장 비싼 리소스입니다. 잘못 관리하면 수십 달러가 낭비됩니다.
한 달에 수천 유로. Kubernetes는 다음을 통해 GPU를 예약 가능한 리소스로 노출합니다.
NVIDIA 장치 플러그인, 노드에서 GPU를 자동으로 감지하는 DaemonSet
그리고 그것들을 다음과 같이 기록합니다. nvidia.com/gpu 쿠벨렛에서.
# Installazione NVIDIA Device Plugin via Helm
helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo update
helm upgrade -i nvdp nvdp/nvidia-device-plugin \
--namespace kube-system \
--set failOnInitError=false
# Verifica GPU disponibili sui nodi
kubectl describe nodes | grep -A5 "Allocatable:"
# Output atteso:
# nvidia.com/gpu: 8
# cpu: 96
# memory: 768Gi
# Pod che richiede 1 GPU intera
apiVersion: v1
kind: Pod
metadata:
name: ml-training-job
spec:
containers:
- name: trainer
image: pytorch/pytorch:2.5.0-cuda12.4-cudnn9-runtime
resources:
limits:
nvidia.com/gpu: 1 # Richiede 1 GPU intera
cpu: "8"
memory: "32Gi"
requests:
nvidia.com/gpu: 1
cpu: "4"
memory: "16Gi"
nodeSelector:
accelerator: nvidia-a100 # Forza scheduling su A100
전체 GPU가 필요하지 않은 추론 워크로드의 경우 NVIDIA는 두 가지 전략을 제공합니다. GPU 공유: 시간 분할 e 멀티 인스턴스 GPU(MIG).
# Configurazione Time-Slicing (per GPU T4/V100, sharing software)
# Ogni GPU fisica viene divisa in N repliche logiche
apiVersion: v1
kind: ConfigMap
metadata:
name: time-slicing-config
namespace: kube-system
data:
any: |-
version: v1
flags:
migStrategy: none
sharing:
timeSlicing:
replicas: 4 # 4 pod condividono 1 GPU fisica
failRequestsGreaterThanOne: false
# Apply al device plugin
kubectl patch clusterpolicies/cluster-policy \
-n gpu-operator --type merge \
-p '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config"}}}}'
# Configurazione MIG per A100/H100 (hardware isolation)
# Partiziona A100 in 7 istanze MIG da 10GB ciascuna
nvidia-smi mig -cgi 9,9,9,9,9,9,9 -C
# Pod che usa una slice MIG
resources:
limits:
nvidia.com/mig-1g.10gb: 1 # Usa 1 istanza MIG da 10GB
시간 분할과 MIG: 언제 어느 것을 사용해야 할까요?
시간 분할: 가벼운 추론 워크로드(<2GB VRAM 모델)에 적합합니다. 컨텍스트 전환으로 인해 대기 시간이 발생합니다. 모든 NVIDIA GPU에서 작동합니다. 미그: 완벽한 하드웨어 격리, 전용 메모리 보장, 간섭 없음 워크로드 사이. A100, A30, H100에서만 사용할 수 있습니다. 엄격한 대기 시간 SLA에 적합합니다. 동일한 노드에서 두 가지 접근 방식을 결합하지 마십시오.
KServe: Kubernetes의 기본 추론 제공
KServe (이전 KFServing) 및 Kubernetes에서의 추론 제공을 위한 CNCF 표준,
Google, IBM, Bloomberg 등의 협력을 통해 탄생했습니다. 추상화를 제공합니다.
InferenceService 배포의 복잡성을 숨기고 자동으로 관리
카나리아 출시, 0으로 확장, 요청 기반 자동 확장, 여러 프레임워크 지원
(PyTorch, TensorFlow, scikit-learn, XGBoost, ONNX, Hugging Face).
# Installazione KServe (versione 0.13+)
kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.13.0/kserve.yaml
# Verifica installazione
kubectl get pods -n kserve
# kserve-controller-manager-xxx Running
# kserve-gateway-xxx Running
# InferenceService per modello scikit-learn
apiVersion: "serving.kserve.io/v1beta1"
kind: "InferenceService"
metadata:
name: "churn-predictor"
namespace: ml-serving
annotations:
serving.kserve.io/enable-prometheus-scraping: "true"
spec:
predictor:
minReplicas: 1
maxReplicas: 10
scaleTarget: 50 # Target: 50 req/sec per replica
scaleMetric: rps # Scala in base a requests-per-second
sklearn:
storageUri: "gs://my-ml-bucket/models/churn-model/v3"
runtimeVersion: "1.5.2"
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "4Gi"
KServe의 강점 중 하나는 i에 대한 기본 지원입니다. 카나리아 출시: 트래픽의 일부를 템플릿의 새 버전으로 보내고 나머지는 보낼 수 있습니다. 기사에서 본 A/B 테스트와 똑같이 안정적인 버전을 계속 사용하세요. 이 시리즈의 이전 것.
# Canary Rollout: 20% traffico alla nuova versione
apiVersion: "serving.kserve.io/v1beta1"
kind: "InferenceService"
metadata:
name: "churn-predictor"
namespace: ml-serving
spec:
predictor:
# Versione stabile (80% traffico)
minReplicas: 2
maxReplicas: 8
sklearn:
storageUri: "gs://my-ml-bucket/models/churn-model/v3"
runtimeVersion: "1.5.2"
canaryTrafficPercent: 80
# Versione canary (20% traffico)
predictor:
# NOTA: nella specifica KServe, il canary si gestisce con
# l'annotation traffic-split
# Ecco la sintassi corretta tramite Knative revisions:
---
# Alternativa: InferenceGraph per traffic splitting esplicito
apiVersion: "serving.kserve.io/v1alpha1"
kind: "InferenceGraph"
metadata:
name: "churn-ab-split"
namespace: ml-serving
spec:
nodes:
root:
routerType: WeightedEnsemble
routes:
- serviceName: churn-predictor-v3
weight: 80
- serviceName: churn-predictor-v4
weight: 20
# Test dell'endpoint
curl -X POST \
http://churn-predictor.ml-serving.svc.cluster.local/v1/models/churn-predictor:predict \
-H 'Content-Type: application/json' \
-d '{"instances": [[35, 12000, 2, 1, 0.8, 3]]}'
특징 0으로 축소 KServe의 (Knative Serving 기반) e 가끔 사용하는 모델에 특히 유용합니다. 일정 시간이 지나면 포드가 꺼집니다. 유휴 시간을 구성할 수 있으며 첫 번째 요청 시 콜드 스타트로 자동으로 다시 시작됩니다. 일반적으로 사전 캐시된 모델의 경우 30초 미만입니다.
# Configurazione scale-to-zero con timeout personalizzato
apiVersion: "serving.kserve.io/v1beta1"
kind: "InferenceService"
metadata:
name: "batch-analyzer"
namespace: ml-serving
annotations:
# Scale-to-zero dopo 5 minuti di inattivita
autoscaling.knative.dev/scaleToZeroGracePeriod: "300s"
# Window per calcolo scale-up
autoscaling.knative.dev/window: "60s"
# Utilization target (in percentuale)
autoscaling.knative.dev/targetUtilizationPercentage: "70"
spec:
predictor:
minReplicas: 0 # Abilita scale-to-zero
maxReplicas: 5
pytorch:
storageUri: "gs://my-ml-bucket/models/analyzer/v1"
runtimeVersion: "2.5.0"
Seldon Core v2: 구성 가능한 ML 파이프라인
KServe는 개별 모델을 제공하는 데 탁월하지만, 셀던 코어 v2 빛난다 복잡한 ML 아키텍처 관리: 다단계 파이프라인, 모델 앙상블, 비즈니스 로직을 갖춘 A/B 라우팅 및 스트림 처리를 위한 Kafka와의 통합. Seldon v2는 V2 프로토콜과 호환되는 추론 런타임으로 MLServer를 사용합니다. (KFServing 추론 프로토콜), PyTorch, scikit-learn을 기본적으로 지원합니다. 허깅 페이스(Hugging Face) 및 맞춤형 모델.
# Installazione Seldon Core v2 via Helm
helm repo add seldonio https://storage.googleapis.com/seldon-charts
helm install seldon-core-v2 seldonio/seldon-core-v2 \
--namespace seldon-mesh \
--create-namespace \
--set controller.clusterwide=true
# Model: singolo modello XGBoost
apiVersion: mlops.seldon.io/v1alpha1
kind: Model
metadata:
name: churn-xgb
namespace: ml-serving
spec:
storageUri: "gs://my-ml-bucket/models/churn-xgb/v2"
requirements:
- xgboost
memory: 100Mi
# Pipeline: preprocessing + prediction + postprocessing
apiVersion: mlops.seldon.io/v1alpha1
kind: Pipeline
metadata:
name: churn-pipeline
namespace: ml-serving
spec:
steps:
- name: preprocessor
inputs:
- churn-pipeline.inputs
- name: churn-xgb
inputs:
- preprocessor.outputs
- name: postprocessor
inputs:
- churn-xgb.outputs
output:
steps:
- postprocessor
# Autoscaling basato su RPS
replicas: 1
scaling:
replicas:
minReplicas: 1
maxReplicas: 8
metric: rps
target: 100
KServe vs Seldon Core: 어느 것을 선택해야 할까요?
- K서브: 단일 모델에 가장 적합하며 Knative 및 Istio와의 통합, 기본 scale-to-0, CNCF 커뮤니티입니다. K8s ML로 시작하는 팀에 이상적입니다.
- 셀던 코어 v2: 복잡한 파이프라인, 앙상블, Kafka 통합, 다중 모델 제공에 가장 적합합니다. 비즈니스 로직 라우팅을 갖춘 고급 ML 아키텍처에 이상적입니다.
- 둘 다: V2 프로토콜, Prometheus 모니터링, GPU 서비스용 Triton을 지원합니다. 이들은 상호 배타적이지 않으며 일부 조직에서는 서로 다른 사용 사례에 함께 사용합니다.
지능형 자동 확장: HPA, VPA 및 KEDA
ML 워크로드 확장은 기존 웹 애플리케이션보다 더 복잡합니다. CPU 및 메모리 측정항목은 모델의 실제 로드를 정확하게 반영하지 못하는 경우가 많습니다. GPU 바인딩 모델은 CPU가 80% 유휴 상태인 동안 그래픽 카드를 포화시킬 수 있습니다. Kubernetes는 올바르게 함께 사용하면 다음과 같은 세 가지 보완적인 자동 확장 메커니즘을 제공합니다. 모든 ML 시나리오를 다룹니다.
# HPA (Horizontal Pod Autoscaler): scala il numero di repliche
# Configurazione per inference service basata su custom metrics
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: churn-predictor-hpa
namespace: ml-serving
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: churn-predictor
minReplicas: 2
maxReplicas: 20
metrics:
# Scala su CPU (fallback)
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# Scala su custom metric: inference latency P99
- type: Pods
pods:
metric:
name: inference_request_duration_p99
target:
type: AverageValue
averageValue: "500m" # 500ms P99 latency target
behavior:
scaleUp:
stabilizationWindowSeconds: 30 # Reazione rapida al traffico
policies:
- type: Percent
value: 100
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 300 # Lento a rimuovere pod (warm models)
# VPA (Vertical Pod Autoscaler): ottimizza resources requests/limits
# NOTA: non usare VPA e HPA sulle stesse metriche CPU/Memory!
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: batch-trainer-vpa
namespace: ml-training
spec:
targetRef:
apiVersion: batch/v1
kind: Job
name: model-training
updatePolicy:
updateMode: "Off" # Solo raccomandazioni, non applica auto (Off | Initial | Recreate)
resourcePolicy:
containerPolicies:
- containerName: trainer
minAllowed:
cpu: "1"
memory: 4Gi
maxAllowed:
cpu: "16"
memory: 128Gi
controlledResources: ["cpu", "memory"]
# Leggi le raccomandazioni VPA
kubectl describe vpa batch-trainer-vpa
# Output:
# Recommendation:
# Container Recommendations:
# Container Name: trainer
# Lower Bound: cpu: 2, memory: 8Gi
# Target: cpu: 6, memory: 32Gi
# Upper Bound: cpu: 12, memory: 64Gi
케다 (Kubernetes Event-Driven Autoscaler, CNCF 졸업 프로젝트) 및 lo 이벤트 중심 ML 워크로드를 위한 가장 강력한 도구: 이벤트를 기반으로 포드 확장 메시지 대기열, 데이터베이스, Prometheus 측정항목 또는 HTTP 트리거에서 일괄 처리를 위해 0으로 축소.
# KEDA: scala i worker ML in base alla coda di inference requests
# Installazione
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda --create-namespace
# ScaledObject per batch ML processing da RabbitMQ
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: ml-batch-processor-scaler
namespace: ml-serving
spec:
scaleTargetRef:
name: batch-ml-processor
minReplicaCount: 0 # Scale-to-zero quando coda vuota
maxReplicaCount: 30 # Max 30 worker per GPU cluster
pollingInterval: 15 # Controlla la coda ogni 15 secondi
cooldownPeriod: 60 # Aspetta 60s prima di scale-down
triggers:
- type: rabbitmq
metadata:
host: amqp://rabbitmq.ml-serving.svc.cluster.local
queueName: inference-requests
mode: QueueLength
value: "10" # 1 pod ogni 10 messaggi in coda
# Trigger alternativo: Prometheus metric
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring.svc.cluster.local:9090
metricName: inference_queue_depth
query: sum(inference_queue_depth{namespace="ml-serving"})
threshold: "50" # 1 replica ogni 50 richieste pendenti
ML을 위한 패턴 자동 확장: 권장 사항
세 가지 메커니즘을 서로 다른 책임과 결합합니다.
- HPA 온라인 추론을 위한 대기 시간/RPS(응답성, 빠름)
- 꺼짐 모드의 VPA 교육 작업 요청 최적화(수동으로 문의 및 업데이트)
- 케다 일괄 처리 및 이벤트 기반 파이프라인용(0으로 축소 포함)
동일한 리소스(CPU/메모리)에서 HPA와 VPA를 동시에 사용하지 마세요: 충돌
확장은 예측할 수 없는 변동과 리소스 낭비를 초래합니다.
자원 관리 및 우선 순위 클래스
서로 다른 ML 팀 간에 공유되는 클러스터에서는 리소스 관리가 매우 중요합니다. 학습 작업이 프로덕션 또는 실험에서 추론을 차단하지 못하도록 방지 사용 가능한 모든 GPU를 소비합니다. Kubernetes는 세 가지 도구를 제공합니다. 리소스할당량, 제한 범위 e 우선순위클래스.
# ResourceQuota: limita risorse per namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: ml-serving-quota
namespace: ml-serving
spec:
hard:
requests.cpu: "40"
requests.memory: 160Gi
limits.cpu: "80"
limits.memory: 320Gi
requests.nvidia.com/gpu: "4" # Max 4 GPU per inference namespace
limits.nvidia.com/gpu: "4"
pods: "50"
---
# LimitRange: imposta defaults e limiti per singolo container
apiVersion: v1
kind: LimitRange
metadata:
name: ml-container-limits
namespace: ml-serving
spec:
limits:
- type: Container
default: # Default limits se non specificati
cpu: "2"
memory: 4Gi
defaultRequest: # Default requests se non specificati
cpu: "500m"
memory: 1Gi
max: # Massimo per container
cpu: "8"
memory: 32Gi
nvidia.com/gpu: "2"
min: # Minimo per container
cpu: "100m"
memory: 256Mi
---
# PriorityClass: garantisce che l'inferenza non venga preemptata dal training
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: ml-inference-critical
value: 1000000 # Alta priorità per serving
globalDefault: false
description: "Inference services critici - non preemptabili"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: ml-training-batch
value: 100000 # Bassa priorità per training
preemptionPolicy: PreemptLowerPriority
description: "Training jobs - preemptabili se necessario"
Il 노드 선호도 그리고 나 오염/관용 당신이 할 수 있도록 ML 워크로드가 예약된 노드를 정확하게 제어하여 다음을 보장합니다. 훈련 작업은 동일한 GPU에서 추론과 경쟁하지 않습니다.
# Taint nodi GPU dedicati all'inferenza
kubectl taint nodes gpu-inference-1 dedicated=inference:NoSchedule
kubectl taint nodes gpu-inference-2 dedicated=inference:NoSchedule
# Solo pod con toleration possono usare questi nodi
# InferenceService spec con affinity e toleration
spec:
predictor:
tolerations:
- key: dedicated
operator: Equal
value: inference
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: accelerator
operator: In
values:
- nvidia-a100
- nvidia-h100
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: churn-predictor
topologyKey: kubernetes.io/hostname
# Distribuisce repliche su host diversi per HA
ML용 Prometheus 및 Grafana를 사용한 모니터링
Kubernetes에서 ML 시스템을 모니터링하려면 두 가지 수준의 메트릭이 필요합니다. Kubernetes 표준 인프라(CPU, 메모리, 네트워크) 및 특정 지표 ML 추론(모델 지연 시간, 처리량, 오류율, 데이터 드리프트 신호) KServe와 Seldon은 Prometheus 측정항목을 표준 형식으로 자동 노출합니다.
# Configurazione Prometheus per scraping KServe metrics
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: kserve-inference-monitor
namespace: ml-monitoring
labels:
release: prometheus
spec:
namespaceSelector:
matchNames:
- ml-serving
selector:
matchLabels:
serving.kserve.io/inferenceservice: "true"
endpoints:
- port: metrics
interval: 15s
path: /metrics
honorLabels: true
# Metriche KServe esposte automaticamente:
# kserve_inference_request_total{model_name, namespace, status_code}
# kserve_inference_request_duration_seconds{model_name, quantile}
# kserve_inference_request_size_bytes{model_name}
# kserve_inference_response_size_bytes{model_name}
# PrometheusRule: alert per latenza elevata
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: ml-inference-alerts
namespace: ml-monitoring
spec:
groups:
- name: ml-inference.rules
rules:
- alert: HighInferenceLatency
expr: |
histogram_quantile(0.99,
rate(kserve_inference_request_duration_seconds_bucket[5m])
) > 1.0
for: 5m
labels:
severity: warning
annotations:
summary: "P99 latency > 1s per {{ $labels.model_name }}"
description: "Modello {{ $labels.model_name }} ha latenza P99 di {{ $value }}s"
- alert: ModelErrorRateHigh
expr: |
rate(kserve_inference_request_total{status_code!="200"}[5m])
/ rate(kserve_inference_request_total[5m]) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "Error rate > 5% per {{ $labels.model_name }}"
# Dashboard Grafana: query principali per ML inference monitoring
# (da importare come JSON o configurare manualmente)
# 1. Throughput modello (req/sec)
rate(kserve_inference_request_total[5m])
# 2. Latenza P50, P95, P99
histogram_quantile(0.50, rate(kserve_inference_request_duration_seconds_bucket[5m]))
histogram_quantile(0.95, rate(kserve_inference_request_duration_seconds_bucket[5m]))
histogram_quantile(0.99, rate(kserve_inference_request_duration_seconds_bucket[5m]))
# 3. GPU Utilization per nodo (richiede NVIDIA DCGM Exporter)
DCGM_FI_DEV_GPU_UTIL{namespace="ml-serving"}
# 4. GPU Memory in uso
DCGM_FI_DEV_FB_USED{namespace="ml-serving"} /
DCGM_FI_DEV_FB_TOTAL{namespace="ml-serving"} * 100
# 5. Numero repliche attive per modello
kube_deployment_status_replicas_available{
namespace="ml-serving",
deployment=~".*-predictor.*"
}
# 6. Scaling events (utile per debug autoscaler)
kube_horizontalpodautoscaler_status_desired_replicas{
namespace="ml-serving"
}
클러스터 ML의 비용 최적화
GPU는 ML 클러스터의 주요 비용 항목입니다. NVIDIA A100 SXM4 비용은 대략 클라우드의 경우 시간당 $2-3, H100의 경우 시간당 $4-5입니다. 20개의 GPU 클러스터에서 월별 비용은 다음과 같습니다. $100,000를 초과합니다. 비용 최적화는 선택 사항이 아닙니다.
비용 최적화 전략
- 학습용 스팟/선점형 인스턴스: 작업당 60-80% 절감 방해에 견딜 수 있습니다. 자동 재개를 위해 빈번한 체크포인트와 Argo Workflows를 사용하세요.
- 비정기 모델의 경우 0으로 축소: minReplicas=0 재설정으로 KServe 모델이 트래픽을 수신하지 않을 때 GPU 비용.
- 경량 추론을 위한 GPU 시간 분할: 물리적 GPU당 모델 4~8개 감소 모델당 비용은 4~8배입니다.
- 혼합 노드 풀이 있는 자동 확장 처리 클러스터: GPU 노드 추가/제거 실제 클러스터 로드에 따라 자동으로 생성됩니다.
- Karpenter를 사용한 노드 통합: 더 적은 수의 노드에 포드를 더 빨리 통합 빈 노드를 종료합니다(가변 사용량의 클러스터에서 20-40% 절감).
# Cluster Autoscaler per node pool GPU
# (esempio GKE, ma concettualmente uguale per EKS/AKS)
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-autoscaler-config
namespace: kube-system
data:
config.yaml: |
nodeGroups:
- name: gpu-a100-pool
minSize: 0 # Scala a zero se nessun workload GPU
maxSize: 10 # Max 10 nodi A100
machineType: a2-highgpu-1g
expander: least-waste # Usa il nodo che spreca meno risorse
scaleDownUnneededTime: 10m # Rimuovi nodo inutilizzato dopo 10 min
scaleDownUtilizationThreshold: 0.5 # Scala down se utilizzo < 50%
skipNodesWithSystemPods: false
# Cost tracking con labels obbligatorie su tutti i workload
# Ogni Job/Deployment deve avere questi labels per tracking
metadata:
labels:
cost-center: "data-science"
project: "churn-prediction"
environment: "production"
model-version: "v3"
전체 배포: 엔드투엔드 파이프라인
모델의 전체 Helm 배포에 모든 구성 요소를 통합하는 방법을 살펴보겠습니다. KServe, Prometheus 모니터링 및 자동 확장을 KEDA와 결합하여 생산:
# Helm Chart structure per ML service completo
# charts/ml-inference-service/
# ├── Chart.yaml
# ├── values.yaml
# └── templates/
# ├── inference-service.yaml
# ├── hpa.yaml
# ├── service-monitor.yaml
# └── network-policy.yaml
# values.yaml
model:
name: "churn-predictor"
version: "v3"
storageUri: "gs://my-ml-bucket/models/churn-model/v3"
framework: "sklearn"
runtimeVersion: "1.5.2"
scaling:
minReplicas: 2
maxReplicas: 20
targetRPS: 50
targetLatencyP99: "500m"
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "4Gi"
monitoring:
enabled: true
prometheusNamespace: "ml-monitoring"
grafanaDashboard: true
canary:
enabled: false
weight: 0
# Deploy
helm upgrade --install churn-predictor ./charts/ml-inference-service \
--namespace ml-serving \
--values production-values.yaml \
--wait --timeout 10m
# Verifica deployment
kubectl get inferenceservice -n ml-serving
# NAME URL READY PREV LATEST ...
# churn-predictor http://churn-predictor True 0 100 ...
모범 사례 및 안티 패턴
기술 구현을 본 후 ML 배포에서 배운 교훈은 다음과 같습니다. 엔터프라이즈 환경의 Kubernetes:
모범 사례
- 항상 리소스 요청과 제한을 지정하세요. 요청 없이, 스케줄러가 포드를 올바르게 배치할 수 없습니다. OOM 모델은 제한 없이 다음을 수행할 수 있습니다. 전체 노드를 불안정하게 만듭니다.
- ML 관련 준비 프로브를 사용합니다. 컨테이너는 "실행 중"이지만 모델이 여전히 로드 중입니다. 준비 상태 프로브는 다음을 확인해야 합니다. 모델이 실제로 게재될 준비가 되었음을 의미합니다.
- GPU 노드에서 이미지를 미리 가져옵니다. CUDA를 사용한 PyTorch 이미지 10GB를 초과하는 경우가 많습니다. 높은 콜드 스타트를 방지하려면 DaemonSet 또는 이미지 사전 캐싱을 사용하세요.
- 환경별로 네임스페이스를 구분합니다. 다양한 네임스페이스에서의 스테이징 및 프로덕션 별도의 ResourceQuota를 사용하면 우발적인 간섭을 방지할 수 있습니다.
- 회로 차단기를 구현합니다. 모델의 오류율이 10%보다 크면 중지합니다. Istio 또는 사이드카 프록시를 통해 자동으로 트래픽을 처리합니다.
- 명시적 모델 버전 관리: 모든 InferenceService에는 다음이 있어야 합니다. 이름이나 라벨에 버전 태그가 있습니다. 프로덕션에서는 "최신"을 사용하지 마십시오.
피해야 할 안티패턴
- 추론 노드에 대한 교육: 훈련 작업은 CPU/GPU를 포화시킵니다. 프로덕션 모델에 지연 시간이 급증할 수 있습니다. 항상 taint가 있는 별도의 노드 풀을 사용하세요.
- GPU 바인딩 모델을 위한 CPU의 HPA: CPU 성능이 낮을 수 있습니다. GPU 및 포화. GPU 워크로드에는 항상 사용자 지정 측정항목(지연 시간, RPS, GPU 사용률)을 사용하세요.
-
정상적인 종료 없음: ML 포드는 요청을 완료해야 합니다.
코스가 끝나기 전에. 항상 구성
terminationGracePeriodSeconds>= 30대. - Docker 이미지의 모델: 이미지에 모델 가중치 포함 Docker는 업데이트를 느리게 만들고 이미지를 거대하게 만듭니다. 별도의 모델 저장소(S3, GCS)를 사용합니다.
-
중단 없는 예산: 없이
PodDisruptionBudget, 클러스터 업데이트는 모든 모델 복제본을 동시에 제거할 수 있습니다.
SME 예산: 연간 5,000 EUR 미만으로 시작
Kubernetes에서 ML을 시작하기 위해 월 10만 달러 규모의 엔터프라이즈 클러스터가 필요하지 않습니다. 여기 예산이 제한된 SME를 위한 현실적인 스택:
- 클라우드 VM의 K3s 클러스터(노드 2개, vCPU 8개, 32GB RAM): 월 150~200유로 정도. K3s는 Rancher의 경량 Kubernetes 배포판으로 소규모 클러스터에 적합합니다.
- NVIDIA T4 GPU 노드 1개(스팟 인스턴스): 0.35-0.50 EUR/시간, 약 120-180 EUR/월 하루 12시간 사용한다면. 필요하지 않을 때는 0으로 조정하세요.
- KServe + MLflow + 프로메테우스: 모두 무료, 오픈 소스, 설치 가능 Helm을 사용하면 30분 안에 완료됩니다.
- S3 호환 스토리지(자체 호스팅 MinIO): 라이선스 비용은 0이고 스토리지만 해당됩니다. 100GB의 모델 및 데이터 세트: 클라우드 개체 스토리지 비용은 약 2-5 EUR/월입니다.
예상 총액: 월 300-400 EUR, 연간 5,000 EUR 미만 환경을 위해 GPU, 전체 모니터링 및 자동 확장을 통해 프로덕션 준비가 완료되었습니다. 비교를 위해 SageMaker 동일한 구성을 사용하면 비용이 3~5배 더 비쌉니다.
결론
Kubernetes는 다음과 같은 이유로 프로덕션 환경에 ML 모델을 배포하기 위한 업계 표준입니다. GPU 스케줄링, 이벤트 기반 자동 확장, 워크로드 격리의 고유한 조합을 제공합니다. 다른 플랫폼에서는 할 수 없는 전문 도구 생태계(KServe, Seldon, KEDA) 유연성과 장기 비용 측면에서 일치합니다.
초보자를 위한 최적의 경로: GPU 노드로 K3s 클러스터 설정, KServe 설치 첫 번째 모델을 제공하려면 모니터링을 위해 Prometheus 및 Grafana를 추가하면 됩니다. 클러스터가 생산 중인 모델이 5~10개 이상으로 성장하면 KEDA 및 Seldon Core에 투자합니다. 더 복잡한 아키텍처. Kubernetes의 복잡성은 작업량이 그것을 정당화합니다.
시리즈의 다음 기사에서는 ML 거버넌스: 보증 방법 AI Act EU 준수, SHAP 및 LIME을 통한 설명 가능성 구현, 감사 추적 관리 생산 모델의 공정성.
이 시리즈의 관련 기사
- 서비스 모델: FastAPI + Uvicorn 프로덕션 - 쿠버네티스 이전 모델
- ML 모델의 A/B 테스트 - 카나리아 출시 및 트래픽 분할
- ML 거버넌스: 규정 준수, 감사, 윤리 - 다음 기사
- 모델 드리프트 감지 및 자동 재훈련 - 고급 모니터링
시리즈 간
- 고급 딥러닝 시리즈 - K8에 배포할 복잡한 모델 훈련
- 컴퓨터 비전 시리즈 - GPU 추론에 최적화된 CV 템플릿







