LabHub

ブログ

KServe モデルサービング完全ガイド:InferenceService・Canaryデプロイ・Transformer・InferenceGraph プロダクション運用

한국어English日本語中文

KServe モデルサービング

はじめに

ML モデルを学習させることと、プロダクション環境で安定してサービングすることは、本質的に異なるエンジニアリング課題である。学習段階では GPU 使用率と収束速度が中心だが、サービング段階ではレイテンシ、スループット、バージョン管理、安全なロールアウト、障害復旧が決定的になる。特に複数のモデルが相互作用する複合推論パイプラインでは、単に Flask にモデルを載せる方式では運用の複雑さに耐えられない。

KServe(旧 KFServing)は、こうしたプロダクションのモデルサービング問題を Kubernetes ネイティブな方式で解決するために設計された CNCF Incubating プロジェクトである。InferenceService CRD によって宣言的にモデルを配備し、Knative ベースのオートスケーリングでトラフィック変動に対応し、Canary 配備で安全なロールアウトを行い、InferenceGraph で DAG ベースの複合推論を構成できる。

KServe は 2019 年に KFServing という名前で Kubeflow プロジェクトの一部として始まり、2021 年に独立プロジェクトとして分離される際に KServe へリブランドされた。2023 年に CNCF Sandbox へ加わったあと急速に成長し、2025 年に Incubating 段階へ昇格した。TFServing、TorchServe、Triton、vLLM など主要な推論ランタイムをすべてサポートし、LLM 時代に合わせて vLLM バックエンドや Envoy AI Gateway との連携まで広げている。

本記事では、KServe の中心的なアーキテクチャからプロダクション運用戦略まで、実務で必要になるすべてをコードとともに扱う。

InferenceService CRD の詳細

Predictor / Transformer / Explainer のアーキテクチャ

KServe の InferenceService は、三つの中心的なコンポーネントで構成される。

Client Request
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
Transformer │────▶│  Predictor  │────▶│  Explainer (前処理/ (モデル推論) (説明生成)│  後処理)    │◀────│             │     │             │
└─────────────┘     └─────────────┘     └─────────────┘
Client Response

対応ランタイムの比較

ランタイムフレームワークGPU 対応動的バッチLLM サービング主な用途
TFServingTensorFlowOOXTF SavedModel のサービング
TorchServePyTorchOOXPyTorch モデルのサービング
TritonマルチフレームワークOOO複数モデルの同時サービング
vLLMPyTorch/HuggingFaceOOOLLM 推論の最適化
SklearnScikit-learnXXX軽量な ML モデル
XGBoostXGBoostOXX勾配ブースティング
LGBMLightGBMXXX勾配ブースティング

基本的な InferenceService の YAML

最も基本的な形の InferenceService は Predictor だけを定義する。以下は S3 に保存された Sklearn モデルをサービングする例である。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: sklearn-iris
  namespace: ml-serving
  annotations:
    serving.kserve.io/deploymentMode: Serverless
spec:
  predictor:
    minReplicas: 1
    maxReplicas: 10
    scaleTarget: 5
    scaleMetric: concurrency
    model:
      modelFormat:
        name: sklearn
      storageUri: 's3://ml-models/sklearn/iris/v1'
      resources:
        requests:
          cpu: '500m'
          memory: '512Mi'
        limits:
          cpu: '1'
          memory: '1Gi'

この YAML を適用すると、KServe コントローラが Knative Service を作成し、Istio VirtualService でルーティングを設定し、Knative Pod Autoscaler が concurrency ベースでオートスケーリングを行う。

vLLM バックエンドでの LLM サービング

KServe は v0.13 から vLLM を1 級のランタイムとしてサポートする。OpenAI 互換 API を自動的に公開するため、既存の OpenAI クライアントコードをそのまま使える。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: llama3-vllm
  namespace: ml-serving
spec:
  predictor:
    minReplicas: 1
    maxReplicas: 4
    model:
      modelFormat:
        name: vLLM
      storageUri: 'pvc://llm-model-cache/Meta-Llama-3.1-8B-Instruct'
      args:
        - '--max-model-len=8192'
        - '--gpu-memory-utilization=0.90'
        - '--enable-chunked-prefill'
        - '--max-num-batched-tokens=16384'
        - '--tensor-parallel-size=2'
      resources:
        requests:
          cpu: '8'
          memory: '32Gi'
          nvidia.com/gpu: '2'
        limits:
          cpu: '16'
          memory: '64Gi'
          nvidia.com/gpu: '2'
    tolerations:
      - key: 'nvidia.com/gpu'
        operator: 'Exists'
        effect: 'NoSchedule'
    nodeSelector:
      gpu-type: 'a100'

storageUri に PVC を指定すると、大容量の LLM 重みをあらかじめノードにキャッシュしておき、素早くロードできる。tensor-parallel-size=2 は 2 枚の GPU にモデルを分散配置し、単一 GPU のメモリ限界を克服する。

Canary 配備の戦略

canaryTrafficPercent を活用した段階的ロールアウト

プロダクションでモデルを更新するとき、最も危険な瞬間は新バージョンの配備直後である。KServe は canaryTrafficPercent フィールドによって、トラフィックを段階的に新バージョンへ移す Canary 配備をネイティブにサポートする。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: fraud-detector
  namespace: ml-serving
  annotations:
    serving.kserve.io/deploymentMode: Serverless
spec:
  predictor:
    canaryTrafficPercent: 10
    minReplicas: 2
    maxReplicas: 20
    model:
      modelFormat:
        name: sklearn
      storageUri: 's3://ml-models/fraud/v2'
      resources:
        requests:
          cpu: '1'
          memory: '2Gi'
        limits:
          cpu: '2'
          memory: '4Gi'

上の設定は、新しいモデル(v2)へ全トラフィックの 10% だけをルーティングし、残りの 90% は既存の安定版へ送る。配備後にモニタリングで新バージョンの性能を検証したうえで、canaryTrafficPercent を段階的に上げていく。

段階的な切り替えスクリプト

段階的ロールアウトを自動化するスクリプトを書けば、手作業のミスを減らせる。

#!/bin/bash
# canary-promote.sh - 段階的な Canary プロモーションスクリプト
ISVC_NAME="fraud-detector"
NAMESPACE="ml-serving"
STAGES=(10 30 50 80 100)
MAX_ERROR_RATE=0.05
OBSERVE_MINUTES=10

for pct in "${STAGES[@]}"; do
  echo "=== Canary traffic を ${pct}% へ更新 ==="

  kubectl patch inferenceservice "$ISVC_NAME" -n "$NAMESPACE" \
    --type='json' \
    -p="[{\"op\": \"replace\", \"path\": \"/spec/predictor/canaryTrafficPercent\", \"value\": $pct}]"

  echo "${OBSERVE_MINUTES}分間メトリクスを観察中..."
  sleep $((OBSERVE_MINUTES * 60))

  # Prometheus から canary のエラー率を取得
  ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query" \
    --data-urlencode "query=rate(revision_request_count{revision_name=~\".*canary.*\",response_code!=\"200\"}[5m]) / rate(revision_request_count{revision_name=~\".*canary.*\"}[5m])" \
    | jq -r '.data.result[0].value[1] // "0"')

  if (( $(echo "$ERROR_RATE > $MAX_ERROR_RATE" | bc -l) )); then
    echo "エラー率 ${ERROR_RATE} が閾値 ${MAX_ERROR_RATE} を超過。ロールバックを実行。"
    kubectl patch inferenceservice "$ISVC_NAME" -n "$NAMESPACE" \
      --type='json' \
      -p='[{"op": "replace", "path": "/spec/predictor/canaryTrafficPercent", "value": 0}]'
    exit 1
  fi

  echo "エラー率 ${ERROR_RATE} - 正常範囲。次の段階へ進む。"
done

echo "=== Canary プロモーション完了。v2 が 100% のトラフィックを処理します。 ==="

このスクリプトは 10% から 100% まで 5 段階でトラフィックを切り替え、各段階で 10 分間エラー率をモニタリングする。エラー率が 5% を超えると自動的に 0% へロールバックする。

Custom Transformer の実装

前処理/後処理パイプラインの設計

実際のプロダクションでは、クライアントが送る生データ(画像 URL、テキスト、JSON)をモデルが期待するテンソル形式へ変換しなければならない。Transformer を Predictor から切り離すと、次のような利点がある。

kserve.Model の継承とハンドラの実装

KServe Python SDK の kserve.Model クラスを継承して Custom Transformer を実装する。

import kserve
from kserve import InferRequest, InferResponse, InferInput
from typing import Dict, List
import numpy as np
from PIL import Image
import requests
from io import BytesIO
import logging

logger = logging.getLogger(__name__)

class ImageTransformer(kserve.Model):
    """画像 URL を受け取り、前処理して Predictor へ渡す Transformer"""

    def __init__(self, name: str, predictor_host: str):
        super().__init__(name)
        self.predictor_host = predictor_host
        self.target_size = (224, 224)
        self.mean = np.array([0.485, 0.456, 0.406])
        self.std = np.array([0.229, 0.224, 0.225])
        self.ready = False

    def load(self):
        """モデルの初期化。Warm-up ロジックはここに置く。"""
        logger.info("ImageTransformer の初期化が完了しました")
        self.ready = True

    def preprocess(
        self, payload: Dict, headers: Dict = None
    ) -> InferRequest:
        """画像 URL を受け取り、正規化されたテンソルへ変換する"""
        instances = payload.get("instances", [])
        processed_images = []

        for instance in instances:
            image_url = instance.get("image_url")
            response = requests.get(image_url, timeout=10)
            response.raise_for_status()

            image = Image.open(BytesIO(response.content)).convert("RGB")
            image = image.resize(self.target_size)

            # numpy 配列へ変換してから正規化
            img_array = np.array(image, dtype=np.float32) / 255.0
            img_array = (img_array - self.mean) / self.std
            img_array = np.transpose(img_array, (2, 0, 1))  # CHW
            processed_images.append(img_array)

        input_tensor = np.stack(processed_images)

        infer_input = InferInput(
            name="input",
            shape=list(input_tensor.shape),
            datatype="FP32",
            data=input_tensor.tolist(),
        )
        return InferRequest(
            model_name=self.name,
            infer_inputs=[infer_input],
        )

    def postprocess(
        self, response: InferResponse, headers: Dict = None
    ) -> Dict:
        """モデルの出力を人が読みやすい形式へ変換する"""
        predictions = response.outputs[0].data

        class_names = ["cat", "dog", "bird", "fish", "other"]
        results = []

        for pred in predictions:
            if isinstance(pred, list):
                probs = np.array(pred)
            else:
                probs = np.array([pred])

            top_idx = int(np.argmax(probs))
            results.append({
                "class": class_names[top_idx],
                "confidence": float(probs[top_idx]),
                "all_scores": {
                    name: float(score)
                    for name, score in zip(class_names, probs)
                },
            })

        return {"predictions": results}


if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--predictor_host", required=True)
    parser.add_argument("--model_name", default="image-classifier")
    args = parser.parse_args()

    transformer = ImageTransformer(
        name=args.model_name,
        predictor_host=args.predictor_host,
    )
    transformer.load()
    kserve.ModelServer(workers=4).start([transformer])

Transformer を含む InferenceService の YAML

Transformer を InferenceService に統合すると、KServe が Transformer と Predictor の間の内部ルーティングを自動で設定する。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: image-classifier
  namespace: ml-serving
spec:
  transformer:
    minReplicas: 2
    maxReplicas: 15
    scaleTarget: 10
    scaleMetric: concurrency
    containers:
      - name: image-transformer
        image: registry.example.com/ml/image-transformer:v1.2.0
        args:
          - '--model_name=image-classifier'
        resources:
          requests:
            cpu: '1'
            memory: '2Gi'
          limits:
            cpu: '2'
            memory: '4Gi'
        env:
          - name: STORAGE_URI
            value: ''
  predictor:
    minReplicas: 1
    maxReplicas: 8
    model:
      modelFormat:
        name: pytorch
      storageUri: 's3://ml-models/image-classifier/resnet50-v2'
      resources:
        requests:
          cpu: '2'
          memory: '4Gi'
          nvidia.com/gpu: '1'
        limits:
          cpu: '4'
          memory: '8Gi'
          nvidia.com/gpu: '1'

この構成では、Transformer は CPU ノードで最大 15 個までスケールアウトし、Predictor は GPU ノードで最大 8 個までスケールアウトする。前処理がボトルネックの場合は Transformer だけを増やせばよいので、コスト効率が良い。

InferenceGraph: DAG ベースの複合推論

4 種類のノード型

InferenceGraph は、複数の InferenceService を DAG として繋ぎ、複合推論パイプラインを構成する KServe の高度な機能である。v0.11 から GA へ昇格し、4 種類のノード型に対応する。

ノード型実行方式入力の受け渡し主な Use Case説明
Sequence逐次実行前ノードの出力を次の入力へ前処理チェーンA の結果を B の入力へ渡す
Switch条件分岐条件に応じて一つのノードを選択A/B テスト、ルーティング条件に基づく単一経路の選択
Ensemble並列実行 + 結合同じ入力をすべてのノードへ渡すアンサンブル推論複数モデルの結果を合算/投票
Splitter重み付き分配比率に応じて一つのノードを選択トラフィック分割、Canary重みに基づくトラフィックのルーティング

A/B テストとアンサンブルのパターン

実際のプロダクションでよく使われるパターンは、アンサンブルと A/B テストの組み合わせである。たとえば不正検知システムで、ルールベースのモデル、XGBoost モデル、ディープラーニングモデルを同時に実行して結果をアンサンブルすれば、単一モデルより精度を高められる。

apiVersion: serving.kserve.io/v1alpha1
kind: InferenceGraph
metadata:
  name: fraud-detection-ensemble
  namespace: ml-serving
  annotations:
    serving.kserve.io/propagateHeaders: 'x-request-id,x-trace-id'
spec:
  nodes:
    root:
      routerType: Sequence
      steps:
        - name: feature-enrichment
          serviceName: feature-enricher
          weight: 100
        - name: ensemble-node
          nodeName: model-ensemble
    model-ensemble:
      routerType: Ensemble
      steps:
        - name: xgboost-model
          serviceName: fraud-xgboost
          weight: 40
        - name: deep-model
          serviceName: fraud-deep-learning
          weight: 40
        - name: rule-engine
          serviceName: fraud-rule-engine
          weight: 20
    result-combiner:
      routerType: Sequence
      steps:
        - name: weighted-average
          serviceName: ensemble-combiner
          weight: 100

この InferenceGraph は次のように動作する。

  1. root ノード (Sequence): まず feature-enricher が生データを豊かなフィーチャーへ変換し、その結果を model-ensemble ノードへ渡す。
  2. model-ensemble ノード (Ensemble): XGBoost、ディープラーニング、ルールエンジンという三つのモデルが同じ入力で並列に実行される。各モデルの weight は最終結果を合算する際の重みとして使われる。
  3. 最終結果は三つのモデルの加重平均として算出される。

A/B テストのための Splitter パターン

apiVersion: serving.kserve.io/v1alpha1
kind: InferenceGraph
metadata:
  name: recommendation-ab-test
  namespace: ml-serving
spec:
  nodes:
    root:
      routerType: Splitter
      steps:
        - name: model-v1-stable
          serviceName: recommender-v1
          weight: 80
        - name: model-v2-experiment
          serviceName: recommender-v2
          weight: 20

Splitter はトラフィックの 80% を安定版へ、20% を実験版へ分配する。InferenceService の Canary と違い、InferenceGraph の Splitter は完全に独立した InferenceService 間のトラフィック分割なので、異なるモデルアーキテクチャ同士の A/B テストに向いている。

オートスケーリング戦略

Knative Pod Autoscaler (KPA) vs HPA vs KEDA

KServe は三つのオートスケーラをサポートする。ワークロードの特性によって適したスケーラが異なる。

特性KPA (Knative)HPA (Kubernetes)KEDA
Scale-to-ZeroOXO
スケーリング指標concurrency, rpscpu, memory, custom外部メトリクス (Prometheus, CloudWatch など)
反応速度速い (1-2 秒)普通 (15-30 秒)普通 (15 秒)
GPU ワークロード限定的適する非常に適する
カスタム指標限定的Metrics API が必要豊富な Scaler に対応
Cold Start 対応activationScaleN/AminReplicaCount
設定の複雑さ低い中程度高い

GPU ワークロードでの Scale-to-Zero

GPU インスタンスはコストが高いため Scale-to-Zero が重要になる。ただし GPU モデルは cold start 時間が長く(数十秒から数分)、注意が必要だ。KPA を使う場合は scaledown の遅延を適切に設定しなければならない。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: gpu-model
  namespace: ml-serving
  annotations:
    # Scale-to-Zero の有効化 (既定値)
    serving.kserve.io/enable-scale-to-zero: 'true'
    # 最後のリクエストから Scale-to-Zero までの待機時間
    autoscaling.knative.dev/scale-to-zero-pod-retention-period: '15m'
    # スケールダウンの遅延 (急激な縮小の防止)
    autoscaling.knative.dev/scale-down-delay: '5m'
    # 同時処理可能なリクエスト数 (GPU モデルは低く設定)
    autoscaling.knative.dev/target: '2'
    autoscaling.knative.dev/metric: 'concurrency'
spec:
  predictor:
    minReplicas: 0
    maxReplicas: 4
    model:
      modelFormat:
        name: pytorch
      storageUri: 's3://ml-models/large-model/v1'
      resources:
        requests:
          nvidia.com/gpu: '1'
        limits:
          nvidia.com/gpu: '1'

KEDA + vLLM メトリクスによるオートスケーリング

LLM サービングでは、CPU/メモリではなく vLLM 自体のメトリクス(待機中のリクエスト数、KV キャッシュ使用率)に基づいてスケーリングするのが効果的である。KEDA の Prometheus Scaler を活用すればこれを実装できる。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: llama3-vllm-scaler
  namespace: ml-serving
spec:
  scaleTargetRef:
    apiVersion: serving.kserve.io/v1beta1
    kind: InferenceService
    name: llama3-vllm
  minReplicaCount: 1
  maxReplicaCount: 8
  pollingInterval: 15
  cooldownPeriod: 300
  advanced:
    restoreToOriginalReplicaCount: true
    horizontalPodAutoscalerConfig:
      behavior:
        scaleUp:
          stabilizationWindowSeconds: 30
          policies:
            - type: Pods
              value: 2
              periodSeconds: 60
        scaleDown:
          stabilizationWindowSeconds: 300
          policies:
            - type: Pods
              value: 1
              periodSeconds: 120
  triggers:
    # vLLM の待機リクエスト数に基づくスケーリング
    - type: prometheus
      metadata:
        serverAddress: http://prometheus.monitoring:9090
        metricName: vllm_waiting_requests
        query: |
          avg(vllm:num_requests_waiting{model_name="llama3-vllm"})
        threshold: '5'
    # KV Cache 使用率に基づくスケーリング
    - type: prometheus
      metadata:
        serverAddress: http://prometheus.monitoring:9090
        metricName: vllm_kv_cache_usage
        query: |
          avg(vllm:gpu_cache_usage_perc{model_name="llama3-vllm"})
        threshold: '0.85'

この設定は、二つの条件のいずれかを満たせばスケールアウトをトリガーする。

スケールダウン時には 5 分の安定化ウィンドウと、2 分あたり 1 個ずつ減らすポリシーを適用して、急激な縮小を防ぐ。

v0.15 の新機能

Envoy AI Gateway との連携

KServe v0.15(2025 年 6 月)で最も注目すべき機能は Envoy AI Gateway との連携である。LLM サービングに特化したルーティングと可観測性を提供する。

LocalModelCache のマルチノードグループ

大規模な LLM の重みを毎回 S3 からダウンロードすると cold start に数分かかる。v0.15 の LocalModelCache は、ノードのローカルディスクへモデルを事前にキャッシュして startup 時間を劇的に短縮する。

apiVersion: serving.kserve.io/v1alpha1
kind: LocalModelCache
metadata:
  name: llama3-cache
  namespace: ml-serving
spec:
  sourceModelUri: 's3://ml-models/Meta-Llama-3.1-8B-Instruct'
  nodeGroups:
    - name: a100-nodes
      nodeSelector:
        gpu-type: 'a100'
      persistentVolumeClaimSpec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 50Gi
        storageClassName: local-nvme

この設定は gpu-type: a100 ラベルを持つすべてのノードに 50Gi の NVMe ボリュームを作成し、S3 からモデルの重みを事前にダウンロードしておく。Pod の起動時に S3 ではなくローカルディスクから重みをロードするため、cold start 時間が数分から数秒へ短縮される。

LLM サービングの最適化

v0.15 では LLM ワークロードに対する最適化が数多く盛り込まれた。

失敗事例とトラブルシューティング

事例 1: Transformer の OOM で推論パイプラインが停止

症状: 画像分類パイプラインで Transformer Pod が断続的に OOMKilled となり、推論チェーン全体が失敗した。

原因分析: Transformer が大容量画像(8K 解像度)をメモリへロードする際、PIL は展開後の原寸大のメモリを確保する。同時リクエストが 10 個入ると 10 x 200MB = 2GB が瞬間的に必要になったが、メモリ limit は 1Gi に設定されていた。

解決方法:

# 画像サイズの制限を前処理の初期段階で適用する
from PIL import Image

# PIL の DecompressionBomb 対策の設定
Image.MAX_IMAGE_PIXELS = 89_478_485  # 約 9500x9500

def safe_load_image(image_bytes: bytes, max_size: int = 2048):
    """メモリ安全な画像ロード"""
    img = Image.open(BytesIO(image_bytes))

    # 元のサイズが max_size を超えたら直ちにリサイズ
    if max(img.size) > max_size:
        ratio = max_size / max(img.size)
        new_size = (int(img.width * ratio), int(img.height * ratio))
        img = img.resize(new_size, Image.LANCZOS)

    return img.convert("RGB")

さらに Transformer のメモリ limit を 4Gi へ引き上げ、concurrency target を 5 へ下げて同時処理量を制限した。

事例 2: Scale-to-Zero での Cold Start 遅延

症状: GPU モデルが Scale-to-Zero の状態から最初のリクエストを受けたとき、60 秒以上のタイムアウトが発生した。

原因分析: モデルの重み(2GB)を S3 からダウンロードして GPU メモリへロードする時間が、Knative の既定のタイムアウト(30 秒)を超えていた。

解決方法:

  1. progressDeadline を 600 秒へ拡張する
  2. LocalModelCache を適用してノードローカルにモデルを事前キャッシュする
  3. minReplicas: 1 に設定して最低 1 個の Pod を維持する (コストが許容できる場合)

デバッグのチェックリスト

KServe の配備問題をデバッグする際に、体系的に確認すべき項目である。

  1. InferenceService の状態確認: kubectl get isvc -n ml-serving で READY が True かを確認する
  2. Pod の状態確認: kubectl get pods -n ml-serving -l serving.kserve.io/inferenceservice=MODEL_NAME で Pod の状態を点検する
  3. イベントの確認: kubectl describe isvc MODEL_NAME -n ml-serving の Events セクションを確認する
  4. Knative Revision の確認: kubectl get revisions -n ml-serving で revision の状態を点検する
  5. ストレージアクセスの確認: StorageInitializer のログに S3/GCS のアクセスエラーがないか確認する
  6. Istio ルーティングの確認: kubectl get virtualservice -n ml-serving でトラフィックのルーティングルールを点検する
  7. リソース不足の確認: kubectl describe node で GPU の割り当て可能量とメモリの余裕を確認する

運用上の注意事項

GPU ノードのスケジューリングと tolerations

GPU ノードには一般に taint が設定されているため、InferenceService には必ず tolerations と nodeSelector を明示しなければならない。これを漏らすと Pod は Pending 状態のまま止まる。

spec:
  predictor:
    tolerations:
      - key: 'nvidia.com/gpu'
        operator: 'Exists'
        effect: 'NoSchedule'
    nodeSelector:
      gpu-type: 'a100'
    model:
      modelFormat:
        name: vLLM
      # ... モデルの設定

モデルのキャッシュ戦略

大規模なモデルを運用する際は、階層的なキャッシュ戦略が不可欠である。

リソース Quota の管理

名前空間ごとに ResourceQuota を設定して、チーム間の GPU リソース競合を防ぐ。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: ml-serving-quota
  namespace: ml-serving
spec:
  hard:
    requests.cpu: '64'
    requests.memory: '256Gi'
    requests.nvidia.com/gpu: '8'
    limits.cpu: '128'
    limits.memory: '512Gi'
    limits.nvidia.com/gpu: '8'
    persistentvolumeclaims: '20'

この Quota は、ml-serving 名前空間で最大 GPU 8 枚、CPU 128 コア、メモリ 512Gi まで使えるように制限する。チームごとに名前空間を分け、それぞれ適切な Quota を割り当てれば、安定したマルチテナント運用ができる。

参考資料

コメント

まだコメントはありません。

ログインするとコメントできます