Slide 1

Slide 1 text

負荷を予測して事前スケーリングする HPA の Custom Controller 実装
 @zuiurs (Mizuki Urushida) KubeFest Tokyo 2020 (2020/06/13)

Slide 2

Slide 2 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 2 みなさん HPA 使ってますか❓


Slide 3

Slide 3 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 3

Slide 4

Slide 4 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 4 負荷を予測してスケールできたら
 もっと良いと思いませんか❓


Slide 5

Slide 5 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 5

Slide 6

Slide 6 text

負荷を予測して事前スケーリングする HPA の Custom Controller 実装
 @zuiurs (Mizuki Urushida) KubeFest Tokyo 2020 (2020/06/13)

Slide 7

Slide 7 text

自己紹介
 7 ● Mizuki Urushida (@zuiurs)
 ● 2018~ CyberAgent, Inc.
 ● 最近やったこと
 ○ Kubernetes-native Testbed の構築・実装
 ○ Cluster Autoscaler の Cloud Provider 実装
 ○ Prow による CI/CD 基盤作成中
 ○ HPA に時系列予測を組み込む Custom Controller の実装
 ● 夕方までマンションが断水してます


Slide 8

Slide 8 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 8 


Slide 9

Slide 9 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 9 ☺ Horizontal Pod Autoscaler
 ☺ Background / Motivation
 ☺ About Intelligent HPA
 ☺ Architecture
 ☺ Tips of implemtation


Slide 10

Slide 10 text

Horizontal Pod Autoscaler 10

Slide 11

Slide 11 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 11 HPA についておさらい


Slide 12

Slide 12 text

Horizontal Pod Autoscaler
 12 ● 指定したメトリクスのしきい値を
 基準に Pod を増減させる仕組み
 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler spec: minReplicas: 1 maxReplicas: 30 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 Deployment ( 66% / Pod ) 40% 70% Deployment ( 50% / Pod ) 90% 40% 60% 70% 30% *

Slide 13

Slide 13 text

複数メトリクスの監視
 13 ● 最大レプリカ数が選択される
 ○ 一方が小さくなったときに
 誤ってスケールダウンされない
 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler spec: metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: External external: metric: name: nginx.net.request_per_s target: type: AverageValue averageValue: 10 5 replicas
 7 replicas
 7 replicas


Slide 14

Slide 14 text

外部メトリクスの参照
 14 ● Datadog/Prometheus のメトリクスを参照できる
 HPA
 metrics.k8s.io/v1beta1
 external.metrics.k8s.io/v1beta1
 kube-system/
 metrics-server
 default/
 datadog-cluster-agent-metrics-api 


Slide 15

Slide 15 text

Background / Motivation 15

Slide 16

Slide 16 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 16 HPA は実測値をもとに
 スケールします


Slide 17

Slide 17 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 17 負荷上がったし
 レプリカ数増やすかー


Slide 18

Slide 18 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 18 負荷上がったし
 レプリカ数増やすかー
 負荷が上がらないと増えない


Slide 19

Slide 19 text

しきい値設定に注意する
 19 ● 許容負荷ギリギリに設定していると間に合わない
 ○ 余裕をもたせたしきい値にする
 ○ 余裕をもたせすぎるとリソースの無駄遣いになってしまう
 ● READY まで時間のかかるアプリケーションだと設定が難しい
 ○ StatefulSet は比較的そういうものが多い
 起動ラグ


Slide 20

Slide 20 text

しきい値設定に注意する
 20 ● 許容負荷ギリギリに設定していると間に合わない
 ○ 余裕をもたせたしきい値にする
 ○ 余裕をもたせすぎるとリソースの無駄遣いになってしまう
 ● READY まで時間のかかるアプリケーションだと設定が難しい
 ○ StatefulSet は比較的そういうものが多い
 起動ラグ


Slide 21

Slide 21 text

Cluster Autoscaler 併用時の懸念
 21 ● Pod が起動するためのリソースがクラスタにないかも
 ○ CA は仕組み上 Pending Pod が現れないと Node を増やせない
 ○ Cluster Autoscaler の仕組みの詳細はこちら
 ● READY までの時間が Node の起動時間と一致してしまう
 ノード起動ラグ


Slide 22

Slide 22 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 22 めんどくせえ!


Slide 23

Slide 23 text

About Intelligent HPA 23

Slide 24

Slide 24 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 24 cyberagent-oss/intelligent-hpa


Slide 25

Slide 25 text

Intelligent HPA (IHPA)
 25 ● HPA への予測エントリの注入と
 予測ジョブやメトリクスの管理をするコントローラー
 ○ Kubebuilder v2 を使用して実装
 ○ 社内向けに作ったものを OSS 化
 ● メトリクス管理は Datadog のみ実装している
 ○ いずれ Prometheus (未検証) でクラスタ内完結させたい
 Intelligent
 HPA
 HPA
 Deployment
 生成
 操作


Slide 26

Slide 26 text

その他特徴
 26 ● メトリクスの予測ロジックのカスタマイズ
 ○ 予測ロジックを入れたコンテナイメージを作って指定する
 ● 予測メトリクスの調整機能
 ○ 予測値の外れ度合いに応じて、次の予測値を調整
 ● Type External の対応


Slide 27

Slide 27 text

Minimum Usage
 27 ● HPA を使っているようなイメージで使えるように設計
 apiVersion: ihpa.ake.cyberagent.co.jp/v1beta2 kind: IntelligentHorizontalPodAutoscaler spec: metricProvider: name: datadog datadog: apikey: xxx appkey: yyy template: spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: External external: metric: name: forecasted_cpu target: type: AverageValue averageValue: 10M 注入された
 予測エントリ
 Applied manifest
 Generated HPA


Slide 28

Slide 28 text

● 予測値の参照は Datadog を経由
 ● 先に参照するために時間をずらす
 ○ 例) 9:00 の予測値は 8:55 にずらす
 ○ → 8:55 になると 9:00 の値が見える
 予測値を参照するためのずらし
 28 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: External external: metric: name: forecasted_cpu target: type: AverageValue averageValue: 10M 注入された
 予測エントリ
 Generated HPA
 実測値
 予測値


Slide 29

Slide 29 text

● 実測値のエントリを残して実負荷の
 レプリカ数を下回らないようにする
 ○ 予測値は先に上昇する一方で
 先に下降し始める
 実測値のエントリの残存
 29 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: External external: metric: name: forecasted_cpu target: type: AverageValue averageValue: 10M 注入された
 予測エントリ
 Generated HPA
 実測値
 予測値


Slide 30

Slide 30 text

Architecture 30

Slide 31

Slide 31 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 31

Slide 32

Slide 32 text

CRD とその役割
 32 ● 責任の分割と単独利用性を考慮
 ● IntelligentHorizontalPodAutoscaler (IHPA)
 ○ IHPA に関わる全リソースの CRUD に集中
 ● FittingJob
 ○ 予測ジョブを実行して対象の
 ConfigMap に結果を出力
 ● Estimator
 ○ ConfigMap 内の予測データを
 Datadog などのプロバイダに送信


Slide 33

Slide 33 text

CRD とその役割
 33 ● 責任の分割と単独利用性を考慮
 ● IntelligentHorizontalPodAutoscaler (IHPA)
 ○ IHPA に関わる全リソースの CRUD に集中
 ● FittingJob
 ○ 予測ジョブを実行して対象の
 ConfigMap に結果を出力
 ● Estimator
 ○ ConfigMap 内の予測データを
 Datadog などのプロバイダに送信
 生成
 予測
 送信


Slide 34

Slide 34 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 34 あとは HPA に祈る


Slide 35

Slide 35 text

IntelligentHorizontalPodAutoscaler
 35 ● HPA の対象メトリクスの予測エントリを生成
 ○ cpu とかは例外的に kubernetes.cpu.usage.total に変換するなど
 ● 各種リソースをつなぎこむ
 ○ FittingJob/Estimator は独立しているため、
 データ共有用の ConfigMap を統一
 ○ ConfigMap に書き込むための RBAC をそれぞれ紐付ける
 予測データとして “cm1” を監視させる
 出力先として “cm1” 指定する


Slide 36

Slide 36 text

FittingJob
 ● 指定時刻周辺で学習を実行
 ○ Affinity などで実行ノードを指定可能
 ● デフォルトイメージは Prophet を使用した時系列予測
 ○ Datadog へのアクセス・各種入出力はライブラリにしているので
 予測モデルの実装に集中できるようにしている
 n 時台に実行
 { "provider":{ "datadog":{ "apikey":"xxx", "appkey":"yyy" } }, "targetMetricsName":"nginx.net.request_per_s", "targetTags":{ "kube_deployment":"nginx" }, "seasonality":"daily", "dataConfigMapName":"cm1", "dataConfigMapNamespace":"loadtest", "customConfig":"" } 36

Slide 37

Slide 37 text

Estimator
 37 ● 予測データをずらして送信
 ○ READY になるまでの時間 = ずらす時間として設定すると良い
 ■ 時間のかかるアプリでも、かからないものとして値を考えられる
 timestamp,yhat,yhat_upper,yhat_lower 1582253873,176.89,244.83,50.89 1582253933,126.80,251.26,8.17 1582253993,134.48,268.67,75.97

Slide 38

Slide 38 text

Estimator の予測値調整
 38 ● Upper/Lower の値の範囲で予測値を調整する
 ○ Prophet の設定では 90%ile/10%ile の値を吐き出す
 ○ 予測の外れ度合いをチェック


Slide 39

Slide 39 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 39

Slide 40

Slide 40 text

Tips of implementation 40

Slide 41

Slide 41 text

Kubebuilder のマニフェストカスタマイズ
 41 ● マニフェスト生成は kustomize が使用されている
 ○ 大体のパラメータは自由に変えられる
 ■ Namespace や Label など
 resources: - manager.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller newName: cyberagentoss/intelligent-hpa-controller newTag: latest apiVersion: apps/v1 kind: Deployment metadata: name: controller-manager namespace: system spec: template: spec: imagePullSecrets: - name: pull-secret ● イメージを置換したり
 ● パッチをあてたり


Slide 42

Slide 42 text

controller-runtime の Watch と Own
 42 ● Watch()
 ○ 対象 API の全リソースに対して発火
 ● Own()
 ○ 対象 API のうち自身の OwnerReference のついたものに対して発火
 ○ Estimator の ConfigMap への予測データ格納監視はこれが役立った
 ● 仕組みや基本的な機能についてはこちらの資料が詳しい
 ○ Kubebuilder/controller-runtime 入門
 Estimator
 ConfigMap
 ConfigMap
 ConfigMap
 Watch()
 Estimator
 ConfigMap
 ConfigMap
 ConfigMap
 Own()


Slide 43

Slide 43 text

マニフェスト設計における下位リソースの定義方法
 43 apiVersion: databases.spotahome.com/v1 kind: RedisFailover spec: redis: replicas: 3 image: redis:4.0-alpine imagePullPolicy: IfNotPresent Redis Operator
 
 直接的
 パッチ的 (?)
 なにそれ
 ・書いたものがそのまま作られる 
 ・省略できない
 ・一部のフィールドだけ書ける 
 ・省略できる
 例
 ・Deployment の Pod 定義 
 ・CronJob の Job 定義 
 ・Redis Operator の Redis/Sentinel 定義 
 ・TiDB Operator の PD などの定義
 定義
 ・k8s.io/api から引っ張るだけなので楽 
 ・YAMLを書くときの階層が深くなる 
 ・本家と同じような定義をするので面倒 
 ・階層がフラットになる 
 Defaulting
 コード内で行う必要がある 
 CRD の機能でできる 
 ● IHPA はパッチ的な定義を選択
 ○ 下位リソースを隠蔽するのに
 こちらの方が都合が良かった


Slide 44

Slide 44 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 44 type JobPatchSpec struct { // related to Job ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty"` BackoffLimit *int32 `json:"backoffLimit,omitempty"` Completions *int32 `json:"completions,omitempty"` // related to Pod Affinity *corev1.Affinity `json:"affinity,omitempty"` ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` NodeSelector map[string]string `json:"nodeSelector,omitempty"` ServiceAccountName string `json:"serviceAccountName,omitempty"` Tolerations []corev1.Toleration `json:"tolerations,omitempty"` Volumes []corev1.Volume `json:"volumes,omitempty"` // related to Container Args []string `json:"args,omitempty"` Command []string `json:"command,omitempty"` Env []corev1.EnvVar `json:"env,omitempty"` EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"` Image string `json:"image,omitempty"` ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` Resources corev1.ResourceRequirements `json:"resources,omitempty"` }

Slide 45

Slide 45 text

Predictive HPA
 45 ● 対抗馬
 ○ 名前が良いので嫉妬している
 ● 作り終わってホッとしていたらなんか出てきた
 ● アプローチの違い
 ○ IHPA: メトリクスを予測・HPA 経由でスケール
 ○ PHPA: レプリカ数を予測・Scale Subresource 経由でスケール
 ● 詳細はこちら


Slide 46

Slide 46 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 46 cyberagent-oss/intelligent-hpa


Slide 47

Slide 47 text

まとめ (3 行)
 47 ● HPA は一部ケースではしきい値決定が非常に難しい
 ● 予測値に対してスケールすると HPA がうまく働きやすくなる
 ● 予測値エントリを注入する Custom Controller を作りました


Slide 48

Slide 48 text

Implement custom controller for metrics prediction @KubeFest Tokyo 2020 48 Thank you for your watching! Any Question?