Kubernetes のコスト最適化ゴールデンシグナル

## はじめに
こんにちは、Datadog Japan で Sales Engineer をしている [**AoTo**](https://qiita.com/AoTo0330) です。

この記事は [**<font color="#6495ED">AoTo Advent Calendar 2023</font>**](https://qiita.com/advent-calendar/2023/aoto) と [**Google Cloud Champion Innovators Advent Calendar 2023**](https://adventar.org/calendars/9217) のクロスポスト記事です。

[State of Kubernetes Cost Optimization](
https://inthecloud.withgoogle.com/state-of-kubernetes-cost-optimization-report/dl-cd.html) というレポートをご存じでしょうか。このレポートでは **Kubernetes のコスト最適化**にフォーカスし、その指標となる**4つのゴールデンシグナル**を示しています。

https://cloud.google.com/blog/ja/products/containers-kubernetes/new-report-state-of-kubernetes-cost-optimization

今回は、これらのゴールデンシグナルの定義と最適化方法を、レポートの内容をもとに解説していきます。

## コスト最適化ゴールデンシグナル
コスト最適化ゴールデンシグナルとして示されているのは以下の4つです。[^1]
[^1]:和訳名はオリジナルで付けています。より良い命名があれば教えてください。

 - Workload rightsizing(ワークロードの適正サイズ)
 - Demand based downscaling(需要に基づくダウンスケーリング)
 - Cluster bin packing(クラスター詰め込み)
 - Discount coverage(割引適用率)

![golden_signals.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/e7552f8a-5752-b451-f7b3-d84e1722297c.png)

上記のうち、はじめの3点は Kubernetes クラスターの使用状況を表すメトリクスで、最後はコストの支払いモデルに関する達成度です。さらに、それぞれのステークホルダーが示されており、はじめの3点は**アプリケーション開発者**が、後ろの3点は**プラットフォーム管理者**が、そして最後の1点は**予算所有者**によってコントロールできます。

### Workload rightsizing(ワークロードの適正サイズ)
**Workload rightsizing** は、開発者がアプリケーション([ワークロード](https://kubernetes.io/ja/docs/concepts/workloads/))にリクエストした CPU とメモリを使用する能力を測定します。これは [Vertical Pod Autoscaler(VPA)](https://cloud.google.com/kubernetes-engine/docs/concepts/verticalpodautoscaler) が推奨した値と実測値を比較して、どれほど最適なサイズで Pod がリソースの要求を行っているかによって定義されます。

$k$ はクラスター数の合計値、$C_{k}$ は $k$ 番目のクラスターが存在していた期間を示します。$r_{1,k}$ と $r_{２,k}$ は通常$(0,1]$ で定義されます。

```math
r_{1,k} = \frac{\sum_{k=1}^{C_{k}} 平均推奨CPU量}{\sum_{k=1}^{C_{k}} 平均CPU リクエスト量}
```

```math
r_{2,k} = \frac{\sum_{k=1}^{C_{k}} 平均推奨メモリ量}{\sum_{k=1}^{C_{k}} 平均メモリリクエスト量}
```

これは、[自動モードでの VPA](https://cloud.google.com/kubernetes-engine/docs/concepts/verticalpodautoscaler?hl=ja#vertical_pod_autoscaling_in_auto_mode) を使用することで最適化が可能です。 K8s の制限により、実行中の Pod のリソースリクエストをそのまま変更することはできず、Pod を再作成する必要があるため注意が必要です。

Google Cloud の VPA は更新前に[クラスタオートスケーラー](https://cloud.google.com/kubernetes-engine/docs/concepts/cluster-autoscaler?hl=ja)に通知をして、変更に必要なリソースをワークロードの際作成前に提供することで中断時間を最小限にします。

### Demand based downscaling(需要に基づくダウンスケーリング)
**Demand based downscaling** は、開発者とプラットフォーム管理者がオフピーク時にクラスタをスケールダウンさせる能力を測定します。これは、最小ノード数の最大ノード数からの乖離によって定義されます。

$r_{3,k}$ は $(0,1]$ で定義されます。1に近いほどダウンスケーリングを最適に行えていることになります。

```math
r_{3,k} = 1 - \frac{最小ノード数}{最大ノード数}
```

これは、前述の[クラスタオートスケーラー](https://cloud.google.com/kubernetes-engine/docs/concepts/cluster-autoscaler?hl=ja)によって最適化が可能です。

### Cluster bin packing(クラスターへのビンパッキング)
**Cluster bin packing** は、開発者とプラットフォーム管理者がポッド配置によって各ノードのCPUとメモリを完全に割り当てる能力を測定します。これは、CPU とメモリのリクエストと割当の量の乖離によって定義されます。

$r_{4,k}$ と $r_{5,k}$ は $(0,1]$ で定義されます。1に近いほどビンパッキングを最適に行えていることになります。

```math
r_{4,k} = \frac{\sum_{k=1}^{C_{k}} 平均CPUリクエスト量}{\sum_{k=1}^{C_{k}} 平均CPU割当量}
```

```math
r_{5,k} = \frac{\sum_{k=1}^{C_{k}} 平均メモリリクエスト量}{\sum_{k=1}^{C_{k}} 平均メモリ割当量}
```
これらは、[リソース制限の設定](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits)によって最適化が可能です。ただし、前述の [VPA](https://cloud.google.com/kubernetes-engine/docs/concepts/verticalpodautoscaler?hl=ja) を構成することでこれらの値を手動で設定するさいに使用したり、自動で設定が可能です。

### Discount coverage(割引適用率)
**Discount coverage** は、[Spot VM](https://cloud.google.com/compute/docs/instances/spot?hl=ja) のようなディスカウントを活用するプラットフォーム管理者の能力と、[長期継続利用](https://cloud.google.com/compute/docs/sustained-use-discounts?hl=ja)のディスカウントを活用する予算所有者の能力を測定します。これは、単純にディスカウントが適用されているノードの台数で定義されます。

$r_{6,k}$ は $(0,1]$ で定義されます。1に近いほどディスカウントを最適に行えていることになります。

```math
r_{6,k} = \frac{割引されたコア時間}{合計コア時間}
```

これは、[Spot VM](https://cloud.google.com/compute/docs/instances/spot?hl=ja) の活用や[長期継続利用](https://cloud.google.com/compute/docs/sustained-use-discounts?hl=ja)を理解し活用することで最適化が可能です。Spot VM の場合は、ワークロードが中断されても良いようなステートレスな構成であかを考慮する必要があり、継続利用割引は自動的に適用されるためその条件を理解する必要があります。[^2]
[^2]:該当するリソースを請求月の4分の1以上使用すると、そのリソースを継続して使用する1時間ごとに継続利用割引が自動的に適用されます。

## コスト最適化の方法
Kubernetes のコスト最適化の方法は Google Cloud の公式ドキュメント「[コストが最適化された Kubernetes アプリケーションを GKE で実行するためのベスト プラクティス](https://cloud.google.com/architecture/best-practices-for-running-cost-effective-kubernetes-applications-on-gke?hl=ja)」にまとまっていますが、ここでは上記のゴールデンシグナルに関わる Kubernetes の機能を取り上げます。

### Vertical Pod Autoscaler
[Vertical Pod Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler) は Kubernetes のオートスケーラーの一つで、、[リソース制限の設定](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits)を使用状況に応じて自動的に設定し、各ポッドで最適なリソース量が利用できるようにスケジューリングする機能です。


### Cluster Autoscaler
[Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/0c3e9d15d183ffa90e9d03ac79c51db22c68a792/cluster-autoscaler) はその名の通り Kubernetes クラスターのサイズを自動的に調整する機能です。リソース不足が原因で機動に失敗したポッドや十分に活用されていないノードを特定することで、クラスターのノードを自動的にスケールアウト/インすることができます。

## おわりに
Kubenetes のコスト最適化方法にはさまざまなベストプラクティスがありますが、コスト最適化を行うためにはまず初めにシステムに関わる全ての人が基本的な概念を理解することが重要となります。

Kubernetes コスト最適化のゴールデンシグナルは、数ある指標の中から重要となる要素を限定して定義することで、その最適化方法と管理者を明確にしてコスト最適化を実現するための重要な指標です。

Kubernetes のコスト最適化を行う際に何から始めれば良いかわからないという場合、ゴールデンシグナルの測定から始めてみてはいかがでしょうか🐶