はじめに
Horizontal Pod Autoscalerは、CPU負荷などに応じてreplication controller/deployment/replica set /stateful setのreplica数をスケールさせる(増やす)機能です。
今回はこのHorizontal Pod Autoscalerの動作を確認したいと思います。
(参考)スケールアウトとスケールアップ
サーバーの性能を上げる場合、大きく分けてスケールアウトとスケールアップ2つの方式があります。
スケールアウト
スケールアウトは「横に広げる」と言ったりもします。一般的にはサーバーの台数を増やすことで負荷を分散し、システムとして「スループット」を上げます。
スループットとは、一定時間内にどれだけプロセスを処理できるかです。
Horizontal Pod Autoscalerは、スケールアウトする機能です。
スケールアップ
スケールアップは「縦に伸ばす」と言ったりもします。一般的にはCPUを高性能なもの(周波数が高いもの)にすることで「レスポンス」を上げます。
レスポンスとは、1つのプロセスをどれだけ速く処理できるかです。
前提条件
Horizontal Pod Autoscalerを使用するには、事前にmetrics-serverをデプロイする必要があります。
metrics-server monitoring needs to be deployed in the cluster to provide metrics via the resource metrics API, as Horizontal Pod Autoscaler uses this API to collect metrics.
metrics-serverの構築はこちらでも紹介してますので、ご参照ください。
Kubernetesのmetrics-serverを構築する
Deployment/Serviceの作成
まずはDeploymentと、外部と接続するためのServiceとしてここではLoadBalancerを作成します。
以下のマニフェストをapplyします。
apiVersion: v1
kind: Service
metadata:
name: load-balancer
spec:
ports:
- name: load-balancer
port: 8080
protocol: TCP
targetPort: 80
nodePort: 30002
selector:
app: nginx-dep
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
limits:
cpu: 300m
$ kubectl apply -f nginx-hpa.yaml
service/load-balancer created
deployment.apps/nginx created
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 93d
load-balancer LoadBalancer 10.97.254.155 10.20.30.150 8080:30002/TCP 26s
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-65585fc7c9-fb92v 1/1 Running 0 31s
Horizontal Pod Autoscalerの作成
上記で作成したDeploymentに対して、以下のHorizontal Pod Autoscalerを作成します。今回はスケールしやすいように、しきい値を低め(25%)にしました。
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 25
$ kubectl apply -f hpa.yaml
horizontalpodautoscaler.autoscaling/nginx-hpa created
$ kubectl get horizontalpodautoscalers.autoscaling
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-hpa Deployment/nginx 0%/25% 1 10 1 59s
ちなみに、Deploymentにはlimits/requestsの設定が必要になります。
もし、設定していない場合は以下のようにTARGETSの値が<unknown>となって、負荷が上がってもスケールしませんのでご注意ください。
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-hpa Deployment/nginx <unknown>/25% 2 10 2 12m
$ kubectl describe horizontalpodautoscalers.autoscaling nginx-hpa
Name: nginx-hpa
・・・
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedComputeMetricsReplicas 18m (x12 over 21m) horizontal-pod-autoscaler invalid metrics (1 invalid out of 1), first error is: failed to get cpu utilization: missing request for cpu
Warning FailedGetResourceMetric 72s (x81 over 21m) horizontal-pod-autoscaler missing request for cpu
動作確認
では、実際に負荷をかけてスケールするか確認します。
外部からLoadBalancerを経由してコンテナにHTTPのリクエストを無限に送ります。DoS攻撃ですね。。。
[client]$ while true; do curl -s http://10.20.30.150:8080 > /dev/null ;done
このときの負荷の状況とスケールする様子を別ターミナルで確認します。
$ kubectl get horizontalpodautoscalers.autoscaling -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-hpa Deployment/nginx 0%/25% 1 10 1 2m52s
nginx-hpa Deployment/nginx 44%/25% 1 10 1 3m33s
nginx-hpa Deployment/nginx 44%/25% 1 10 2 3m48s
nginx-hpa Deployment/nginx 40%/25% 1 10 2 4m34s
nginx-hpa Deployment/nginx 40%/25% 1 10 4 4m49s
nginx-hpa Deployment/nginx 19%/25% 1 10 4 5m34s
nginx-hpa Deployment/nginx 18%/25% 1 10 4 6m35s
nginx-hpa Deployment/nginx 0%/25% 1 10 4 7m36s
nginx-hpa Deployment/nginx 0%/25% 1 10 4 11m
nginx-hpa Deployment/nginx 0%/25% 1 10 3 11m
nginx-hpa Deployment/nginx 0%/25% 1 10 3 12m
nginx-hpa Deployment/nginx 0%/25% 1 10 1 12m
CPU負荷がしきい値の25%を超えたら、replicaを増やして負荷を分散させていることがわかりますね。
負荷をかける側のリソースが足らないため、4つまでしかスケールはしていません。
今回は1Pod/1コンテナですが、複数コンテナがある場合には、Pod内の全てのコンテナの平均値が対象になります。
負荷を止めるとreplicaも減って、最終的には1に戻っています。
Podの増減の様子も別ターミナルで確認しました。
分かりづらいですが、負荷に応じてPodがデプロイされて、負荷を止めると削除されていることがわかります。
$ kubectl get pod -w
NAME READY STATUS RESTARTS AGE
nginx-65585fc7c9-w8p92 1/1 Running 1 7h7m
nginx-65585fc7c9-fh6vm 0/1 Pending 0 0s
nginx-65585fc7c9-fh6vm 0/1 Pending 0 0s
nginx-65585fc7c9-fh6vm 0/1 ContainerCreating 0 0s
nginx-65585fc7c9-fh6vm 0/1 ContainerCreating 0 1s
nginx-65585fc7c9-fh6vm 1/1 Running 0 6s
nginx-65585fc7c9-xbb9n 0/1 Pending 0 0s
nginx-65585fc7c9-xbb9n 0/1 Pending 0 0s
nginx-65585fc7c9-c56nb 0/1 Pending 0 0s
nginx-65585fc7c9-c56nb 0/1 Pending 0 0s
nginx-65585fc7c9-xbb9n 0/1 ContainerCreating 0 0s
nginx-65585fc7c9-c56nb 0/1 ContainerCreating 0 0s
nginx-65585fc7c9-c56nb 0/1 ContainerCreating 0 1s
nginx-65585fc7c9-xbb9n 0/1 ContainerCreating 0 1s
nginx-65585fc7c9-xbb9n 1/1 Running 0 5s
nginx-65585fc7c9-c56nb 1/1 Running 0 6s
nginx-65585fc7c9-c56nb 1/1 Terminating 0 6m50s
nginx-65585fc7c9-c56nb 0/1 Terminating 0 6m51s
nginx-65585fc7c9-c56nb 0/1 Terminating 0 6m52s
nginx-65585fc7c9-c56nb 0/1 Terminating 0 6m52s
nginx-65585fc7c9-fh6vm 1/1 Terminating 0 8m52s
nginx-65585fc7c9-xbb9n 1/1 Terminating 0 7m51s
nginx-65585fc7c9-fh6vm 0/1 Terminating 0 8m53s
nginx-65585fc7c9-xbb9n 0/1 Terminating 0 7m52s
nginx-65585fc7c9-xbb9n 0/1 Terminating 0 7m53s
nginx-65585fc7c9-xbb9n 0/1 Terminating 0 7m53s
nginx-65585fc7c9-fh6vm 0/1 Terminating 0 8m54s
nginx-65585fc7c9-fh6vm 0/1 Terminating 0 8m54s
Horizontal Pod Autoscalerの動作について
マニュアルを確認しましたので、以下に整理します。英語のマニュアルですので、間違ってたらすみません。
監視間隔
horizontal-pod-autoscaler-sync-periodによって、15秒間隔で監視されています。
replica数の決定
必要なreplica数は、設定値と現在のメトリクス値の比から、以下の式で決まります。
必要なreplica数=ceil[現在のreplica数 * ( 現在のメトリクス値 / 設定値 )]
※ceil:切り上げ
スケーリングの対象
APIバージョンが現行の安定板であるautoscaling/v1の場合、CPUのみがサポートされています。
ベータ版のautoscaling/v2beta2の場合、メモリやカスタムメトリクスもサポートされています。
まとめ
今回はHorizontal Pod Autoscalerについて確認しました。
スケールアウトはWebサービスなどの比較的軽い業務を大量に処理するシステムに向いています。Kubernetesのマイクロサービスと相性が良い拡張方法ですね。
マニュアルを読むとAPIバージョンがautoscaling/v2beta2からautoscaling/v1へ変わると、機能や動作が異なるようです。マニフェストの書き方も少し変わっていました。オープンソースは変化が早いので、常に最新情報をチェックしないといけないですね。