【2026年版】LLMOps on Kubernetes — AIモデルのCI/CDパイプラインとGPUリソース管理の設計パターン

AI × Infrastructure

この記事の概要

  • LLMOpsはMLOpsの進化形で、Kubernetes上でAIモデルのCI/CDを自動化する設計が2025〜26年に急速に確立されつつある
  • Ray Serve + Argo Workflows + MLflowの組み合わせが現場での定番スタックになってきた
  • GPU OperatorとKarpenterを組み合わせることで、GPUノードの自動プロビジョニングが現実的に使えるレベルに達している

背景・概要

「LLMをプロダクションに投入したら、そこからどうやって運用・改善サイクルを回すの?」という問いに答える枠組みが LLMOps です。
MLOpsをベースに、LLM特有の課題——巨大なモデルウェイト、GPU依存、プロンプトエンジニアリング、評価の難しさ——に対応するための設計パターンが含まれます。

従来のMLOpsはスキルト機械学習モデル(scikit-learnやXGBoostなど)が中心でしたが、LLMはモデルサイズが桁違いで、推論にGPUが必須、Fine-tuningのコストも巨大です。
そのため「とりあえずJupyter Notebookで動いたから本番に持っていく」という雑なやり方では、すぐに破綻します。

ここ1〜2年でKubernetes上のLLMOpsスタックが整備されてきました。
インフラSEとしてこの設計パターンを把握しておくのは、もはや必須スキルになりつつあります。

詳細解説

LLMOpsの主要フロー

LLMOpsのパイプラインは大きく5つのフェーズで構成されます。

flowchart LR
    A[Experiment\n実験・プロンプト設計] --> B[Training\nFine-tuning]
    B --> C[Evaluation\n評価・ベンチマーク]
    C --> D[Staging\nカナリアデプロイ]
    D --> E[Production\n本番稼働]
    E -->|フィードバック| A

    style A fill:#4A90D9,color:#fff
    style B fill:#7B68EE,color:#fff
    style C fill:#50C878,color:#fff
    style D fill:#FFB347,color:#fff
    style E fill:#FF6B6B,color:#fff

このフローのどこかが人手の作業になっていると、リリースサイクルが詰まります。
Argo WorkflowsでEvaluationまでを自動化し、ArgoCDでStagingとProductionへのデプロイをGitOpsで管理するのが現時点の最適解です。

主要ツールの使い分け

ここが一番迷うポイントなので、整理しておきます。

ツール 役割 向いているケース
Argo Workflows CI/CDパイプライン実行 データ前処理・評価・デプロイの自動化
Ray / Ray Serve 分散学習・推論サーバ 大規模Fine-tuning、高スループット推論
KubeFlow MLプラットフォーム全般 チームで統一したML基盤が必要なとき
MLflow 実験管理・モデルレジストリ 実験トラッキング、モデルバージョン管理
vLLM 高効率LLM推論エンジン 本番エンドポイント(PagedAttentionで高スループット)
ArgoCD GitOpsデプロイ Kubernetes上のモデルデプロイを自動化

意外と「全部入れなければいけない」わけではなく、小規模なら Argo Workflows + MLflow + vLLM の3つで十分なパターンも多いです。
KubeFlowは機能が豊富な分、導入コストも高いので、チームの習熟度を見て判断してください。

Argo Workflows による LLM評価パイプライン

実際のArgo WorkflowsのYAMLを見てみましょう。
モデルのFine-tuning後に評価を走らせ、閾値をクリアしたらMLflowのモデルレジストリに登録するパイプラインです。

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: llm-eval-pipeline
  namespace: mlops
spec:
  entrypoint: llm-pipeline
  arguments:
    parameters:
      - name: model-version
        value: "v1.2.0"
      - name: eval-threshold
        value: "0.85"

  templates:
    - name: llm-pipeline
      dag:
        tasks:
          - name: preprocess
            template: data-preprocess

          - name: fine-tune
            template: fine-tune-model
            dependencies: [preprocess]
            arguments:
              parameters:
                - name: model-version
                  value: "{{workflow.parameters.model-version}}"

          - name: evaluate
            template: run-evaluation
            dependencies: [fine-tune]
            arguments:
              parameters:
                - name: model-version
                  value: "{{workflow.parameters.model-version}}"
                - name: threshold
                  value: "{{workflow.parameters.eval-threshold}}"

          - name: register
            template: register-model
            dependencies: [evaluate]
            when: "{{tasks.evaluate.outputs.parameters.passed}} == true"

    - name: data-preprocess
      container:
        image: your-registry/llm-preprocess:latest
        command: [python, preprocess.py]
        resources:
          requests:
            memory: "8Gi"
            cpu: "4"

    - name: fine-tune-model
      inputs:
        parameters:
          - name: model-version
      container:
        image: your-registry/llm-trainer:latest
        command: [python, train.py, "--model-version", "{{inputs.parameters.model-version}}"]
        resources:
          requests:
            memory: "64Gi"
            nvidia.com/gpu: "4"
          limits:
            nvidia.com/gpu: "4"
        env:
          - name: MLFLOW_TRACKING_URI
            value: "http://mlflow-server.mlops.svc.cluster.local:5000"

    - name: run-evaluation
      inputs:
        parameters:
          - name: model-version
          - name: threshold
      outputs:
        parameters:
          - name: passed
            valueFrom:
              path: /tmp/eval_result.txt
      container:
        image: your-registry/llm-evaluator:latest
        command: [python, evaluate.py,
                  "--model-version", "{{inputs.parameters.model-version}}",
                  "--threshold", "{{inputs.parameters.threshold}}",
                  "--output", "/tmp/eval_result.txt"]
        resources:
          requests:
            nvidia.com/gpu: "1"
          limits:
            nvidia.com/gpu: "1"

    - name: register-model
      container:
        image: your-registry/llm-registry:latest
        command: [python, register.py]
        env:
          - name: MLFLOW_TRACKING_URI
            value: "http://mlflow-server.mlops.svc.cluster.local:5000"

ここ地味に大事なポイントが when 条件です。
評価スコアが閾値を超えた場合だけモデルレジストリへの登録が走ります。
これがないと「性能が下がったモデルが自動デプロイされる」という最悪の事態が起きます。

ArgoCD によるモデルデプロイ(GitOps)

Fine-tuningとレジストリ登録が完了したら、ArgoCDでKubernetesへのデプロイをGitOpsで管理します。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: llm-model-prod
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/llm-manifests
    targetRevision: main
    path: apps/llm-inference/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: llm-prod
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
  # Staging環境で検証済みの場合のみ自動同期
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas  # HPA管理下のレプリカ数は無視

モデルのバージョンをGitのタグやコミットハッシュと紐付けておくと、問題発生時のロールバックがGit revertで完結します。
これが本当に便利で、障害対応の心理的負担が大きく下がります。

GPU Operator + Karpenter によるGPUノード管理

GPUリソース管理はLLMOpsの中でも特にコストに直結する部分です。
NVIDIA GPU OperatorはKubernetesクラスタ上のGPUドライバとプラグインの管理を自動化してくれます。

# Karpenter NodePool for GPU workloads
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: gpu-nodepool
spec:
  template:
    metadata:
      labels:
        workload-type: gpu
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-family
          operator: In
          values: ["g5", "p3", "p4d"]   # GPU instanceファミリー
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]  # コスト最適化のためSpot優先
      nodeClassRef:
        apiVersion: karpenter.k8s.aws/v1beta1
        kind: EC2NodeClass
        name: gpu-node-class
  limits:
    nvidia.com/gpu: 64   # クラスタ全体のGPU上限
  disruption:
    consolidationPolicy: WhenEmpty
    consolidateAfter: 30s   # ジョブ完了後すぐに回収

ポイントはSpotインスタンスを優先しつつ、consolidateAfter を短めに設定してGPUノードが空になったらすぐ回収することです。
GPUのSpotインスタンスはオンデマンドの60〜70%引きになることもあり、学習ジョブのコストを大幅に削減できます。

ただし、Spotインスタンスは突然中断されるので、学習ジョブにはCheckpointingを必ず実装しておいてください。
Ray Trainを使うと、このCheckpointingが比較的簡単に設定できます。

実務での活用方法

まずは全部を一気に導入しようとしないことが大切です。
実務では段階的に進めることをおすすめします。

ステップ1(最初の1ヶ月): Argo Workflows + MLflowだけで評価パイプラインを構築。これだけでも「手動でモデル評価していた工数」を大幅削減できます。

ステップ2(2〜3ヶ月目): ArgoCDを導入してデプロイをGitOps化。ここでモデルバージョン管理の仕組みが整います。

ステップ3(安定後): GPU OperatorとKarpenterを導入してGPUノードの自動管理を実現。コスト最適化と運用効率化が同時に達成できます。

vLLMの本番投入に関しては、OpenAI互換APIを提供してくれるため、既存のアプリケーション側の変更を最小限にできます。
Ray Serveと組み合わせることで、モデルの自動スケーリングも実現できます。

まとめ

LLMOpsはまだ発展途上の領域ですが、Kubernetes上のスタックはかなり成熟してきました。

  • Argo Workflows でCI/CDパイプライン(評価・登録・デプロイ)を自動化
  • MLflow で実験管理とモデルレジストリを一元管理
  • ArgoCD でGitOpsによるモデルデプロイを実現
  • GPU Operator + Karpenter でGPUリソースを自動管理・コスト最適化
  • vLLM で本番推論エンドポイントを高効率に運用

全部を一度に導入する必要はなく、チームの習熟度とシステムの規模に応じて段階的に取り入れていくのが現実解です。
まずはArgo WorkflowsとMLflowから始めて、痛みを感じた部分から改善していくのが、インフラSEとして現場で使える現実的なアプローチだと思います。

参考リンク

コメント