Slinky・Slurm・Kubernetesハイブリッドで実現するAIクラスタのジョブスケジューリング最適化
この記事でわかること
- Slinkyプロジェクト(slurm-operator / slurm-bridge)の2コンポーネント構成とそれぞれの役割
- SlurmのHPCスケジューリングとKubernetesのコンテナオーケストレーションを1つのクラスタで共存させるアーキテクチャ
- Kueue・Volcano・Slinkyの3スケジューラのベンチマーク比較と使い分け基準
- NVIDIAの本番環境で8,000超GPUに対応した運用パターンと落とし穴
- GPU利用効率を下げずにSlurm/K8sワークロードを動的に切り替える設計手法
対象読者
- 想定読者: MLエンジニア・インフラエンジニアでGPUクラスタの運用に携わっている方
-
必要な前提知識:
- Kubernetesの基本概念(Pod、Deployment、CRD)の理解
-
kubectlコマンドの基本操作 - GPUを使った学習・推論ジョブの運用経験(Slurm未経験でもOK)
結論・成果
SlurmとKubernetesのハイブリッド構成は、2025〜2026年にかけてSlinkyプロジェクト(SchedMD/NVIDIA)とSUNK(CoreWeave)の2つのアプローチで急速に実用段階に入りました。NVIDIAの報告によると、Slinky slurm-operatorは本番環境で8,000超GPUにスケールし、NCCLベンチマーク(all-reduce / all-gather)で非コンテナ化Slurmと同等の性能を達成しています。一方、このハイブリッド構成には「ノード予約によるGPU利用効率低下」という固有の課題があり、設計段階での対策が不可欠です。
SlurmとKubernetesを統合する背景を理解する
なぜ「どちらか一方」では不十分なのか
AIクラスタの運用では、大規模分散学習と推論サービングという根本的に異なる2つのワークロードが同じGPUプールを取り合います。Slurmは2003年の誕生以来、HPC向けバッチスケジューリングの標準として「gang scheduling」(必要な全リソースを一括確保してからジョブを開始する方式)をデフォルト動作で提供してきました。一方、Kubernetesは2014年にGoogleで生まれ、ステートレスなマイクロサービスの水平スケーリングに最適化されています。
この設計思想の違いが実務上の問題を生みます。Kubernetesのデフォルトスケジューラにはgang schedulingが存在しません。70Bパラメータのモデルを64 GPUで分散学習する場合、63 GPUだけ確保できても残り1 GPUが来るまでジョブは開始できず、確保済みのGPUが無駄になります。これが「partial allocation deadlock」と呼ばれる問題です。
逆にSlurmには、推論サービングの常時稼働・オートスケールが苦手という弱点があります。SkyPilotのブログでは、Slurmでの推論サービングを「awkward(不自然)」と表現しており、Kubernetesのエコシステム(Kubeflow、KServe、Istio等)と比べるとサービングの運用ツールが不足しています。
よくある間違い: 「Slurmは古いからKubernetesに移行すればよい」と考えがちですが、Kubernetesでgang schedulingを実現するにはVolcanoやKueueといった追加プラグインが必要です。また、Kubernetesのジョブ定義YAMLは、同等のSlurmバッチスクリプトと比べて3倍以上の記述量になるという報告もあります。
Slinkyプロジェクトの全体像
SchedMD(Slurmの開発元)とNVIDIAが共同開発するSlinkyプロジェクトは、この2つの世界を橋渡しするオープンソースツールセットです。Slinkyは以下の2つのコンポーネントで構成されます。
| コンポーネント | リリース | 機能 | ユースケース |
|---|---|---|---|
| slurm-operator | 2024年11月(v0.1.0) | Slurm on K8s: Slurmクラスタ全体をK8s上で運用 | 既存SlurmワークロードのK8s移行 |
| slurm-bridge | 2025年6月(v1.0.0) | Slurm as K8s Scheduler: K8s PodをSlurmでスケジュール | K8s/Slurmワークロードの共存 |
この2つは排他的ではなく、組み合わせて使用可能です。slurm-operatorでSlurmクラスタをK8s上に構築し、slurm-bridgeで通常のK8s PodもSlurmスケジューラに統合する、という構成が推奨パターンです。
slurm-operatorでSlurmクラスタをKubernetes上に構築する
CRDベースのアーキテクチャ
slurm-operatorは、Slurmの各デーモンをKubernetesのCustom Resource Definition(CRD)として定義します。Pythonの__init__のようにオブジェクトの初期化を宣言的に定義するのと同じ発想で、Slurmクラスタの構成をYAMLで宣言的に記述できます。
Slurmの4つのコアコンポーネントがそれぞれCRDとしてマッピングされます。
# slurm-cluster.yaml - Slurmクラスタの宣言的定義(例)
# 実際のCRDスキーマはSlinky公式ドキュメントを参照
apiVersion: slinky.slurm.net/v1alpha1
kind: SlurmCluster
metadata:
name: ai-training-cluster
namespace: slurm-system
spec:
slurmctld:
replicas: 2 # HA構成
image: ghcr.io/slinkyproject/slurmctld:25.05
slurmdbd:
replicas: 1
image: ghcr.io/slinkyproject/slurmdbd:25.05
storage:
size: 100Gi # アカウンティングDB用
slurmd:
replicas: 64 # GPU計算ノード数
image: ghcr.io/slinkyproject/slurmd:25.05
resources:
limits:
nvidia.com/gpu: 8 # ノードあたり8 GPU
slurmrestd:
replicas: 2
image: ghcr.io/slinkyproject/slurmrestd:25.05
なぜCRDベースの設計を選んだか:
-
宣言的管理:
kubectl apply一発でクラスタ構成を適用。手動でのデーモン起動が不要 - 自己修復: Podがクラッシュしても、Operatorが自動で再生成(PodDisruptionBudgetで実行中ジョブを保護)
- ローリングアップデート: Slurm設定変更時にダウンタイムゼロで反映
注意: slurm-operatorは現時点で「1ワーカーPod = 1物理ノード」の前提で動作します。1ノードに複数のslurmd Podを配置する構成はサポートされていません。DaemonSet-styleスケーリング(v1.1.0〜)を使うことで、ノード追加時に自動でslurmd Podが起動します。
本番運用で確認された性能
NVIDIAの本番環境での報告によると、slurm-operatorは以下の実績を示しています。
| 指標 | 結果 | 条件 |
|---|---|---|
| スケール上限 | 8,000超GPU | 複数クラスタ構成 |
| NCCL all-reduce性能 | 非コンテナ同等 | 性能差測定不能レベル |
| NCCL all-gather性能 | 非コンテナ同等 | K8sレイヤのオーバーヘッドなし |
| ローリングアップデート | ダウンタイムゼロ | PodDisruptionBudget使用 |
出典: Running Large-Scale GPU Workloads on Kubernetes with Slurm | NVIDIA Technical Blog
制約条件: これらの数値はNVIDIAの大規模環境(DGX/HGX系ハードウェア、高速インターコネクト)での結果です。一般的なクラウドGPUインスタンス(例: AWS p4d.24xlarge)では、ネットワーク帯域の違いにより異なる結果になる可能性があります。
ハイブリッド構成: ベアメタルslurmdの統合
slurm-operatorの特徴的な機能の1つが、ベアメタルのslurmdノードをK8s上のSlurmクラスタに参加させる「ハイブリッド構成」です。これにより、既存のオンプレミスGPUサーバーを維持しながら、管理プレーン(slurmctld)だけをK8sに移行する段階的な移行が可能になります。
この構成では、slurmctldがK8s内のslurmd PodとオンプレミスのベアメタルslurmdをSlurmの統一的なビュー(パーティション)で管理します。ユーザーは srun や sbatch を通常通り使用でき、ジョブが物理マシンとコンテナのどちらで動いているかを意識する必要がありません。
slurm-bridgeでKubernetesワークロードをSlurmスケジューラに統合する
Scheduling Pluginとしてのslurm-bridge
slurm-bridgeは、KubernetesのScheduling FrameworkにSlurmをプラグインとして組み込むコンポーネントです。2025年6月にSlurm 25.05と同時にリリースされ、通常のKubernetes Podに対してSlurmのスケジューリングアルゴリズム(Backfill、Fair Share、Preemption等)を適用できます。
通常のK8sスケジューラとslurm-bridgeの動作の違いを見てみましょう。
# 通常のK8s Pod(デフォルトスケジューラ)
apiVersion: v1
kind: Pod
metadata:
name: training-job
spec:
schedulerName: default-scheduler # K8sデフォルト
containers:
- name: train
image: nvcr.io/nvidia/pytorch:24.05-py3
resources:
limits:
nvidia.com/gpu: 8
# slurm-bridgeを使うPod
apiVersion: v1
kind: Pod
metadata:
name: training-job
labels:
slurm.schedmd.com/partition: "gpu-a100"
slurm.schedmd.com/qos: "high"
slurm.schedmd.com/gres: "gpu:8"
spec:
schedulerName: slurm-bridge # Slurmスケジューラを指定
containers:
- name: train
image: nvcr.io/nvidia/pytorch:24.05-py3
resources:
limits:
nvidia.com/gpu: 8
ポイント: schedulerName を slurm-bridge に変更し、Slurm固有のラベル(partition、QoS、GRES)を付与するだけで、そのPodはSlurmのスケジューリングキューに入ります。既存のK8sワークロード(推論サービス等)は default-scheduler のまま維持できるため、段階的な導入が可能です。
Converged Clusterの実現
slurm-bridgeの真価は、1つのハードウェアプールでSlurmジョブとK8s Podを混在させる「Converged Cluster」を実現できる点です。これにより、学習ジョブ(Slurm管理)と推論サービス(K8s管理)が同じGPUノード群を共有し、時間帯やワークロードの変動に応じて動的にリソースを割り当てできます。
トレードオフ: Converged Clusterでは、SlurmがノードをDRAIN状態にしてからK8sに返却するまでの「遷移時間」が発生します。この間GPUは非生産的な状態になるため、頻繁にワークロードタイプが切り替わる環境では、専用ノードプールを分離する方が効率的な場合があります。
Kueue・Volcano・Slinkyの3スケジューラを比較する
ベンチマーク結果の概要
Kubernetesでバッチスケジューリングを実現する方法は、Slinky以外にもKueue(Google主導)とVolcano(CNCF Incubating)が存在します。Radiantのベンチマークでは、模擬GPUジョブ(nvidia/cuda:12.4.0ベース)を使って3つのスケジューラを比較しています。
| 評価項目 | Kueue | Volcano | Slinky |
|---|---|---|---|
| 設計思想 | K8sネイティブキューイング | HPC向けバッチスケジューラ | Slurm互換スケジューリング |
| 優先度制御の効果 | 66秒短縮 | 63秒短縮 | 60秒短縮 |
| プリエンプション速度 | 約1秒 | 約35秒(クロスキュー) | 1秒未満(QoS経由) |
| 障害復旧時間 | Pass | 約4秒 | Pass |
| 導入の容易さ | 中 | 低〜中 | 高(Slurm知識必要) |
| Gang Scheduling | v0.10+でサポート | ネイティブサポート | Slurm標準動作 |
出典: Benchmarking Kueue, Volcano, and Slinky on Radiant
3スケジューラの使い分け基準
それぞれのスケジューラには明確な適用領域があります。チーム構成とワークロード特性に基づいて選定してみましょう。
Kueueが適するケース:
- Kubernetesネイティブなチームで、追加のスケジューラを導入したくない
- CPU/GPUバッチジョブが混在し、軽量なキューイングレイヤが欲しい
- デフォルトの
kube-schedulerをそのまま活かしたい(Kueueはジョブの「入場管理」のみを担当し、Pod配置はkube-schedulerに委譲)
Volcanoが適するケース:
- MPI/Horovodベースの分散学習が主ワークロード
- ネットワークトポロジを考慮したGPU配置が必要
- Slurmの経験はないが、HPC的なバッチスケジューリングが必要
Slinkyが適するケース:
- 既存のSlurmクラスタ・ワークフローをKubernetesに移行したい
- Slurmの
sbatch/srunに慣れた研究者チームがいる - 1秒未満のプリエンプション(QoS経由)が必要な優先度管理
注意: Slinkyの導入にはSlurm自体の知識(パーティション設計、QoS設定、Fair Share設定等)が前提となります。Slurm未経験のチームがSlinkyから始めるのは学習コストが高く、Kueueから導入して段階的にSlinkyに移行する方が現実的です。
用語の違いに注意: 「Gang Scheduling」の意味
SlurmとKubernetesコミュニティでは「gang scheduling」の定義が異なります。この用語の混乱はアーキテクチャ設計の議論で頻繁に問題を引き起こすため、ここで整理します。
| コミュニティ | 「Gang Scheduling」の意味 |
|---|---|
| Kubernetes | 必要な全リソースを一括確保してからジョブを開始する(Slurmではデフォルト動作) |
| Slurm | 複数ジョブがリソースを時分割で共有する方式 |
SkyPilotのブログでは、「Kubernetesが『gang scheduling』と呼んでいるもの(一括リソース確保)は、Slurmのデフォルトのスケジューリング動作に過ぎない」と指摘しています。この違いを理解していないと、Volcanoの「gang scheduling対応」とSlurmの「gang scheduling対応」を同じ機能だと誤解するリスクがあります。
出典: Slurm vs K8s for AI Infra | SkyPilot Blog
SUNK(CoreWeave)との違いを理解する
SUNKの独自アーキテクチャ
SlinkyがSchedMD/NVIDIA主導であるのに対し、SUNK(Slurm on Kubernetes) はCoreWeaveが独自に開発したSlurm/K8s統合ソリューションです。SUNKは以下の3コンポーネントで構成されます。
| コンポーネント | 役割 |
|---|---|
| Nodeset CRD | Slurmノードを定義するCRD。K8sノードと1:1マッピング。ノードの準備状態、ドレイン条件、Slurm状態同期を管理 |
| Syncer | Slurm REST APIを通じた双方向の状態同期。効率的なキャッシュで大規模クラスタに対応 |
| Scheduler | カスタムK8sスケジューラ。SlurmジョブとK8s Podの混在スケジューリングを実現 |
出典: A Slurm on Kubernetes Implementation | CoreWeave
SlinkyとSUNKの選定基準
2つのソリューションは目的が近いものの、設計哲学が異なります。
| 観点 | Slinky | SUNK |
|---|---|---|
| 開発元 | SchedMD / NVIDIA | CoreWeave |
| ライセンス | OSS(Apache 2.0) | CoreWeave環境専用 |
| アーキテクチャ | Operator + Bridge の2段構成 | Nodeset + Syncer + Scheduler の3段構成 |
| 対応環境 | AWS EKS、OpenShift、汎用K8s | CoreWeaveプラットフォーム |
| ベアメタル統合 | slurmd ハイブリッド対応 | K8s内完結 |
| 適用シーン | マルチクラウド・オンプレミス混在 | CoreWeave利用者 |
ハマりポイント: SUNKはCoreWeaveのプラットフォームに最適化されているため、他のクラウド環境やオンプレミスに移植するのは困難です。マルチクラウドやオンプレミス混在環境では、Slinkyを選択するのが安全です。
GPU利用効率を最大化する運用パターンを設計する
ノード予約問題と対策
Slurm-on-K8sのハイブリッド構成で最も注意すべきは、ノード予約によるGPU利用効率の低下です。SkyPilotの分析では、Slurm-on-K8s実装が「Slurmプロセス用にK8sノードを丸ごと予約してしまい、Slurmジョブが走っていなくてもGPUが遊んでしまう」リスクを指摘しています。
この問題への対策を3つのレベルで整理します。
# 対策レベル1: パーティション分離(最もシンプル)
# slurm.conf の設定例
SLURM_PARTITION_CONFIG = """
# 学習専用パーティション(Slurm管理)
PartitionName=train
Nodes=gpu-node[001-032]
Default=YES
MaxTime=72:00:00
State=UP
# 推論専用パーティション(K8s管理、slurm-bridge経由)
PartitionName=inference
Nodes=gpu-node[033-048]
MaxTime=UNLIMITED
State=UP
# 共有パーティション(時間帯で切り替え)
PartitionName=shared
Nodes=gpu-node[049-064]
MaxTime=24:00:00
State=UP
PreemptMode=REQUEUE # 推論Podに割り込まれたらリキュー
"""
# 対策レベル2: オートスケーリング連携
# Slinky slurm-operator + Kubernetes Cluster Autoscaler
# K8s Cluster Autoscalerの設定例
AUTOSCALER_CONFIG = {
"scaleDown": {
"enabled": True,
"delayAfterAdd": "10m",
"unneededTime": "5m",
},
"nodeGroups": [
{
"name": "gpu-a100-pool",
"minSize": 8, # 最小8ノード(常時稼働)
"maxSize": 64, # 最大64ノード(バースト対応)
"instanceType": "p4d.24xlarge",
}
],
}
# slurm-operatorのautoscaling設定
# ワークロードの増減に応じてslurmd Podを自動スケール
# drain-before-terminate でジョブ安全に終了後にスケールイン
# 対策レベル3: QoSベースの優先度管理
# slurm.conf の QoS設定例
QOS_CONFIG = """
# 高優先度: 大規模学習ジョブ(プリエンプション権限あり)
# sacctmgr add qos high_priority Priority=1000 Preempt=low_priority
# 低優先度: 実験・探索ジョブ(プリエンプトされうる)
# sacctmgr add qos low_priority Priority=100 PreemptMode=requeue
# 推論: 常時稼働(プリエンプトされない)
# sacctmgr add qos inference Priority=500 Preempt= PreemptMode=off
"""
Prometheus/Grafanaによる統合監視
Slurm-on-K8s環境では、SlurmメトリクスとKubernetesメトリクスの統合監視が運用の鍵になります。slurm-operatorはPrometheusメトリクスエクスポーターを内蔵しており、以下のようなメトリクスを公開します。
| メトリクス | 説明 | 用途 |
|---|---|---|
slurm_jobs_pending |
待機中ジョブ数 | キュー詰まりの検知 |
slurm_jobs_running |
実行中ジョブ数 | クラスタ使用率の把握 |
slurm_nodes_idle |
アイドルノード数 | スケールダウン判断 |
slurm_scheduler_latency_seconds |
スケジューリング遅延 | スケジューラの健全性 |
slurm_partition_gpu_utilization |
パーティション別GPU使用率 | リソース配分の最適化 |
これらをKubernetesの標準メトリクス(kube_pod_status_phase、node_gpu_utilization 等)と同じGrafanaダッシュボードに統合することで、「Slurmジョブが詰まっているのにK8s側のGPUノードが遊んでいる」といった非効率を即座に検知できます。
# prometheus-slurm-exporter の ServiceMonitor設定例
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: slurm-metrics
namespace: slurm-system
spec:
selector:
matchLabels:
app: slurm-exporter
endpoints:
- port: metrics
interval: 30s
path: /metrics
よくある問題と解決方法
| 問題 | 原因 | 解決方法 |
|---|---|---|
slurmd PodがCrashLoopBackOff
|
Slurm設定ファイルの不整合 | ConfigMapのslurm.confを確認。SlurmctldParameters=enable_configlessが有効か確認 |
| ジョブ投入後にPendingのまま進まない | パーティションのノード数不足 or GRES設定ミス |
scontrol show partition と scontrol show node でリソース状態を確認 |
| NCCLテストで性能低下 | Pod間のネットワーク設定不備 | hostNetworkモード or Multus CNIでRDMA/GPUDirectを有効化 |
| slurm-bridgeでPodがスケジュールされない |
schedulerNameの指定漏れ |
Pod spec に schedulerName: slurm-bridge を明示 |
| スケールイン時にジョブが中断 | PodDisruptionBudget未設定 |
minAvailable を設定し、実行中ジョブのあるノードを保護 |
| Slurmアカウンティングが記録されない | slurmdbd Podのストレージ不足 | PersistentVolumeClaimのサイズを拡大。定期的なsacctmgrでのパージを設定 |
まとめと次のステップ
まとめ:
- Slinkyプロジェクトはslurm-operator(Slurm on K8s)とslurm-bridge(Slurm as K8s Scheduler)の2コンポーネントで構成され、NVIDIAの本番環境で8,000超GPUの実績がある
- 3スケジューラの使い分け: K8sネイティブならKueue、HPC/MPIならVolcano、Slurm移行ならSlinky。プリエンプション速度ではSlinkyが1秒未満で最速
- GPU利用効率の最大化にはパーティション分離、オートスケーリング連携、QoSベースの優先度管理の3段階の対策が有効
- ハイブリッド構成(ベアメタルslurmd + K8s上slurmd)により、既存環境を維持しながらの段階的移行が可能
次にやるべきこと:
- Slinky公式ドキュメントのQuick Startで、ローカルKindクラスタ上にslurm-operatorを試す
- チームのワークロード特性(学習/推論の比率、ジョブサイズ分布)を整理し、パーティション設計を検討する
- 既存のSlurm環境がある場合は、slurmctldだけをK8sに移行するハイブリッド構成から始める
参考
- Running Large-Scale GPU Workloads on Kubernetes with Slurm | NVIDIA Technical Blog
- Introducing the Slinky Project | SchedMD
- Slinky公式ドキュメント
- GitHub - SlinkyProject/slurm-operator
- GitHub - SlinkyProject/slurm-bridge
- Running Slurm on Amazon EKS with Slinky | AWS
- How to run Slurm workloads on OpenShift with Slinky operator | Red Hat Developer
- Benchmarking Kueue, Volcano, and Slinky on Radiant
- Slurm vs K8s for AI Infra: Academic HPC vs Cloud-Native Reality | SkyPilot Blog
- A Slurm on Kubernetes Implementation for HPC and Large Scale AI | CoreWeave
- Slurm on Kubernetes (SUNK): Modernizing HPC and AI workload management | Medium
注意: この記事はAI(Claude Code)により自動生成されました。内容の正確性については複数の情報源で検証していますが、実際の利用時は公式ドキュメントもご確認ください。