技術入門

AWS EKS Auto Mode でLLMモデルのScale-to-Zeroを実現する

NIC ネットワーク制御ソフトウェアプロジェクト

森 優大(もり ゆうだい)

#AI/LLM#AWS#Kubernetes

2026/4/30

背景

機密性の高い研究開発では、セキュリティの観点から外部のLLMサービスではなく、自社で管理するインフラ環境内でLLMを利用するユースケースがあります。 私たちのチームでも、AWS EKS(Elastic Kubernetes Service) Auto Mode[1] 上にLLMを配置して日々の業務に活用しています。
このような環境を構築する際に課題となるのがインフラコストの最適化です。 LLMの稼働には高価なGPUノードが必要なため、夜間や休日といった開発時間外も常時稼働させてしまうと、無駄な費用が発生します。
そのため、インフラ費用を抑えるには、誰も利用しない時間帯のGPUノード数を「0」にスケールする仕組みが欠かせません。
本記事では、EKS環境において非稼働時のノードを0に落とし、コスト最適化を実現した具体的なアプローチについて紹介します。

本記事で学べること

本記事では、GPUノードのゼロスケールを実現するための具体的なアプローチとして、以下の内容について解説します。

  • Scale-to-Zeroの技術的な背景とEKS上での実装方法
    ノード数を0にする「Scale-to-Zero」の仕組みについて、理論的な基礎を整理し、実際のシステムへ組み込む手順を紹介します。
  • KnativeとKEDAの比較および選定理由
    Scale-to-Zeroが実現可能なKubernetesのオートスケーリングツール、KnativeとKEDAを比較します。 それぞれの特徴を踏まえ、今回の要件でKnativeを採用した経緯を説明します。
  • コールドスタート問題への対応策
    ノードを0から起動させる際に避けられない起動遅延(コールドスタート)について、実施した対策を紹介します。
  • Scale-to-Zeroの基礎

    Scale-to-Zeroとは

    リクエストやイベントが発生していないアイドル状態のときに、コンテナやインスタンスの数を0まで縮小することをScale-to-Zeroと呼びます。 これにより、待機時のインフラ維持コストを削減できるというメリットがあります。 一方で、リクエストが来てから環境を0から立ち上げるため、起動時の遅延(コールドスタート)への対処が課題となります。

    KubernetesにおけるScale-to-Zero

    Kubernetes環境でインフラコストを最小化するためには、「Pod(アプリケーション)」と「ノード(インフラ)」という2つの異なるレイヤーでスケーリングを考える必要があります。

    01.jpg
    図1

    ・Podのスケーリング
    Kubernetesはアプリケーションの負荷に合わせてPod数を変更するしくみを備えています。 Kubernetes標準のオートスケール機能であるHPA(Horizontal Pod Autoscaler)[2] は、稼働中のPodから取得するCPUやメモリの使用率に基づいてPod数を調整することができます。

    ・HPAの制約
    HPAはKubernetes標準機能のため、簡単に利用できますが、Podを0にスケールダウン^1できないという制約があります。 仮にPod数を0にしてしまうと、指標となるメトリクスを計測できなくなり、次にいつPodを起動すべきか(スケールアップのタイミング)を判断できなくなります。 そのため、HPA単体ではPodの最小数を1以上に保つ必要があり、0へのスケールダウンには対応できません。 この制約を解決するため、リクエスト数やイベントをトリガーにできるKnative[3] やKEDA(Kubernetes Event-Driven Autoscaling)[4] といった拡張フレームワークが利用されています。

    ・ノードのスケーリング
    アプリケーション側でPod数を0にできても、基盤となるGPUノードが稼働したままではコスト削減につながりません。 Podのスケールダウンとノードのスケールも連動させる必要があります。
    ノードの動的な管理には、Amazon EKS Auto ModeにビルトインされているKarpenterを利用します。 Karpenterは、Kubernetes向けのノード自動管理ツールで、必要に応じてノードを追加・削除する役割を担います。 リソース不足でPending(待機)状態となったPodを検知すると、要求されるGPU要件を満たすノードを自動で起動します。 反対に、Podが0になり不要となったノードは自動的に削除されます。

    KnativeとKEDAの定性的評価

    Kubernetes環境でScale-to-Zeroを実現する代表的なツールとして、KnativeとKEDAが挙げられます。 どちらもPodを0個まで自動スケールさせるという目的は共通していますが、前提としているワークロードの性質と、それを実現するためのアーキテクチャが異なります。

    前提知識: 同期型ワークロードと非同期型ワークロードの違い

    システム処理は、大きく「同期型」と「非同期型」に分けられます。

  • 同期型ワークロード
    WebアプリケーションやAPIサーバのように、ユーザからのHTTPリクエストを主とするモデルです。送信元と受信先の通信コネクションを保持したまま処理タイミングを同期させ、処理結果をその場で直接返却します。そのためリアルタイムでの応答が可能です。一方で、結果が返却されるまで送信元の時間を拘束し続けるため、バックエンドの処理遅延や通信のタイムアウトが課題となり得ます。
  • 非同期型(イベント駆動型)ワークロード
    大規模なデータ処理パイプラインや動画のエンコーディング処理のように、即時完了を前提としないバックグラウンド処理を主とするモデルです。KafkaやIBM MQなどのメッセージキューを送信元と受信先の間に挟むことで、処理タイミングを非同期に切り離すことができます。送信元はタスクを登録した時点で自身の処理に戻ることができ、受信先は自身のタイミングで処理を実行できます。即時の返信が期待できないため、リアルタイム処理には向きません。
  • Knativeのアプローチ

    Knativeは、同期型ワークロードを想定した設計となっており、標準のコンポーネントのみでHTTPリクエストをトリガーとしたScale-to-Zeroを実装できます。 Pod数が0の状態でリクエストが到達すると、「Activator」と呼ばれるコンポーネントが通信を一時的に受け止め、バッファリングを行います。 バックエンドのPodが起動し、リクエストを処理できる状態になるまで接続を維持するため、通信の取りこぼしに強いアーキテクチャとなっています。

    KEDAのアプローチ

    KEDA(Kubernetes Event-Driven Autoscaling)は、非同期型(イベント駆動型)ワークロード向けのオートスケーラとして設計されています。 Knativeがトラフィックの通り道に介入するのに対し、KEDAはKafkaやデータベースといった外部リソースの「キューの滞留数」を定期的に監視(ポーリング)し、そのメトリクスをKubernetes標準のHPA(Horizontal Pod Autoscaler)に渡すことでスケーリングを実現します。


    ・KEDA + HTTP Add-on
    KEDAは非同期型(イベント駆動型)ワークロード向けであるため、HTTPリクエストを直接のトリガーとして扱えません。 これを同期型のWebアプリケーションに適用するには、拡張コンポーネントである「KEDA HTTP Add-on」[5] を導入する必要があります。 この構成では、前段のInterceptorがHTTPリクエストを受け止め、内部的なメトリクスに変換してスケーリングを行う仕組みとなります。
    なお、KnativeとKEDAは監視対象や役割が棲み分けられているため、同一のKubernetesクラスタ内に競合することなく共存させることも可能です。

    02.jpg

    対象とするアプリケーションの要件と選定理由

    今回構築するシステムは、AWS EKS上に「Open WebUI[6] + Ollama[7] + オンプレLLM」を配置する構成です。 ユーザがブラウザから対話的に操作するため、HTTPリクエストを起点とした同期的なWebアプリケーションに該当します。
    本システムの特徴は、ゼロスケールからの復帰(コールドスタート)時に、GPUノードの起動や数十GBに及ぶLLMモデルのメモリへのロードが発生する点です。 これにより、リクエストを受け付けてから処理を開始するまでに数分単位の待機時間が生じます。 したがって、この数分間にわたってHTTPのコネクションを保持し続けるバッファリング機能が必要となります。
    このような要件から、本環境では以下の理由を踏まえてKnativeを採用することにしました。

    1.アーキテクチャの適合性
    前述の通り、Knativeはアーキテクチャの根幹からHTTPトラフィックのハンドリングと保持を前提に設計されています。長時間のコールドスタートを伴う同期リクエストを、Activatorによって安全に保持できる点は本要件に合致しています。

    2.OllamaのKnativeサポートによる導入コストの低減
    Knativeの導入にあたって、独自のカスタムリソース(Knative Service)を管理する必要があるため、学習・運用コストが増大します。しかし、OllamaのエコシステムではKnative Serviceを用いたデプロイがサポートされているため、このコストを意識することなく構築が可能でした。

    3.KEDA HTTP Add-onの運用コストと開発ステータス
    KEDA HTTP Add-onを用いて同等の要件を満たすことも技術的には可能ですが、KEDA本体とは別にInterceptorやOperatorなどのコンポーネントを管理するための学習・運用コストが発生します。さらに、KEDA HTTP Add-onは現在Beta版のステータスであり、本番環境のインフラ基盤として採用するには将来的な仕様変更などの懸念が残ります。

    以上の特性と運用上のトレードオフを踏まえ、同期型のWebアプリケーション運用に自然に適合し、OllamaでもサポートされているKnativeを採用する構成としました。

    Knative + AWS Auto Modeによる実装

    KnativeとAWS EKS Auto Modeを組み合わせたアーキテクチャを構築しました。
    仕組みとしては、まずKnativeがHTTPリクエストの有無に応じてPodの数を制御します。 一定時間リクエストがない場合、KnativeはPod数を0にスケールダウンします。 PodがなくなるとGPUの割り当て要求も消滅するため、EKS Auto Mode(Karpenter[8] ベース)が不要になったGPUノードを検知し、自動で削除します。 これによりインフラのコストの発生が抑えられます。
    逆に、新たなリクエストが届いた際は、KnativeのActivatorが通信をバッファリングしながらPodの起動を要求します。 この要求によりPending状態となったPodをEKS Auto Modeが検知し、GPU要件を満たすノードをJust-In-Time(JIT)でプロビジョニングします。 ノードの準備が整い次第、Podが配置されて推論処理が再開されます。

    コールドスタート問題とクラウドインフラの不確実性への対策

    KnativeとAWS Auto Mode(Karpenter)の組み合わせによってインフラコストの最適化は実現できましたが、コールドスタートによる応答の遅延が課題となります。 ノード数が0の状態からAWS上でGPUノードをプロビジョニングし、数十GBのLLMモデルをロードして応答を返すまでには、数分単位の時間を要します。 KnativeのActivatorが通信の切断(タイムアウト)を防いでくれますが、応答までに数分間の待機時間が発生するという根本的な課題が残ります。
    ノード・Podが0の状態から、ユーザが最初の応答を受け取るまでの測定を実施しました。 測定は、モデルの大きさと、AWSインスタンスタイプによる影響を見るために、以下の組み合わせで実施しました。
    モデル GPUインスタンス
    llama3.2:3b g6.2xlarge
    llama3.2:3b g6.8xlarge
    gpt-oss:120b g6.12xlarge
    この結果を図2に示します。

    03.jpg
    図2

    この結果から、以下の2つのことがわかります。

  • モデルのロード時間
    当然ですが、llama3.2:3b(約2GB)よりも、gpt-oss:120b(約65GB)のほうがモデルロード、初回の推論までに時間がかかります。大きなモデルを利用する場合、そのロード時間がボトルネックとなります。
  • GPUインスタンスのプロビジョニング時間 ^2
    AWSではGPUインスタンスの種類によってもプロビジョニング時間が大きく変動することがわかりました。 g6.2xlarge, g6.8xlargeではプロビジョニングにかなり時間を要していますが、g6.12xlargeではプロビジョニング時間が短くなっています。 これは、AWSリージョン内のキャパシティ(在庫状況)などの要因に影響を受けていると推測されます。
  • AWSのようなクラウドプロバイダを活用する場合、コールドスタートの遅延は「モデルのロード時間」という予測可能な要素だけでなく、特定インスタンスの確保にかかる時間といったコントロールが困難な外部要因にも依存します。このような不確実性を伴う長時間の遅延は、対話型のWebアプリケーションにおいてユーザ体験(UX)を損なう要因となります。

    ・ハイブリッド構成によるUX改善と不確実性の吸収
    この課題に対処するため、LLMプロキシ(LiteLLM[9] )のルーティング機能を活用し、オンプレミス環境のGPUリソースをフォールバックとして利用するハイブリッド構成を採用しました。
    この結果も図2に示しています。
    このフォールバック機構により、初回の要求に対してはオンプレミス環境のロード済みモデルで即座に応答できます。 また、ユーザに即座に応答を返している裏側で、AWS側でのノードプロビジョニングとアプリケーションの初期化処理を並行して進められます。 常時稼働のオンプレミス環境と、需要に応じてスケールするAWS上のKnative環境を組み合わせることで、クラウドインフラの不確実性を吸収しつつ、コスト効率とUXを両立するアーキテクチャを実現しています。

    04.jpg
    図3

    最終的なシステム構成は図3のようになりました。

    まとめ

    本記事では、AWS EKS環境におけるLLM推論基盤のコスト最適化を目的として、GPUノードのScale-to-Zeroを実現するアーキテクチャを紹介しました。 本記事の内容が、LLM環境を効率的に運用する際の一助となれば幸いです。

    付録:KnativeとKEDAの技術的な仕組み

    それぞれのツールがどのようにKubernetesと連携し、Scale-to-Zeroを実現しているのか、技術的なアーキテクチャを整理します。

    Knativeのアーキテクチャ

    Knative(より正確にはKnative Serving)は、HTTPリクエスト駆動に特化した独自のオートスケーラであるKPA(Knative Pod Autoscaler)を提供します。 KubernetesのDeploymentやServiceを直接記述するのではなく、Knative専用のリソースを定義して運用します。

  • リソースの抽象化: apiVersion: serving.knative.dev/v1 のServiceリソースを1つ定義するだけで、KnativeのコントローラがKubernetesのDeployment、Service、Ingress(Route)などを裏側で自動的に作成・管理します。
  • リクエスト駆動のスケーリング: HPAには依存せず、KPAがHTTPリクエストの同時実行数(Concurrency)などを監視してスケーリングを決定します。0へのスケールダウン状態(Pod数0)からリクエストを受信した際、トラフィック経路上に配置された「Activator」コンポーネントがリクエストを一時的にバッファリングし、Podの起動完了後にルーティングを行うことで通信の取りこぼしを防ぎます
  • 05.jpg
    図4

    KEDAのアーキテクチャ

    KEDAは、Kubernetes標準のオートスケーラであるHPA(Horizontal Pod Autoscaler)と協調して動作する拡張コンポーネントです。カスタムリソースである ScaledObject を用いてスケーリングの条件を定義します。

  • メトリクスの取得: KEDAのメトリクスが、外部のメッセージキュー(KafkaやAmazon SQSなど)やデータベースからイベント数やキューの滞留数をPullベースで監視・取得します。
  • HPAとの役割分担: KEDAはスケジューリングのフェーズによって実行主体がかわります。
  • ▪ 0から1へのスケーリング: HPAはPod数を0にできないため、最初の1台を起動する(0 → 1)処理は、KEDA Operatorが直接Deploymentを操作して実行します。

    ▪ 1からNへのスケーリング: Podが1台以上起動した後は、KEDAが取得した外部メトリクスをHPAに提供し、以降のスケールアップ・スケールダウン(1 ↔ N)はHPAが担当します。

    06.jpg
    図5

    ・KEDA HTTP Add-on
    KEDA単体は外部のイベントソースを監視する仕組みであるため、HTTPトラフィックを直接監視してスケーリングのトリガーとすることはできません。これを解決するために提供されているのがKEDA HTTP Add-onです。

  • トラフィックの捕捉とメトリクス変換: 通信経路上に「Interceptor」と呼ばれるコンポーネントをプロキシとして配置します。Interceptorは到達したHTTPリクエストを受け止め、「現在処理待ちとなっているリクエスト数」を内部的なキューサイズとしてKEDAに報告します。KEDA本体はこれを「疑似的なイベント」として解釈し、上記のスケーリング処理(0→1、1→N)を実行します。
  • リソース定義: 運用時は、KEDA標準の ScaledObject ではなく、HTTPScaledObject という専用のカスタムリソースを定義します。これにより、対象のアプリケーションに対するInterceptorのルーティングとスケーリング設定が自動的に構成されます。Podが0台の際のリクエストは、Interceptor内で設定されたタイムアウト時間まで保持されます。
  • 07.jpg
    図6
        

    参考文献

        

    [1] "Managed kubernetes - amazon elastic kubernetes service (EKS) auto mode - AWS." https://aws.amazon.com/eks/auto-mode/.

    [2] "Horizontal pod autoscaling." https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/.

    [3] "Home - knative." https://knative.dev/.

    [4] "KEDA." https://keda.sh/.

    [5] "KEDA HTTP add-on." https://kedacore.github.io/http-add-on/.

    [6] "Open WebUI: Self-hosted AI platform." https://openwebui.com/.

    [7] "Ollama." https://ollama.com/.

    [8] "Karpenter." https://karpenter.sh/.

    [9] "LiteLLM." https://www.litellm.ai/.

        
        

    注釈

        
           

    ^1 一般的なインフラストラクチャの文脈では、サーバ台数の増減(水平スケール)を「スケールアウト / イン」と呼びますが、KubernetesコミュニティではPodの水平スケールについても「スケールアップ / ダウン」と表現します [2] 。本ブログでは、Kubernetesの慣習にならい「スケールアップ / ダウン」と表現しています。

           

    ^2 本検証では、Amazon EC2 スポットインスタンスを利用しています。

        

    関連するプロジェクト

    プロジェクト一覧へ

    採用情報

    採用情報