Flaggerを利用しているKubernetes環境にKEDAを導入する方法

# 本記事
前回、Kubernetes Podのゼロスケールを実現するためにKEDAの活用を紹介しました。
今回はFlaggerを利用している場合のKEDAの導入方法と注意ポイントについて紹介します。

https://qiita.com/yuuuuuu10/private/a51ddd2e8d6c9b212441

# Flagger
Kubernetes上で実行されるアプリケーションのリリースプロセスを自動化するプログレッシブデリバリーツールです。

https://docs.flagger.app/

公式でKEDAに関するドキュメントも用意されています。

https://docs.flagger.app/tutorials/keda-scaledobject

# Canary
Horizontal Pod Autoscaler(HPA)でPodの自動スケーリングを行なっている場合、カスタムリソースであるCanaryリソースの`.spec.autoscalerRef`は以下のようになっています。


``` yaml
autoscalerRef:
  apiVersion: autoscaling/v2
  kind: HorizontalPodAutoscaler
  name: sample-hpa
```

KEDAを導入する場合は`.spec.autoscalerRef`にKEDAのカスタムメトリクスであるScaledObjectを指定します。

``` yaml
autoscalerRef:
  apiVersion: keda.sh/v1alpha1
  kind: ScaledObject
  name: sample-scaledobject
```

上記を設定することでPodの自動スケーリングはHPAからScaledObject（が内部で作成するHPA）に切り替わります。

# ScaledObjectのデプロイ
Flaggerを利用している場合にScaledObjectのデプロイにおいて注意したいポイントがあります。

ScaledObjectは内部でHPAを作成するため、既存で利用しているHPAが存在しているとHPAの重複エラーが発生します。
```
Error from server (the workload 'sample-deployment' of type 'apps/v1.Deployment' is already managed by the hpa 'sample-hpa'): admission webhook "vscaledobject.kb.io" denied the request: the workload 'sample-deployment' of type 'apps/v1.Deployment' is already managed by the hpa 'sample-hpa'
```

エラーの回避策がドキュメントにあり、既存のHPAの所有権をScaledObjectに譲渡します。そうすることでエラーは発生せず、既存のHPAの設定がScaledObjectによって上書きされます。

ただしここが注意したいポイントであり、Flaggerを利用しているとこの設定を追加しても正常にScaledObjectをデプロイすることはできません。

https://keda.sh/docs/2.16/concepts/scaling-deployments/#transferring-ownership-of-an-existing-hpa

``` yaml
metadata:
  annotations:
    scaledobject.keda.sh/transfer-hpa-ownership: "true"
spec:
   advanced:
      horizontalPodAutoscalerConfig:
        name: {name-of-hpa-resource}
```

## なぜデプロイが失敗するのか？
Canaryリソースで以下のように定義すると、`sample-hpa`と`sample-hpa-primary`というようにCanary Pod用とPrimary Pod用の2つのHPAが作られます。

``` yaml
autoscalerRef:
  apiVersion: autoscaling/v2
  kind: HorizontalPodAutoscaler
  name: sample-hpa
```

先述したエラー回避策を設定すると`sample-hpa`には適用されますが`sample-hpa-primary`には適用されません。

``` yaml
metadata:
  annotations:
    scaledobject.keda.sh/transfer-hpa-ownership: "true"
spec:
   advanced:
      horizontalPodAutoscalerConfig:
        name: sample-hpa
```

そのためScaledObjectをデプロイしてカナリアリリースが始まっても`sample-hpa-primary`の重複エラーが発生してしまいます。

```
Warning Synced flagger creating Keda ScaledObject sample-scaledobject-primary.sample-ns failed: admission webhook "vscaledobject.kb.io" denied the request: the workload 'sample-deployment-primary' of type 'apps/v1.Deployment 
│ ' is already managed by the hpa 'sample-hpa-primary'
```

この事象はissueが切られています。

https://github.com/fluxcd/flagger/issues/1646

## どうすれば良いのか？
選択肢は3つあると思います。

1. 既存のHPAを削除してからScaledObjectをデプロイする
1. Admission Webhooksのバリデーションを無効化
1. 事象が改善されるのを待つ

「2.Admission Webhooksのバリデーションを無効化」は設定方法がドキュメントにありますが、KEDAを利用する上でのベストプラクティスとしてScaledObject（が内部で作成するHPA）とHPAは競合するリスクがあるため併用しないようにとあります。選択肢から外すのが無難です。

https://keda.sh/docs/2.16/concepts/scaling-deployments/#disabling-validations-on-an-existing-hpa

https://keda.sh/docs/2.16/reference/faq/#dont-combine-scaledobject-with-horizontal-pod-autoscaler-hpa

筆者は「1. 既存のHPAを削除してからScaledObjectをデプロイする」を選択しました。
既存のHPAを削除してからScaledObjectのデプロイが完了するまでは自動スケールされないため、アプリケーションの負荷が低い時間帯に実施したり、あらかじめ十分なPod数に拡張したりするなど対策することをおすすめします。

最後の「3. 事象が改善されるのを待つ」については、筆者がKEDAを導入した際にはissueが切られているだけでいつ改善されるか分からない状況でしたが、現在はissueに対するPull Requestが作成されています。これからKEDAの導入を検討されるのであれば改善されるのを待つこともありかもしれません。

https://github.com/fluxcd/flagger/pull/1677

## 終わりに
Flaggerを利用しているKubernetes環境にKEDAを導入する方法と注意ポイントを紹介しました。これからKEDAを導入しようと考えている人の参考になれば幸いです。