KEDAを使ってGPUワークロードをゼロにスケールさせる

KEDA
ollama

2024-09-27

#はじめに

今回は、KEDAを使ってGPUワークロードをゼロにスケールさせる方法について紹介します。

GPUは、機械学習やディープラーニングなどのワークロードを高速に処理するために利用されます。しかし、GPUはコストが高いため、常に利用されているわけではありません。そのため、GPUワークロードをゼロにスケールさせることで、コストを削減することができます。KEDAを利用してこの課題に取り組みたいと思います。

#目次

#KEDAとは

KEDA is a Kubernetes-based Event Driven Autoscaler. With KEDA, you can drive the scaling of any container in Kubernetes based on the number of events needing to be processed.

KEDA is a single-purpose and lightweight component that can be added into any Kubernetes cluster. KEDA works alongside standard Kubernetes components like the Horizontal Pod Autoscaler and can extend functionality without overwriting or duplication. With KEDA you can explicitly map the apps you want to use event-driven scale, with other apps continuing to function. This makes KEDA a flexible and safe option to run alongside any number of any other Kubernetes applications or frameworks.

出典:https://keda.sh/

以下、翻訳。

KEDAはKubernetesベースのEvent Driven Autoscalerです。KEDAを使えば、処理が必要なイベントの数に基づいてKubernetesの任意のコンテナのスケーリングを駆動できます。

KEDAは、あらゆるKubernetesクラスタに追加できる単一目的の軽量コンポーネントです。KEDAはHorizontal Pod Autoscalerのような標準的なKubernetesコンポーネントと一緒に動作し、上書きや重複なしに機能を拡張することができます。KEDAを使えば、イベントドリブンスケールを使いたいアプリを明示的にマッピングし、他のアプリはそのまま機能させることができます。このためKEDAは、他のあらゆるKubernetesアプリケーションやフレームワークと並行して実行できる、柔軟で安全なオプションとなります。

KEDAは、イベント駆動のオートスケーラーとのことです。同じようなソリューションとしては、上記の通りHPAがありますが、HPAはCPU利用率やメモリ利用率などのリソース利用率に基づいてスケールアウトを行います。また、HPAでは、ゼロにスケールする方法はありません。一方、KEDAはイベントに基づいて、スケールすることができます。そして、ゼロにスケールすることもできます。サーバーレスのようなアーキテクチャで利用されるようなものですね。

似たようなソリューションとしては、Knativeがあります。
Knativeは、GoogleのCloud Runというサーバーレスのサービスで利用されている技術です。
Knativeでは、主にHTTPイベントを扱いますが、KEDAは、Scalerと呼ばれるリソースによって、様々なイベントやカスタムメトリクスに基づいたスケーリングができます。
次のリンクにKEDAが扱えるScalerの一覧があります。

https://keda.sh/docs/2.15/scalers/

#背景

最近いくつかのGPUワークロードを扱う機会がありました。その中で、自宅のマシンだとGPUが1台しかないので、一つのワークロードでGPUリソースを専有してしまうと、他のワークロードでは、GPUリソースを取得できずに待ち状態になってしまいます。そのため、GPUワークロードをより効率的に利用する方法を模索していました。

そこで、KEDAを使ってGPUワークロードをゼロにスケールさせる方法を検討しました。

#KEDA HTTP add-onとは

KEDAが扱えるScalerには、HTTPがありません。KEDA HTTP add-onを使うことで、HTTPリクエストに基づいたスケーリングができるようになります。
詳細は、こちらのThe Design of HTTP Add-onを参照してください。KEDA HTTP add-onは、Project statusがBetaなので、本番環境での利用には注意が必要です。

今回は、ollamaをserveしてHTTPリクエストに基づいたスケーリングを試してみたいと思います。

#実装

下記のドキュメントを参考に実装を進めます。

https://github.com/kedacore/http-add-on/blob/main/docs/install.md

https://github.com/kedacore/http-add-on/blob/main/docs/walkthrough.md

#KEDAのインストール

helmfileを使ってKEDAをインストールします。

repositories:
  - name: kedacore
    url: https://kedacore.github.io/charts
releases:
  - name: kedacore
    chart: kedacore/keda
    namespace: keda
    version: 2.15.1

#KEDA HTTP add-onのインストール

helmfileを使ってKEDA HTTP add-onをインストールします。

repositories:
  - name: kedacore
    url: https://kedacore.github.io/charts
releases:
  - name: http-add-on
    chart: kedacore/keda-add-ons-http
    namespace: keda
    version: 0.8.0

この時点でkeda namespaceに以下のPodが作成されていることを確認します。

 k get po -n keda
NAME                                                    READY   STATUS    RESTARTS   AGE
keda-add-ons-http-controller-manager-5cf6648b77-8n8pw   2/2     Running   0          2m47s
keda-add-ons-http-external-scaler-5bb5f74bfc-cpqhg      1/1     Running   0          2m47s
keda-add-ons-http-external-scaler-5bb5f74bfc-m8zqh      1/1     Running   0          2m47s
keda-add-ons-http-external-scaler-5bb5f74bfc-s894b      1/1     Running   0          2m47s
keda-add-ons-http-interceptor-7fdc6b7cb7-5zsxw          1/1     Running   0          2m47s
keda-add-ons-http-interceptor-7fdc6b7cb7-pb6tb          1/1     Running   0          2m30s
keda-add-ons-http-interceptor-7fdc6b7cb7-vj6fw          1/1     Running   0          2m30s
keda-admission-webhooks-86597c4884-lsx6v                1/1     Running   0          2m48s
keda-operator-7f84d94549-zcrh5                          1/1     Running   0          2m48s
keda-operator-metrics-apiserver-8458849cc8-g2tfl        1/1     Running   0          2m48s

#HTTPScaledObjectの作成

以前の記事で作成したollamaのHelmに追加のHTTPScaledObjectを作成します。
クラスタ内部からアクセスしたいので、ホストにはollama-proxy.ollama.svc.cluster.localを指定しています。

  • httpscaledobject.yaml
apiVersion: http.keda.sh/v1alpha1
kind: HTTPScaledObject
metadata:
  name: {{ include "ollama.fullname" . }}
  labels:
    {{- include "ollama.labels" . | nindent 4 }}
spec:
  hosts:
    - ollama-proxy.ollama.svc.cluster.local
  pathPrefixes:
    - /
  scaleTargetRef:
    name: {{ include "ollama.fullname" . }}
    kind: Deployment
    apiVersion: apps/v1
    service: {{ include "ollama.fullname" . }}
    port: {{ .Values.service.port }}
  replicas:
    min: 0
    max: 1
  scaledownPeriod: 300
  scalingMetric:
    requestRate:
      granularity: 1s
      targetValue: 100
      window: 1m

ollamaのServiceとは別に、ollama-proxyというExternalNameのServiceを作成します。
これは、kedaのkeda-add-ons-http-interceptor-proxy.keda.svc.cluster.localに名前解決されます。

  • externalservice.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "ollama.fullname" . }}-proxy
  labels:
    {{- include "ollama.labels" . | nindent 4 }}
spec:
  type: ExternalName
  externalName: keda-add-ons-http-interceptor-proxy.keda.svc.cluster.local

#動作確認

クラスタ内からollama-proxy.ollama.svc.cluster.localにアクセスすると、ゼロからスケールアウトして、HTTPレスポンスが返ってきます。2回叩いてみましたが、初回はPod起動するのに時間がかかり、3秒強といったところです。2回目は、すぐにレスポンスが返ってきました。初回の遅延をどう評価するかは、ユースケース次第だと思いますが、AIの推論など、そもそも遅延が長い場合や、ユーザが直接触らないようなEmbeddingの計算などでは、問題ないかもしれません。

> time curl ollama-proxy.ollama.svc.cluster.local:8080
Ollama is running
real	0m 3.41s
user	0m 0.00s
sys	0m 0.00s
> time curl ollama-proxy.ollama.svc.cluster.local:8080
Ollama is running
real	0m 0.00s
user	0m 0.00s
sys	0m 0.00s

scaledownPeriodで指定した300秒が経過すると、ゼロにスケールインされます。
これで他のGPUワークロードがGPUリソースを利用できるようになります。

 k get all -n ollama
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP                                                  PORT(S)     AGE
service/ollama         ClusterIP      10.43.172.18   <none>                                                       11434/TCP   114m
service/ollama-proxy   ExternalName   <none>         keda-add-ons-http-interceptor-proxy.keda.svc.cluster.local   <none>      89m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ollama   0/0     0            0           114m

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/ollama-8657894646   0         0         0       114m

NAME                                                  REFERENCE           TARGETS               MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/keda-hpa-ollama   Deployment/ollama   <unknown>/100 (avg)   1         1         0          114m

#参考リンク

#まとめ

今回は、KEDAを使ってGPUワークロードをゼロにスケールさせる方法について紹介しました。
KEDAは、イベント駆動のオートスケーラーで、HTTPリクエストに基づいたスケーリングも可能です。
KEDA HTTP add-onを使うことで、HTTPリクエストに基づいたスケーリングができるようになります。
GPUワークロードに限らず、イベント駆動でスケーリングしたい場合には、KEDAを使ってみると良いかもしれません。