- Authors

- Name
- Youngju Kim
- @fjvbn20031
目次
1. KarpenterによるGPUノードプロビジョニング
GPUワークロードの特殊性
AI/MLワークロードは一般的なコンピューティングとは異なる固有の要件があります:
+---------------------------------------------------------------+
| GPUワークロードの特性 |
+---------------------------------------------------------------+
| - 高額なGPUインスタンス(1時間あたり数〜数十ドル) |
| - 長時間の学習ジョブ(数時間〜数日) |
| - 推論作業の低レイテンシ要件 |
| - GPUメモリ(VRAM)ベースのリソース制約 |
| - インスタンスタイプ別のGPU性能差が大きい |
| - Spot中断時の学習進捗損失リスク |
+---------------------------------------------------------------+
KarpenterがGPU管理に適している理由
+------------------------------------------+
| 従来方式(Cluster Autoscaler) |
| |
| GPU Node Group A: p3.2xlarge |
| GPU Node Group B: g5.xlarge |
| GPU Node Group C: g5.2xlarge |
| GPU Node Group D: p4d.24xlarge |
| ... |
| 各Node Groupを個別管理(非効率) |
+------------------------------------------+
+------------------------------------------+
| Karpenter方式 |
| |
| 単一のGPU NodePool: |
| - Pod要件の分析 |
| - 最適なGPUインスタンスを自動選択 |
| - Spot/On-Demandの自動切替 |
| - コストベースのインスタンス最適化 |
+------------------------------------------+
2. GPU NodePool設定
汎用GPU NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-general
spec:
template:
metadata:
labels:
node-type: gpu
workload: ai-ml
spec:
requirements:
# GPUインスタンスのみ選択
- key: karpenter.k8s.aws/instance-gpu-count
operator: Gt
values: ['0']
# GPUインスタンスファミリー
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['g', 'p']
# 容量タイプ
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand', 'spot']
# アベイラビリティゾーン
- key: topology.kubernetes.io/zone
operator: In
values: ['ap-northeast-1a', 'ap-northeast-1c', 'ap-northeast-1d']
# x86アーキテクチャのみ
- key: kubernetes.io/arch
operator: In
values: ['amd64']
# GPU専用taint
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-optimized
# GPUノードは長い有効期限
expireAfter: 336h # 14日
limits:
cpu: '500'
memory: 2000Gi
nvidia.com/gpu: '100'
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 5m
budgets:
- nodes: '1'
weight: 80
AWS GPUインスタンスタイプガイド
+------------------+----------+----------+------------------+---------------------+
| インスタンス | GPU | 数量 | GPUメモリ | 主な用途 |
+------------------+----------+----------+------------------+---------------------+
| g4dn.xlarge | T4 | 1 | 16 GB | 推論、軽量学習 |
| g4dn.12xlarge | T4 | 4 | 64 GB | マルチ推論 |
| g5.xlarge | A10G | 1 | 24 GB | 推論、微調整 |
| g5.12xlarge | A10G | 4 | 96 GB | 中型学習 |
| g5.48xlarge | A10G | 8 | 192 GB | 大型学習 |
| g6.xlarge | L4 | 1 | 24 GB | 推論最適化 |
| g6.12xlarge | L4 | 4 | 96 GB | マルチモーダル推論 |
| p3.2xlarge | V100 | 1 | 16 GB | 汎用学習 |
| p3.8xlarge | V100 | 4 | 64 GB | 大規模学習 |
| p4d.24xlarge | A100 | 8 | 320 GB (40GB x8) | 超大規模学習 |
| p5.48xlarge | H100 | 8 | 640 GB (80GB x8) | 最高性能学習 |
+------------------+----------+----------+------------------+---------------------+
推論専用NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-inference
spec:
template:
metadata:
labels:
node-type: gpu-inference
workload: inference
spec:
requirements:
# 推論に適したインスタンス
- key: karpenter.k8s.aws/instance-gpu-name
operator: In
values: ['t4', 'a10g', 'l4']
# Spotインスタンス優先(推論はstateless)
- key: karpenter.sh/capacity-type
operator: In
values: ['spot', 'on-demand']
# インスタンスサイズ制限
- key: karpenter.k8s.aws/instance-size
operator: In
values: ['xlarge', '2xlarge', '4xlarge']
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-optimized
limits:
nvidia.com/gpu: '50'
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 2m
weight: 60
学習専用NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-training
spec:
template:
metadata:
labels:
node-type: gpu-training
workload: training
spec:
requirements:
# 学習に適した高性能GPU
- key: karpenter.k8s.aws/instance-gpu-name
operator: In
values: ['a100', 'h100', 'a10g']
# On-Demand専用(学習の中断コストが高い)
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand']
# 大型インスタンス
- key: karpenter.k8s.aws/instance-gpu-count
operator: Gt
values: ['0']
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-training
# 学習用ノードは有効期限なし
expireAfter: 720h # 30日
limits:
nvidia.com/gpu: '32'
disruption:
# 学習中のConsolidation無効化
consolidationPolicy: WhenEmpty
consolidateAfter: 30m
budgets:
- nodes: '0'
weight: 90
3. GPU専用EC2NodeClass
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: gpu-optimized
spec:
# GPUドライバ対応AMI
amiSelectorTerms:
- alias: al2023@latest
role: KarpenterNodeRole-my-cluster
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
network-type: private
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
# GPUワークロード用大容量ディスク
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 200Gi
volumeType: gp3
iops: 6000
throughput: 250
encrypted: true
deleteOnTermination: true
metadataOptions:
httpEndpoint: enabled
httpPutResponseHopLimit: 2
httpTokens: required
tags:
Environment: production
NodeType: gpu
ManagedBy: karpenter
# GPUドライバインストール用ユーザーデータ
userData: |
#!/bin/bash
echo "GPU node bootstrap"
# NVIDIAドライバはGPU Operatorが処理
学習専用EC2NodeClass(大容量ストレージ)
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: gpu-training
spec:
amiSelectorTerms:
- alias: al2023@latest
role: KarpenterNodeRole-my-cluster
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
# 学習データ用大容量・高性能ストレージ
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 500Gi
volumeType: gp3
iops: 16000
throughput: 1000
encrypted: true
deleteOnTermination: true
tags:
Environment: production
NodeType: gpu-training
ManagedBy: karpenter
4. Spot GPUインスタンス戦略
Spot GPUのコスト削減効果
+------------------+-------------------+-------------------+---------+
| インスタンス | On-Demand (時間) | Spot予想 (時間) | 削減率 |
+------------------+-------------------+-------------------+---------+
| g4dn.xlarge | ~0.526 | ~0.158 | ~70% |
| g5.xlarge | ~1.006 | ~0.302 | ~70% |
| g5.2xlarge | ~1.212 | ~0.364 | ~70% |
| g5.12xlarge | ~5.672 | ~1.702 | ~70% |
| p3.2xlarge | ~3.060 | ~0.918 | ~70% |
+------------------+-------------------+-------------------+---------+
(価格はリージョンと時期により変動します)
Spot GPU NodePool - 推論用
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-spot-inference
spec:
template:
metadata:
labels:
node-type: gpu-spot
workload: inference
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['spot']
# 推論に適した多様なGPUタイプ
- key: karpenter.k8s.aws/instance-gpu-name
operator: In
values: ['t4', 'a10g', 'l4']
# 多様なサイズでSpot可用性確保
- key: karpenter.k8s.aws/instance-size
operator: In
values: ['xlarge', '2xlarge', '4xlarge', '8xlarge', '12xlarge']
# 複数AZ活用
- key: topology.kubernetes.io/zone
operator: In
values: ['ap-northeast-1a', 'ap-northeast-1c', 'ap-northeast-1d']
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-optimized
limits:
nvidia.com/gpu: '40'
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 1m
weight: 70
Spot中断対策
# 長時間学習ジョブにdo-not-disruptアノテーションを適用
apiVersion: v1
kind: Pod
metadata:
name: training-job
annotations:
karpenter.sh/do-not-disrupt: 'true'
spec:
containers:
- name: training
image: my-training-image:latest
resources:
requests:
nvidia.com/gpu: '1'
cpu: '4'
memory: 16Gi
limits:
nvidia.com/gpu: '1'
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
terminationGracePeriodSeconds: 120
5. NVIDIA GPU Operator連携
GPU Operatorの概要
+----------------------------------------------------------------+
| NVIDIA GPU Operator |
| |
| +------------------+ +-------------------+ +--------------+ |
| | NVIDIAドライバ | | Container Toolkit | | Device Plugin| |
| | (自動インストール)| | (自動設定) | | (自動デプロイ)| |
| +------------------+ +-------------------+ +--------------+ |
| |
| +------------------+ +-------------------+ +--------------+ |
| | GPU Feature | | DCGM Exporter | | MIG Manager | |
| | Discovery | | (メトリクス収集) | | (MIG管理) | |
| +------------------+ +-------------------+ +--------------+ |
+----------------------------------------------------------------+
GPU Operatorのインストール
# NVIDIA GPU Operator Helmリポジトリ追加
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
# GPU Operatorインストール
helm install gpu-operator nvidia/gpu-operator \
--namespace gpu-operator \
--create-namespace \
--set driver.enabled=true \
--set toolkit.enabled=true \
--set devicePlugin.enabled=true \
--set dcgmExporter.enabled=true \
--set migManager.enabled=false \
--set gfd.enabled=true
GPU OperatorとKarpenterの連携確認
# GPUノードのラベル確認
kubectl get nodes -l node-type=gpu -o json | \
jq '.items[].metadata.labels | with_entries(select(.key | startswith("nvidia")))'
# GPUリソース確認
kubectl describe node gpu-node-name | grep -A 5 "nvidia.com/gpu"
# DCGM Exporter Pod確認
kubectl get pods -n gpu-operator -l app=nvidia-dcgm-exporter
GPUワークロードデプロイ例
apiVersion: apps/v1
kind: Deployment
metadata:
name: gpu-inference-server
namespace: ml-serving
spec:
replicas: 3
selector:
matchLabels:
app: inference-server
template:
metadata:
labels:
app: inference-server
spec:
containers:
- name: inference
image: nvcr.io/nvidia/tritonserver:24.01-py3
ports:
- containerPort: 8000
name: http
- containerPort: 8001
name: grpc
- containerPort: 8002
name: metrics
resources:
requests:
cpu: '4'
memory: 16Gi
nvidia.com/gpu: '1'
limits:
nvidia.com/gpu: '1'
volumeMounts:
- name: model-store
mountPath: /models
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
nodeSelector:
node-type: gpu-inference
volumes:
- name: model-store
persistentVolumeClaim:
claimName: model-store-pvc
6. マルチアーキテクチャサポート(x86 + ARM/Graviton)
マルチアーキテクチャNodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: multi-arch
spec:
template:
spec:
requirements:
# x86とARMの両方を許可
- key: kubernetes.io/arch
operator: In
values: ['amd64', 'arm64']
# Gravitonインスタンスを含む
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['c', 'm', 'r']
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ['5']
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand', 'spot']
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
limits:
cpu: '1000'
memory: 2000Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 1m
GravitonのGPU代替:Inferentia/Trainium
# AWS Inferentia推論専用NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: inferentia
spec:
template:
metadata:
labels:
accelerator: inferentia
spec:
requirements:
- key: node.kubernetes.io/instance-type
operator: In
values: ['inf2.xlarge', 'inf2.8xlarge', 'inf2.24xlarge', 'inf2.48xlarge']
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand']
taints:
- key: aws.amazon.com/neuron
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: inferentia-nodes
limits:
aws.amazon.com/neuron: '32'
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 5m
7. コスト最適化戦略
SpotとOn-Demandの混合戦略
+-------------------------------------------------------------+
| コスト最適化の意思決定ツリー |
+-------------------------------------------------------------+
| |
| ワークロードタイプの確認 |
| | |
| +-- 推論 (Stateless) --> Spot優先 + On-Demand代替 |
| | |
| +-- 微調整 (短期) --> Spot + チェックポイント戦略 |
| | |
| +-- 大規模学習 (長期) --> On-Demand + リザーブド |
| | |
| +-- バッチ処理 --> Spot専用 |
| |
+-------------------------------------------------------------+
重み付き優先順位によるインスタンスファミリー戦略
# 第1優先:G5 Spot(最もコスト効率的な推論)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-tier1-g5-spot
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['spot']
- key: karpenter.k8s.aws/instance-gpu-name
operator: In
values: ['a10g']
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['g']
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-optimized
weight: 100
limits:
nvidia.com/gpu: '20'
---
# 第2優先:G4dn Spot(フォールバック)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-tier2-g4dn-spot
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['spot']
- key: karpenter.k8s.aws/instance-gpu-name
operator: In
values: ['t4']
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['g']
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-optimized
weight: 50
limits:
nvidia.com/gpu: '20'
---
# 第3優先:G5 On-Demand(最終手段)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-tier3-g5-ondemand
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand']
- key: karpenter.k8s.aws/instance-gpu-name
operator: In
values: ['a10g']
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['g']
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-optimized
weight: 10
limits:
nvidia.com/gpu: '10'
Consolidationポリシーの最適化
# GPUノードのConsolidation設定
disruption:
# GPUノードはWhenEmptyのみ使用(実行中のGPUジョブを保護)
consolidationPolicy: WhenEmpty
# 空ノード検知後5分待機(一時的な非アクティブを考慮)
consolidateAfter: 5m
budgets:
# 同時に最大1ノードのみ中断
- nodes: '1'
# 業務時間中は中断をブロック
- nodes: '0'
schedule: '0 9 * * MON-FRI'
duration: 10h
8. ノード中断バジェット(Node Disruption Budgets)
GPUワークロード用Disruption Budget
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-training-protected
spec:
template:
spec:
requirements:
- key: karpenter.k8s.aws/instance-gpu-count
operator: Gt
values: ['0']
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand']
taints:
- key: nvidia.com/gpu
value: 'true'
effect: NoSchedule
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: gpu-training
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 30m
budgets:
# 学習時間中は中断を完全にブロック
- nodes: '0'
schedule: '0 0 * * *'
duration: 23h
# メンテナンスウィンドウ(毎日1時間)
- nodes: '1'
schedule: '0 23 * * *'
duration: 1h
# ドリフトによる中断は別途管理
- nodes: '1'
reasons:
- 'Drifted'
Podレベルの保護
# 長時間学習Pod:Karpenterの中断を防止
apiVersion: v1
kind: Pod
metadata:
name: long-training-job
annotations:
# このアノテーションでKarpenterの自発的中断を防止
karpenter.sh/do-not-disrupt: 'true'
spec:
containers:
- name: trainer
image: my-training-image:v1
resources:
requests:
nvidia.com/gpu: '4'
cpu: '16'
memory: 64Gi
limits:
nvidia.com/gpu: '4'
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
# 十分な終了猶予時間(チェックポイント保存)
terminationGracePeriodSeconds: 300
PDB(Pod Disruption Budget)設定
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: inference-server-pdb
namespace: ml-serving
spec:
minAvailable: 2
selector:
matchLabels:
app: inference-server
9. Prometheus/Grafanaによるモニタリング
Karpenterメトリクス収集設定
# Karpenter ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: karpenter
namespace: karpenter
spec:
selector:
matchLabels:
app.kubernetes.io/name: karpenter
endpoints:
- port: http-metrics
interval: 15s
path: /metrics
主要なKarpenterメトリクス
+-----------------------------------------------+------------------------------------------+
| メトリクス | 説明 |
+-----------------------------------------------+------------------------------------------+
| karpenter_nodeclaims_launched_total | 起動されたNodeClaim総数 |
| karpenter_nodeclaims_registered_total | 登録されたNodeClaim総数 |
| karpenter_nodeclaims_terminated_total | 終了されたNodeClaim総数 |
| karpenter_pods_state | Pod状態(ノード、ネームスペース等) |
| karpenter_nodepool_usage | NodePool別リソース使用量 |
| karpenter_nodepool_limit | NodePool別リソース制限 |
| karpenter_voluntary_disruption_eligible_nodes | 自発的中断対象ノード数 |
| karpenter_disruption_actions_performed_total | 実行された中断アクション数 |
| karpenter_nodes_allocatable | ノード別割当可能リソース |
| karpenter_nodes_total_daemon_requests | DaemonSetリソース要求合計 |
+-----------------------------------------------+------------------------------------------+
GPU専用Grafanaダッシュボードクエリ
# GPUノード数の追跡
count(karpenter_nodes_allocatable{resource_type="nvidia.com/gpu"} > 0)
# GPU使用率(DCGM Exporter必要)
DCGM_FI_DEV_GPU_UTIL
# NodePool別GPU使用量 vs 制限
karpenter_nodepool_usage{resource_type="nvidia.com/gpu"}
/
karpenter_nodepool_limit{resource_type="nvidia.com/gpu"}
# プロビジョニングレイテンシ
histogram_quantile(0.99,
rate(karpenter_provisioner_scheduling_duration_seconds_bucket[5m])
)
DCGM Exporterメトリクス
# DCGM Exporter ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: dcgm-exporter
namespace: gpu-operator
spec:
selector:
matchLabels:
app: nvidia-dcgm-exporter
endpoints:
- port: metrics
interval: 15s
アラートルール例
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: karpenter-gpu-alerts
namespace: monitoring
spec:
groups:
- name: karpenter-gpu
rules:
# GPU NodePoolが制限の90%に到達
- alert: GPUNodePoolNearLimit
expr: |
karpenter_nodepool_usage{nodepool="gpu-general", resource_type="nvidia.com/gpu"}
/
karpenter_nodepool_limit{nodepool="gpu-general", resource_type="nvidia.com/gpu"}
> 0.9
for: 5m
labels:
severity: warning
annotations:
summary: 'GPU NodePoolがリソース制限に近づいています'
# GPU使用率が低いノードの検知
- alert: LowGPUUtilization
expr: |
avg_over_time(DCGM_FI_DEV_GPU_UTIL[30m]) < 10
for: 1h
labels:
severity: info
annotations:
summary: 'GPU使用率が1時間にわたり10%未満です'
# Karpenterプロビジョニング失敗
- alert: KarpenterProvisioningFailed
expr: |
increase(karpenter_nodeclaims_terminated_total{reason="ProvisioningFailed"}[15m]) > 0
labels:
severity: critical
annotations:
summary: 'KarpenterがGPUノードのプロビジョニングに失敗しました'
10. 実践例:学習クラスタ
分散学習クラスタの構成
# PyTorch分散学習Job
apiVersion: batch/v1
kind: Job
metadata:
name: distributed-training
namespace: ml-training
spec:
parallelism: 4
completions: 4
template:
metadata:
labels:
app: distributed-training
annotations:
karpenter.sh/do-not-disrupt: 'true'
spec:
containers:
- name: pytorch-trainer
image: my-pytorch-training:v1
command: ['torchrun']
args:
- '--nproc_per_node=1'
- '--nnodes=4'
- '--node_rank=$(JOB_COMPLETION_INDEX)'
- '--master_addr=training-master'
- '--master_port=29500'
- 'train.py'
env:
- name: JOB_COMPLETION_INDEX
valueFrom:
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
resources:
requests:
cpu: '8'
memory: 32Gi
nvidia.com/gpu: '1'
limits:
nvidia.com/gpu: '1'
volumeMounts:
- name: shared-data
mountPath: /data
- name: checkpoints
mountPath: /checkpoints
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
nodeSelector:
node-type: gpu-training
restartPolicy: OnFailure
volumes:
- name: shared-data
persistentVolumeClaim:
claimName: training-data-pvc
- name: checkpoints
persistentVolumeClaim:
claimName: checkpoint-pvc
11. 実践例:推論クラスタ
オートスケーリング推論サービス
# 推論Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: llm-inference
namespace: ml-serving
spec:
replicas: 2
selector:
matchLabels:
app: llm-inference
template:
metadata:
labels:
app: llm-inference
spec:
containers:
- name: vllm-server
image: vllm/vllm-openai:latest
args:
- '--model'
- 'meta-llama/Llama-3-8B'
- '--tensor-parallel-size'
- '1'
- '--gpu-memory-utilization'
- '0.9'
ports:
- containerPort: 8000
name: http
resources:
requests:
cpu: '4'
memory: 16Gi
nvidia.com/gpu: '1'
limits:
nvidia.com/gpu: '1'
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60
periodSeconds: 10
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
nodeSelector:
node-type: gpu-inference
---
# HPA設定
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: llm-inference-hpa
namespace: ml-serving
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: llm-inference
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: gpu_utilization
target:
type: AverageValue
averageValue: '70'
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 120
12. トラブルシューティングガイド
一般的なGPUノードの問題
# 1. GPUリソースが表示されない場合
kubectl describe node gpu-node | grep -A 10 "Allocatable"
# nvidia.com/gpuがない場合、GPU Operatorを確認
# 2. GPU Operator Podの状態確認
kubectl get pods -n gpu-operator
kubectl logs -n gpu-operator -l app=nvidia-driver-daemonset
# 3. Karpenterプロビジョニングログの確認
kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter \
| grep -i "gpu\|nvidia\|instance-type"
# 4. NodeClaimの状態確認
kubectl get nodeclaims -o wide
# 5. Pending Podの原因分析
kubectl describe pod gpu-pod-name | grep -A 20 "Events"
よくある問題と解決方法
+---------------------------------------------+------------------------------------------+
| 問題 | 解決方法 |
+---------------------------------------------+------------------------------------------+
| GPUリソースがノードに表示されない | GPU Operatorの再インストールまたは |
| | ドライバの確認 |
| Spot GPUインスタンスが見つからない | より多くのGPUインスタンスタイプとAZを追加|
| GPUノードプロビジョニングがタイムアウト | EC2NodeClassのサブネット/SGタグを確認 |
| 学習中にノードが中断された | do-not-disruptアノテーションを追加 |
| GPUメモリ不足(OOM) | より大きなGPUインスタンスタイプを許可 |
| 不要なGPUノードが維持されている | Consolidationポリシーと |
| | consolidateAfter値を確認 |
| 特定のGPUタイプのみプロビジョニングされる | NodePool requirements範囲を拡張 |
+---------------------------------------------+------------------------------------------+
GPUメモリデバッグ
# ノード上で直接GPU状態を確認(デバッグPod使用)
kubectl run gpu-debug --rm -it \
--image=nvidia/cuda:12.0.0-base-ubuntu22.04 \
--overrides='{"spec":{"tolerations":[{"key":"nvidia.com/gpu","operator":"Exists","effect":"NoSchedule"}],"nodeSelector":{"node-type":"gpu"}}}' \
--restart=Never \
-- nvidia-smi
13. ベストプラクティスまとめ
GPUノード管理チェックリスト
+---+------------------------------------------------------------+
| # | ベストプラクティス |
+---+------------------------------------------------------------+
| 1 | 推論と学習ワークロードのNodePoolを分離 |
| 2 | GPU taintを設定して非GPUワークロードのスケジューリングを防止|
| 3 | 推論はSpot、学習はOn-Demandを使用 |
| 4 | 長時間学習にdo-not-disruptアノテーションを適用 |
| 5 | チェックポイント戦略で学習進捗を保護 |
| 6 | GPU Operatorでドライバ管理を自動化 |
| 7 | DCGM ExporterでGPUメトリクスを収集 |
| 8 | NodePool limitsでGPUコスト上限を設定 |
| 9 | 複数のGPUインスタンスタイプを許可して可用性を確保 |
| 10| PDBで推論サービスの最小可用性を保証 |
| 11| Disruption Budgetで学習時間中の中断をブロック |
| 12| HPAとKarpenterを連携して自動スケーリングを実現 |
+---+------------------------------------------------------------+
コスト最適化戦略まとめ
戦略1:階層型NodePool
- Spot GPU(高い重み) -> On-Demand GPU(低い重み)
- 推論ワークロードに最適
戦略2:インスタンス多角化
- 複数のGPUファミリー(g4dn、g5、g6)を許可
- 複数のインスタンスサイズを許可
- Spot可用性を最大化
戦略3:自動スケールダウン
- WhenEmpty consolidationで空のGPUノードを即座に削除
- consolidateAfterを短く設定(推論)
- 学習ノードはより長い待機時間を設定
戦略4:適切なリソース制限
- NodePool limitsで最大GPU数を制限
- 予期しないコスト暴走を防止
- チーム/プロジェクト別の割当量を管理
Karpenter + GPU最終アーキテクチャ図
+---------------------------------------------------------------------+
| EKS Cluster |
| |
| +-------------------+ +-------------------+ +-----------------+ |
| | NodePool: | | NodePool: | | NodePool: | |
| | gpu-inference | | gpu-training | | multi-arch | |
| | (Spot, weight:60) | | (OD, weight:90) | | (Mixed, w:50) | |
| +--------+----------+ +--------+----------+ +--------+--------+ |
| | | | |
| +--------v----------+ +--------v----------+ +--------v--------+ |
| | EC2NodeClass: | | EC2NodeClass: | | EC2NodeClass: | |
| | gpu-optimized | | gpu-training | | default | |
| | (200GB, gp3) | | (500GB, gp3) | | (100GB, gp3) | |
| +-------------------+ +-------------------+ +-----------------+ |
| |
| +-------------------+ +-------------------+ |
| | GPU Operator | | Prometheus + | |
| | (NVIDIAドライバ、 | | Grafana | |
| | Device Plugin、 | | (Karpenter + | |
| | DCGM Exporter) | | DCGMメトリクス) | |
| +-------------------+ +-------------------+ |
+---------------------------------------------------------------------+