Horizontal Pod Autoscaler Walkthrough

- *HPAの理解のために[Horizontal Pod Autoscaler Walkthrough](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics)を翻訳しました。*
- *2018,10,09(ver1.12.1)現在の内容の素人翻訳なので間違いなどあると思います。*
- 原文と対応させたいので各セクションの見出しや用語は原文ママにしています。

# Horizontal Pod Autoscaler
`Horizontal Pod Autoscaler`(以下`HPA`)は`Replication Controller`, `Deployment`, `Replica Set`のPod数をCPU使用率(もしくは他のアプリケーションから提供されるカスタムメトリクス)に基づいて自動的にスケールします。

ただし、`Deamon Sets`のようなリソースは対象外であることは留意してください。

`HPA`はk8s Apiリソースとコントローラとして実装されています。
それはコントローラの動作を定義します。

コントローラはユーザによって設定された平均CPU使用率にマッチするように定期的に`Replication Controller`, `Deployment`内のレプリカ数を調整します。

- [How does the Horizontal Pod Autoscaler work?](#how-does-the-horizontal-pod-autoscaler-work)
- [API Object](#api-object)
- [Support for Horizontal Pod Autoscaler in kubectl](#support-for-horizontal-pod-autoscaler-in-kubectl)
- [Autoscaling during rolling update](#autoscaling-during-rolling-update)
- [Support for cooldown/delay](#support-for-cooldowndelay)
- [Support for multiple metrics](#support-for-multiple-metrics)
- [Support for custom metrics](#support-for-custom-metrics)
- [Support for metrics APIs](#support-for-metrics-apis)
- [What's next](#whats-next)

# How does the Horizontal Pod Autoscaler work?

<img src="https://qiita-image-store.s3.amazonaws.com/0/12060/4a740b9c-ee9a-61a1-fc34-af27cdc424b5.png" alt="Horizontal Pod Autoscaler diagram" width=70% />

`HPA`はコントローラーマネージャーの`--horizontal-pod-autoscaler-sync-period`フラグ(デフォルト30秒)でコントロールされる期間ごとに繰り返しコントロールするものとして実装されています。

それぞれの期間、コントローラマネージャーはそれぞれの`HPA`に定義された指定されたメトリクスに対してリソースの利用量を問い合わせます。

コントローラマネージャーはリソースのメトリクスAPI(podごとのリソースメトリクス)かカスタムメトリクス(他のメトリクス)どちらかからメトリクスを獲得します。

- pod単位のリソースメトリクス(CPUなど)の場合、コントローラは`HPA`で指定された各podのメトリクスAPIからメトリックをフェッチします。

  次に目標使用率が設定されている場合、コントローラは各podのリソース要求に対して目標利用率がどういうパーセンテージなのかを計算します。

  ターゲットの生の値がセットされている場合、直接生のメトリクス値が使用されます。

  次にコントローラは利用率か生の値(指定されたターゲットのタイプに応じた)の平均値を指定された全てのpodから取得します。
  そして要求レプリカ数をスケールするための比率を生成します。

要求リソースがpodの`request`にない場合、podのCPU使用率は定義されず、オートスケーラはメトリックに対して何もしません。

オートスケーリングのアルゴリズムの詳細は[algorithm details](/#algorithm-details)をみてください。

- podごとのカスタムメトリックの場合、リソースメトリックと同様に動作しますが、利用率を使わずに生の値を使います。
- オブジェクトメトリックと外部メトリックでは、まず1つのメトリックをフェッチします。このメトリックは目標値と比較されて[前述の比率](xxxxx)を生成します。

  `autoscaling/v2beta2`では比較される前にpod数で分割した値にするということをオプションで選択できます。

`HPA`は普通は集計API(`metrics.k8s.io`, `custom.metrics.k8s.io`, `external.metrics.k8s.io`)からメトリックをフェッチします。

`metrics.k8s.io`APIは各nodeごとにローンチされているはずの`metrics-server`から提供されています。
[metrics-server](https://kubernetes.io/docs/tasks/debug-application-cluster/core-metrics-pipeline/#metrics-server)の説明はみておいてください。
`HPA`は`Heapster`から直接メトリックを取ることもできます。

**`HPA`が直接`Heapster`からメトリックを取得するのはk8s 1.11から非推奨になりました**

`metrics API`のサポートについてもっと知りたい場合は[ここ](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-apis)参照

*多分GKEとかマネージドだったら特に気にしなくていい情報だと思われ*

オートスケーラは`Scale sub resource`を使ってスケール可能なコントローラ(`RC`,`Deployment`, `RS`)にアクセスします。

`Scale`はレプリカ数をセットすることと、各レプリカの状態を調査することを許可します。

`Scale sub-resource`については[ここ](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/autoscaling/horizontal-pod-autoscaler.md#scale-subresource)を参照ください。


## Algorithm Details
最も基本的な観点として、`HPA`コントローラは目標値と、現在のメトリック値の間の比率で動いています。

```
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
```

(例)
現在のメトリックが200mで、目標値が100mだった場合、`200/100 == 2.0`なのでレプリカ数は2倍になります。

現在値が50mだったら`50/100 == 0.5`なので半分にします。

比率が1.0に十分に近かったら、スケーリングはされません。

このしきい値(耐性)は`--horizontal-pod-autoscaler-tolerance`フラグで設定できます。デフォルトは`0.1`です。

*つまりデフォルトだと current/desire == 1.1*の場合はスケールしないということ*

`targetAverageValue`か`targetAverageUtilization`が指定されている場合、`currentMetricValue`は`HPA`で指定された全てのPodのメトリックの平均を取得して計算されます。

削除タイムスタンプがついたpod(シャットダウンされているプロセス中のpod)と失敗してるpodは全て削除されます。

メトリックが無いpodも存在します。そのpodは一旦置いておかれます。最終的にスケーリングするpod数の最終調整時の辻褄合わせに使用されます。

CPUでスケーリングする場合、まだpodが準備段階（初期化中）かpodの最新メトリックポイント（メトリックするタイミング？）が準備完了になった時点でとり置かれます。

技術的な制約により、特定のCPUメトリクスを脇に取り置くかどうか決めるときは、`HPA`コントローラはpodが準備完了になる最初の時間を正確に決めることはできません。

その代わりに、ポッドは、まだ準備ができていない場合は「準備ができていない」とみなされ、開始されてから短い設定可能な時間内に未使用に移行します。

この`設定可能な時間`は`--horizo​​ntal-pod-autoscaler-initial-readiness-delay`フラグで設定され、デフォルトは30秒です。ポッドが準備完了状態になると、開始されてから設定可能な時間が長くなると、ポッドが最初になる準備が整ったとみなされます。この値は`--horizo​​ntal-pod-autoscaler-cpu-initialization-period`フラグで設定され、デフォルトは5分です。

`currentMetricValue / desiredMetricValue`ベーススケールはそのあと、脇にとり置かれたり、前述のように削除されたpodを使用して計算されます。

取得できなかったメトリックがある場合、スケールダウンの時は100%、スケールアップ(スケールアウトのが正しいのでは？)の場合は0%を消費する仮定をし、より保守的に平均値の消費量を計算し直します。
これにより潜在的なスケールの振れ幅を小さくします。

さらに、準備未完了のpodがあり、欠落したメトリックや準備未完了のpodがある事実を考慮せずにスケールアップしてしまっている場合、保守的に準備未完了のpodは目標メトリックに対して0%消費していると想定し、さらにスケールの振れ幅を小さくします。

欠落したメトリック、準備未完了のpodを判明させた後、使用率を再計算します。
そうしてできた新しい比率が先ほどのスケールの決定事項を覆したり、しきい値(耐性)の範囲内である場合は、スケールをスキップします。
言い換えれば、新しい比率を使うということです。

Note: 新しい使用率が使われても、平均利用値のオリジナル値は準備未完了pod、欠落メトリックを考慮しない状態でHPAのステータスを通して報告されます。

HPAで複数のメトリックが指定されている場合、各メトリックの計算がされ、一番目標レプリカ数の大きいものが採用されます。
もし、それらのメトリックをレプリカ数に変換できない場合（例: メトリックAPIからエラーが返された場合）はスケールがスキップされます。

最後に（ようやく）HPAがスケールをする直前に、スケールのリコメンデーションが記録されます。
(リコメンデーションは複数溜まっていて)HPAコントローラは設定可能なウィンドウの最高推奨値を選択し、そのウィンドウ内の全てのリコメンデーションを考慮します。

最高推奨は`--horizontal-pod-autoscaler-downscale-stabilization-window`フラグで設定できます。デフォルトは5分です。

これにより、スケールダウンが徐々に発生し、急激なメトリック変化の影響によるインパクトを抑えます。

# API Object

HPAはk8sの`autoscaling`API groupのAPIリソースです。
現在のstableバージョン`autoscaling/v1`ではCPUのオートスケールのみサポートします。

`autoscaling/v2beta2`ではmemory, custom metricsを選択することが可能です。
`autoscaling/v2beta2`の記述を`autoscaling/v1`で動かす場合は単に注釈として保存されます。

詳細は[HorizontalPodAutoscaler Object](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/autoscaling/horizontal-pod-autoscaler.md#horizontalpodautoscaler-object)を参照ください。

# Support for Horizontal Pod Autoscaler in kubectl
`HPA`をはじめとして全てのAPIリソースは`kubectl`でサポートされます。
`kubectl create`コマンドで新しいオートスケーラーを作ることができます。
`kubectl get hpa`でリスト表示、`kubectl describe hpa`で詳細を取得できます。
`kubectl delete hpa`で削除できます。

加えて`kubectl autoscale`コマンドで簡単にHPAを作成できます。
おもむろに`kubectl autoscale rs foo --min=2 --max=5 --cpu-percent=80`を実行すれば、fooというRSに目標CPU使用率、2〜5のレプリカ数でHPAを設定することができます。

詳細は[ここ](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands/#autoscale)を見てください。


# Autoscaling during rolling update
現在、k8sはReplication Controllerを直に管理するか、RSを管理するDeploymentオブジェクトを使用して[rolling update](https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/)を実行することができます。
HPAは後者のアプローチをサポートします。
つまり、HPAはDeploymentにバインドされ、Deploymentはそれが持つReplica Setのサイズを設定します。

HPAはReplication Controllerの直接操作のrolling updateでは動作しません。
つまり、Replication ControllerはHPAにバインドされないので`kubectl rolling-update`を使ってください。

上記のようにReplication Controllerのrolling-updateでHPAが動かないのは、rolling-updateが新しいReplication Controllerを作るという挙動によるものです。HPAは新しいReplication Controllerにバインドされません。

# Support for cooldown/delay
HPAを使ってレプリカのグループのスケールを管理するとき、動的に発生するメトリック評価値によって頻繁にレプリカ数の増減が起こり続く可能性があります。
これは`thrashing`と呼ばれます。

v1.6〜では、`kube-controller-manager`コンポーネントに用意されているフラグとして公開されているHPAグローバル設定をチューニングすることでこの問題を緩和できます。

v1.12〜では、新しいアルゴリズムによりアップスケール遅延をする必要がなくなりました。

`--horizontal-pod-autoscaler-downscale-delay`
このオプションは現在のスケーリング処理が完了してから他のダウンスケール処理をはじめるのに待つ期間を設定するものです。

Note: これらのパラメタをチューニングする際はクラスタのオペレータ担当者は発生しうる結果に注意しないといけません。
クールダウンの遅延が長すぎればワークロードの変化にHPAが反応しなくなり、逆に短すぎるとスラッシングが発生します。

# Support for multiple metrics
k8sは`multiple metrics`によるスケーリングをサポートしています。
`autoscaling/v2beta2`APIバージョンを使い、HPAに複数のメトリックを設定し、それに則ってスケールすることができます。
HPAコントローラは各メトリックを評価し、そのメトリックに則った新しいスケーリングを提案します。
一番大きいレプリカ数の提案が採用されます。

# Support for custom metrics
k8s1.2でalphaサポートされました。特別な`annotations`を使うことでアプリケーション固有のメトリックに基づきスケーリングすることができるようになりました。

ただし、それらの`annotations`はk8s1.6でオートスケーリングapiから廃止されました。
従来の方法でのカスタムメトリックの収集はまだ可能です。
ただし、HPAでは使えません。そして、前者のどのカスタムメトリックかを指定するアノテーションをHPAでは使えなくなりました。

k8s1.6はHPAでカスタムメトリックを使うためのサポートを追加しました。
`autoscaling/v2beta2`apiを使ってカスタムメトリクスをHPAに追加できます。
k8sは最適なメトリックを使うために新しいカスタムメトリックapi

詳しくは[Support for metrics APIs](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-APIs)を参照すること

# Support for metrics APIs
デフォルトでは、HPAは一連のapiメトリックapiを検索します。
それらのapiを検索するために、クラスターの管理担当者は下記をしておく必要があります。

- apiの集約レイヤが有効であること
- 対応するapiが登録済みであること
  - `metrics.k8s.io`: 通常、`metric-server`により提供されています。クラスターのアドオンとしてローンチされます。
  - `custom.metrics.k8s.io`: "アダプター"apiサーバーによって提供されます。アダプターはメトリックのソリューションベンダーによって提供されます。
    メトリックのパイプラインをチェックするか、[よく知られたソリューション](https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api)をご活用ください。
  - `external.metrics.k8s.io`: 前述のカスタムメトリクスのアダプターによって提供されると思います。
- `--horizontal-pod-autoscaler-use-rest-clients`はtrueもしくはセットされていない状態です。このフラグによりHeapsterベースのオートスケーリングに切り替わりますが、現在は非推奨です。
(metrics-serverサポートにより？)

# What's next
- Design documentation: [Horizontal Pod Autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-APIs).
- kubectl autoscale command: [kubectl autoscale](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#autoscale).
- Usage example of [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/).