【後編】ゼロから学ぶKEDA：導入手順とScaledObjectの設定方法【コスト削減編】

## はじめに
この記事では、Kubernetesでイベント駆動型スケーリングを実現する KEDA について、基礎から応用（導入）までを解説します。
「KEDAとは何か？」という基本的な疑問に答えるところから始め、KEDAのアーキテクチャやベストプラクティス、さらに実際の導入方法までを 3部構成 で整理し、KEDAの仕組みや運用のポイントを理解できるように構成しています。

【後編】となる本記事では、KEDAの導入手順とScaledObjectの設定方法について解説します。

[【前編】ゼロから学ぶKEDA：概要と導入目的](https://qiita.com/kimuchi-system/items/75c6364141701147905a)
[【中編】ゼロから学ぶKEDA：アーキテクチャ・ベストプラクティス解説](https://qiita.com/kimuchi-system/items/317f6f8b31ba16944744)

## 対象読者
- Kubernetesを学習・導入している方
- KEDAって聞いたことがあるけど、「何をどうスケールしてくれるのかわからない」という方
- 「KEDAの導入に興味はあるけど、どこから手をつければいいかわからない」と悩んでいる方

## KEDAの導入と環境構築

### KEDAのインストール

以下のコマンドを実行して、KEDAをKubernetesクラスタにインストールします。

```bash
> kubectl apply --server-side -f https://github.com/kedacore/keda/releases/download/v2.16.0/keda-2.16.0.yaml

namespace/keda serverside-applied
customresourcedefinition.apiextensions.k8s.io/cloudeventsources.eventing.keda.sh serverside-applied
customresourcedefinition.apiextensions.k8s.io/clustercloudeventsources.eventing.keda.sh serverside-applied
customresourcedefinition.apiextensions.k8s.io/clustertriggerauthentications.keda.sh serverside-applied
customresourcedefinition.apiextensions.k8s.io/scaledjobs.keda.sh serverside-applied
customresourcedefinition.apiextensions.k8s.io/scaledobjects.keda.sh serverside-applied
customresourcedefinition.apiextensions.k8s.io/triggerauthentications.keda.sh serverside-applied
serviceaccount/keda-operator serverside-applied
role.rbac.authorization.k8s.io/keda-operator serverside-applied
clusterrole.rbac.authorization.k8s.io/keda-external-metrics-reader serverside-applied
clusterrole.rbac.authorization.k8s.io/keda-operator serverside-applied
rolebinding.rbac.authorization.k8s.io/keda-operator serverside-applied
rolebinding.rbac.authorization.k8s.io/keda-auth-reader serverside-applied
clusterrolebinding.rbac.authorization.k8s.io/keda-hpa-controller-external-metrics serverside-applied
clusterrolebinding.rbac.authorization.k8s.io/keda-operator serverside-applied
clusterrolebinding.rbac.authorization.k8s.io/keda-system-auth-delegator serverside-applied
service/keda-admission-webhooks serverside-applied
service/keda-metrics-apiserver serverside-applied
service/keda-operator serverside-applied
deployment.apps/keda-admission serverside-applied
deployment.apps/keda-metrics-apiserver serverside-applied
deployment.apps/keda-operator serverside-applied
apiservice.apiregistration.k8s.io/v1beta1.external.metrics.k8s.io serverside-applied
validatingwebhookconfiguration.admissionregistration.k8s.io/keda-admission serverside-applied
```
このコマンドにより、KEDA名前空間にCRDやリソースが作成されます。
（ref.https://keda.sh/docs/2.16/deploy/#yaml）

## ScaledObjectの設定とゼロスケール
KEDAの**ゼロスケール機能**を利用して、特定のスケジュールに基づいてPodのスケールを自動化します。この設定により、指定した時間にPodをスケールダウンしてリソースを節約し、必要なタイミングで自動的にスケールアウトできます。

### ScaledObject設定
以下のYAMLを使用して`ScaledObject`を作成すると、スケジュールに基づいてPodの数を自動で調整できます。

```yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: cron-scaledobject  # ScaledObjectの名前を指定
  namespace: kimuchi-httpbin  # 対象のNamespaceを指定
spec:
  scaleTargetRef:
    name: httpbin  # スケール対象のDeployment名
  minReplicaCount: 0  # 最小Replica数を0に設定（ゼロスケールを有効化）
  maxReplicaCount: 3  # 最大Replica数を3に設定
  triggers:
    - type: cron
      metadata:
        timezone: Asia/Tokyo  # タイムゾーンを指定
        start: 0 7 * * 1-5  # 平日の午前7時にスケーリングを開始
        end: 0 23 * * 1-5  # 平日の午後23時にスケーリングを終了
        desiredReplicas: "1"  # スケールアウト時のPod数
```

### 設定の適用
作成したYAMLファイルを適用するには、以下のコマンドを実行します。
ここでは、`cron-scaledobject.yaml`という名前のファイルを使用していますが、このファイルには先ほど記載した`ScaledObject`の設定が含まれています。

```bash
> kubectl apply -f cron-scaledobject.yaml
```

### 設定後の動作確認

設定が正しく適用されたことを確認するために、以下の手順で状態をチェックします。

#### 1. ScaledObjectの状態を確認

以下のコマンドで`ScaledObject`の状態を確認します。

```bash
# ScaledObject名、ターゲットリソースの種類と名前、最小・最大Pod数、現在の状態などが確認可能
> kubectl get ScaledObject -n kimuchi-httpbin
NAME                SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   READY   ACTIVE   FALLBACK   PAUSED    TRIGGERS   AUTHENTICATIONS   AGE
cron-scaledobject   apps/v1.Deployment   httpbin           0     3     True    False    False      Unknown   cron                         51s

# KEDAによって作成されたHPAが正常に動作しているか確認
> kubectl get hpa -n kimuchi-httpbin                                                                                                                          
NAME                         REFERENCE            TARGETS             MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-cron-scaledobject   Deployment/httpbin   <unknown>/1 (avg)   1         3         0          63s

# 現在のシステム時間を表示するコマンド
# Cronトリガーの動作タイミングを確認する際に使用
> date                                                                                                                                                     
2024年 11月14日 木曜日 23時10分11秒 JST
 
# Namespace内の稼働中のPodを確認するコマンド
# 時間外のため、Podがスケールダウンして0になっていることを確認
> kubectl get po -n kimuchi-httpbin                                                                                                               
No resources found in kimuchi-httpbin namespace.
```
現在の時間はスケーリングルールで指定された**稼働時間外**に該当するため、Podが**スケールダウン**しており、`Namespace`内に稼働中のPodは存在しません。スケーリングルールに基づいて、リソースが管理されている状態です。

### スケールアウトの開始を確認
スケーリングルールの**稼働時間内**に、スケールアウトが開始されているか確認します。
以下のコマンドで、`ScaledObject`、`HPA`、そして`Namespace`内のPodの状態を確認します。

```bash
# 現在のシステム時間を確認
> date 
2024年 11月15日 金曜日 7時10分37秒 JST

# ScaledObjectの状態を確認
> kubectl get ScaledObject -n kimuchi-httpbin
NAME                SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   READY   ACTIVE   FALLBACK   PAUSED    TRIGGERS   AUTHENTICATIONS   AGE
cron-scaledobject   apps/v1.Deployment   httpbin           0     3     True    True     False      Unknown   cron                         4m4s

# HPAの状態を確認
> kubectl get hpa -n kimuchi-httpbin 
NAME                         REFERENCE            TARGETS             MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-cron-scaledobject   Deployment/httpbin   <unknown>/1 (avg)   1         3         0          4m16s

# Namespace内のPodの状態を確認（新しいPodが作成され、稼働中であることを確認）
> kubectl get po -n kimuchi-httpbin
NAME                       READY   STATUS    RESTARTS   AGE
httpbin-7f56dc944b-g8ddb   1/1     Running   0          4m15s
```
この結果から、スケールアウトが正常に動作していることが確認できます。

## CPUトリガーの追加
負荷に応じてPodを自動的にスケーリングするために、CPUトリガーを設定します。

### CPUトリガー設定
`ScaledObject`に以下の設定を追加します：

```yaml
triggers:
  - type: cpu
    metricType: Utilization
    metadata:
      value: "50"  # CPU使用率が50%を超えた場合にスケールアップ
```
この設定により、CPU使用率が50%を超えるとPodが自動的にスケールアップし、負荷に応じた柔軟なスケーリングが可能になります。

### 最終的なマニフェスト
以下は、CPUトリガーとCronトリガーを組み合わせた`ScaledObject`の最終マニフェスト例です：
```yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: cron-scaledobject  # ScaledObjectの名前を指定
  namespace: kimuchi-httpbin  # 対象のNamespaceを指定
spec:
  scaleTargetRef:
    name: httpbin  # スケール対象のDeployment名
  minReplicaCount: 0  # 最小Replica数を0に設定（ゼロスケールを有効化）
  maxReplicaCount: 3  # 最大Replica数を3に設定
  triggers:
    - type: cpu
      metricType: Utilization
      metadata:
        value: "50" # CPU使用率が50%を超えた場合にスケールアップ
    - type: cron
      metadata:
        timezone: Asia/Tokyo  # タイムゾーンを指定
        start: 0 7 * * 1-5  # 平日の午前7時にスケーリングを開始
        end: 0 23 * * 1-5  # 平日の午後23時にスケーリングを終了
        desiredReplicas: "1"  # スケールアウト時のPod数
```

このマニフェストを適用すると、以下の動作が実現します：
- **夜間（利用がない時間帯）**
    - Podを自動的にゼロスケールし、不要なリソースの消費を抑えます。
- **日中（利用がある時間帯）**
    - 常に1つのPodを稼働させ、CPU使用率が高くなると自動的にPodを増やして負荷に対応します。

これにより、夜間はリソースを節約し、日中は負荷に応じて柔軟にスケールする運用が可能になります。

## まとめ
KEDAを活用することで、夜間はPodを**ゼロスケール**してリソースを節約し、不要なコストを削減できます。
さらに、日中の稼働時には最低限のPodを維持しながら、CPU使用率に応じて自動的にスケールアウトするため、柔軟に負荷に対応できます。

いいね・コメントお待ちしてます！