独自メトリクスによるPodの水平スケール


## はじめに

Kubernetesでは、PodのCPUとメモリ使用量を利用したHorizontalPodAutoscale(HPA)機能[^1]が提供されています。しかし、1秒間あたりのHTTPリクエスト数やキューイングされている要素数であったりと、CPUやメモリ以外の指標を利用してPodをスケールさせたいケースもあるのではないでしょうか。このようなケースに対応するため、Kubernetesでは独自メトリクスをスケール指標として利用する方法も提供されています[^2]。


## 独自メトリクスの種類

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26683/cb288f35-3871-3747-eb51-c2a59f937ef6.png)

独自メトリクスを利用する場合、API Aggregation LayerのAPIService[^3]としての登録が必要です。また、登録可能な独自メトリクスには以下の２つがあります。

-   **カスタムメトリクス:** Podやその他Kubernetes APIリソースに紐づくリソースのメトリクス登録に利用するAPIで、APIグループ名は `custom.metrics.k8s.io` として登録する
-   **外部メトリクス:** Kubernetesリソースに紐付かない外部リソースのメトリクス登録に利用するAPIで、APIグループ名は `external.metrics.k8s.io` として登録する

2020/11/24現在、APIServiceで登録するカスタム・外部メトリクスサーバ本体はKubernetesがオフィシャルで提供されていません[^4]。よって、利用するメトリクスを収集しているサービスに合わせて、DataDog[^5]やAzure[^6]といったクラウドサービスプロバイダが提供するカスタムメトリクスサーバや、OSSのカスタムメトリクスサーバ[^7][^8]を利用することになります。


## 独自メトリクスの指定方法

カスタムメトリクスは、標準のCPU/メモリのリソースメトリクスの指定と同様にHPAの `.spec.metrics` に指定します。サポートしているTypeはPodsとObjectの2つで、Podの場合はPods、それ以外の同じNamespaceにいるAPIリソースにはObjectを利用します。

> ちなみに、Kubernetes v1.19現在はHPAのデフォルトバージョンがv1となっているため、カスタムメトリクスをサポートしているv2beta2リソースの取得には、明示的なバージョン指定が必要です。

```yaml
$ kubectl get hpa.v2beta2.autoscaling test -o yaml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
...
  metrics:
  - type: Pods
    pods:
      metric:
        name: io_per_second # 利用するPodカスタムメトリクス名
      target:
        type: AverageValue # AverageValueのみ指定可能で、メトリクスのPod平均を意味する
        averageValue: "10" # しきい値
  - type: Object
    object:
      describedObject:
        apiVersion: apps/v1
        kind: Deployment
        name: test
      metric:
        name: http_request_per_seconds # 利用するその他APIリソースのカスタムメトリクス名
      target:
        type: Value # Value or AverageValueを指定可能。後者の場合、メトリクス値をPod数で割った値が使われる
        value: "10" # しきい値
```

外部メトリクスも `.spec.metrics` に指定します。 `describedObject` 以外は Objectタイプと同様です。

```yaml
...
  metrics:
  - type: External
    external:
      metric:
        name: queue_messages_ready # 利用する外部メトリクス名
      target:
        type: AverageValue  # Value or AverageValueを指定可能。後者の場合、メトリクス値をPod数で割った値が使われる
        averageValue: "30"  # しきい値
...
```

フォーマットはいずれのメトリクスもほとんど共通していますが、モノによってターゲットに指定できる値が異なることに注意してください。また、Objectの場合は同じNamespaceに所属するリソースに限定される点にも注意が必要です。


## おわりに

今回は独自メトリクスの種類とその指定方法について説明しました。次回は[Prometheus Adapterを用いて実際にカスタムメトリクスを利用する方法](https://qiita.com/Ladicle/items/5ff251b89df2f1ebb821)を説明します。


[^1]: [Horizontal Pod Autoscaler | Kubernetes](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)

[^2]: v1.6+の `autoscaling/v2beta2` よりサポート

[^3]: [Configure the Aggregation Layer | Kubernetes](https://kubernetes.io/docs/tasks/extend-kubernetes/configure-aggregation-layer/#register-apiservice-objects)

[^4]: 2020/11/24現在、OSSのPrometheusAdapterはkubernetes-sigsへの移管作業中です

[^5]: [datadog-agent/CUSTOM\_METRICS\_SERVER.md at c4f38af1897bac294d8fed6285098b14aafa6178 · DataDog/datadog-agent](https://github.com/DataDog/datadog-agent/blob/c4f38af1897bac294d8fed6285098b14aafa6178/docs/cluster-agent/CUSTOM_METRICS_SERVER.md)

[^6]: [Azure/azure-k8s-metrics-adapter: An implementation of the Kubernetes Custom Metrics API and External Metrics API for Azure Services](https://github.com/Azure/azure-k8s-metrics-adapter)

[^7]: [DirectXMan12/k8s-prometheus-adapter: An implementation of the custom.metrics.k8s.io API using Prometheus](https://github.com/directxman12/k8s-prometheus-adapter)

[^8]: [zalando-incubator/kube-metrics-adapter: General purpose metrics adapter for Kubernetes HPA metrics](https://github.com/zalando-incubator/kube-metrics-adapter)