この文章は、WavefrontでHorizontal Pod Autoscaler シリーズの第二回目です。
シリーズ
第一回 : 概要編
第二回 : Wavefrontの情報からスケールする ← いまここ
第三回 : サーバーレスもどきを実装する
始めに
概要にも記載したよう、この記事では、Wavefrontのメトリクスをもとに、HPAを実装する方法を紹介します。
今回はまずシンプルにCPUベースでのHPAを実装します。
前提知識
前提知識として、HPAとしてKuberenetesの利用できるAPIとしては3つあります。
-
metrics.k8s.io
: Coreとよばれるメトリクスである、マニュアルにあるよう、CPUとMemoryの使用率を報告します。実際の収集方法はmetrics-serverもしくは Heapster経由で取得します。なお、それらはKubernetesのデフォルトで動いているわけではなく、別途起動しないといけないものです。 -
custom.metrics.k8s.io
: 上とは別に外部データソースからメトリクスを収集してメトリクスに反映するものです。ここに一部実装可能なものが紹介されています。CNCF的にはPrometheusが推奨されています。 -
external.metrics.k8s.io
: これも外部データソースからメトリクスですが、さらに自由度の高い定義ができるようになっています。
このうち、Wavefrontでは、2と3の方法をサポートしています。
2で使えるメトリクス一覧は以下の定義されています。
これが実際のどのWavefrontのメトリクスとマッピングされるかはあとで、触れます。
3の方法では、Annotationを使い好きなメトリクスをマッピングさせることもできます。
準備編
さて検証を始める前に以下が必要です。
- WavefrontのアカウントとAPIキー
- Kubernetes環境
- Helm(v3がおすすめ) cli
なお、Wavefrontのアカウントないよ、という場合ですが、Trialの申し込みをお勧めします。
もし、それも面倒な場合、非常に多くの制約をもちますが、サインアップ不要のFreemiumアカウントもあるにはあります。
現状WavafrontのFreemiumアカウントはSpring Boot経由でないと、作成ができないようになっています。最低限、ここで紹介したようにHelloWorldアプリを作成してください。作成すると~/.wavefront_freemium
にAPIキーが含まれます。
インストール
まずは、Wavefrontのコンポーネントをインストールします。
インストールするのは、以下の2つです。
- Wavefront Collector
- Wavefront HPA Adaptor
どちらでも使うので、以下のmyvalues.yaml
を用意します。
XXXXには取得したWavefrontのアカウントとAPIキーを指定します。またClusterName
は判別しやすい任意の名前をつけてください。
clusterName: mhoshi-test
wavefront:
url: https://XXXXX.wavefront.com
token: XXXXXXXXXXXXXXX
さらに、HelmのRepositoryをダウンロードします。
helm repo add wavefront https://wavefronthq.github.io/helm/
helm repo update
Wavefront Collectorのインストール
以下の手順でインストールします。
kubectl create namespace wavefront
helm install -f myvalues.yaml wavefront wavefront/wavefront --namespace wavefront
Wavefront HPA Adapterのインストール
以下の手順でインストールします。
kubectl create namespace wavefront-adapter
helm install -f myvalues.yaml wavefront-adapter wavefront/wavefront-hpa-adapter --namespace wavefront-adapter
以上でインストールの完了です。
CPU情報でスケールしてみる
では、HPAを早速ためしてみます。
まず作業用のネームスペースを作成します。
kubectl create ns hpa
なんでもいいのでKubernetesのDeploymentを作成します。
筆者の場合は手っ取り早く以下で作ります。
kubectl create deployment --image=nginx hpa-pods -n hpa
次に、HPAの定義を作ります。
cat <<EOF | kubectl apply -n hpa -f -
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: example-hpa-custom-metrics
spec:
minReplicas: 1
maxReplicas: 5
metrics:
- type: Pods
pods:
metricName: cpu.usage_rate
targetAverageValue: 300m
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hpa-pods
EOF
これは、最小1、最大5Podまでを定義したHPAです。
そして、targetAverageValue: 300m
にあるよう、300millisecondのCPU使用率に落ち着くことを期待しています。
HPAができたことを確認します。なお、直後はTARGETS
がunknown
になっているかもしれないですが、これはメトリクスがまだWavefrontに届いていない場合で、すこしまてば、値が取得されます。
kubectl get hpa -n hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
example-hpa-custom-metrics Deployment/hpa-pods <unknown>/300m 1 5 0 8s
しばらくすると、TARGETS
に値が入るはずです。
kubectl get hpa -n hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
example-hpa-custom-metrics Deployment/hpa-pods 0/300m 1 5 1 6m20s
CPU負荷をあげていきます。
手っ取り早い方法がContainerに入って、無限ループをつくってしまう方法です。
kubectl exec -it `kubectl get pods -l app=hpa-pods -n hpa -o name` -n hpa bash
Containerログイン後、以下のコマンドを実行します。以下のコマンドは何もしない無限ループを1つ作ります。理論的には、このコマンドによって1つのvCPU使用率を100%にします。
while true ; do : ; done &
WavefrontのUIを開きます。
Metrics Viewerを開いて、以下の式を入力します。ClusterNameはそれぞれ指定したものを記載してください。
ts("kubernetes.pod.cpu.usage_rate", pod_name="hpa-*" and namespace_name="hpa")
これは、namepsace名hpaのpod名hpa-*
の全てのCPU使用率を算出しています。
すると以下のようにCPU使用率があがっていることがわかります。
現在設定上はCPU使用率300mを超えた場合で、スケリーングを開始するようにしています。
しばらく放置すると、pod数が5に変動します。
% kubectl get hpa -n hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
example-hpa-custom-metrics Deployment/hpa-pods 219200m/300m 1 5 5 19m
% kubectl get po -n hpa
NAME READY STATUS RESTARTS AGE
hpa-pods-8d86f4dc5-2xn52 1/1 Running 0 8m46s
hpa-pods-8d86f4dc5-7wnpw 1/1 Running 0 8m46s
hpa-pods-8d86f4dc5-qbdn9 1/1 Running 0 7m12s
hpa-pods-8d86f4dc5-r55hb 1/1 Running 0 8m46s
hpa-pods-8d86f4dc5-wgc8g 1/1 Running 0 20m
また、CPUをぶん回したPodを止めるには以下を実行します。
kubectl delete po hpa-pods-8d86f4dc5-wgc8g -n hpa
しばらくすると、Podがまた1で落ち着きます。
kubectl get hpa -n hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
example-hpa-custom-metrics Deployment/hpa-pods 0/300m 1 5 1 35m
どうやってメトリクスは計算されている?
これについては、コードがみるのが早いです。
まず、WavefrontへのQueryを担っているのが以下の部分です。
この中でCodeのコメントアウト行にもコメントされていますが、HPAの定義をもとに以下に変換されます。
// if Prefix=kubernetes, metric='cpu.usage_rate', resType='pod', namespace='default' and names=['pod1', 'pod2']
// ts(kubernetes.pod.cpu.usage_rate, (pod_name="pod1" or pod_name="pod2") and (namespace_name="default"))
query := fmt.Sprintf("ts(%s.%s.%s%s)", t.prefix, resType, metric, filters)
つまり、HPAを以下のように定義した場合、
spec:
...
metrics:
- type: Pods
pods:
metricName: cpu.usage_rate
targetAverageValue: 300m
Wavefrontへは<prefix>.<type>.<metricName>
のメトリクスを探しにいきます。
この場合
-
<prefix>
は起動オプションでkubernetes
がデフォルト -
<type>
はHPAの定義のtype: Pods
からpod
に変換 -
<metricName>
はHPA定義のmetricName: cpu.usage_rate
からcpu.usage_rate
つまり、kubernetes.pod.cpu.usage_rate
を参照し、pod名やNamespaceを絞り込んでいくようになっています。
より標準の実装方法は、こちらにも詳しく記載されています。
まとめ
- Wavefrontでは、
custom.metrics.k8s.io
とexternal.metrics.k8s.io
をつかってHPAができる -
custom.metrics.k8s.io
で使える一覧はhttps://github.com/wavefrontHQ/wavefront-kubernetes-adapter/blob/master/docs/metrics.mdにある -
custom.metrics.k8s.io
では、定義してHPAの情報を解釈してWavefrontへのメトリクスに変換して問い合わせる
この回では、Wavefrontの統計にやってくるCPU情報をもとにHPAを実装しました。
次回の「サーバーレスもどきを実装する」ではより突飛なメトリクスを元にHPAを実装してみます。