昼夜で稼働台数を調整できるCronHPA Operatorを作りました!
CronHPAという昼夜のような時間帯で稼働台数やメトリクスを調整できるKubernetes Operatorを作ったので紹介します。
私が働いているUbie株式会社ではtoC向けの受診相談サービスをKubernetesで運用して提供しています。
toC向けのサービスを運用する場合、負荷に合わせてオートスケールする仕組みを入れるのが一般的でKubernetesではHPAというリソースがその役割を担っています。
以下のようなYAMLの記述で最低稼働Pod数4、最大稼働数10でPod全体の平均CPUが50%以下になるように自動でPod数を調整してくれます。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: nginx
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 4
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
非常に簡単に設定できて便利なのですが、toC向けのプロダクトだと夜間はそこまでトラフィックが多くないので、稼働数を減らしたり、スケールする速度を緩めたりして、コスト削減をしたい時もあります。
これに対して単純に最低稼働数やメトリクスを夜のトラフィックの少ない方に合わせてしまうと減らしてしまうと昼間に確保したい最低稼働台数を担保できません。
また、カスタムメトリクスを使って、昼間にPod数が4以下だとメトリクスの数値に下駄を履かせるなどトリッキーな方法で対応できるかもしれないですが、単純に時間帯でコントロールしたいだけの時に複雑なメトリクスを作るのは割に合いません。
これを実現するため、インターネットで既存のソリューションを探してみるとCronHPAというCRDを見つけました。
apiVersion: extensions.tkestack.io/v1
kind: CronHPA
metadata:
name: example-cron-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-deployment
crons:
- schedule: "0 23 * * 5" // Set replicas to 60 every Friday 23:00
targetReplicas: 60
- schedule: "0 23 * * 7" // Set replicas to 30 every Sunday 23:00
targetReplicas: 30
しかし、このCRDだとスケジュールに応じて稼働数を変えるだけで、元々のHPAの良さであるメトリクスに応じて稼働台数を調整する機能が失われてしまっています。
そのため、オリジナルのCronHPAというCRDのOperatorを作りました!
CronHPAでは以下のYAMLで上記の昼夜のPod稼働数のコントロールができます。
apiVersion: cron-hpa.dtaniwaki.github.com/v1alpha1
kind: CronHorizontalPodAutoscaler
metadata:
name: nginx
spec:
template:
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 4
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
scheduledPatches:
- name: daytime
schedule: "0 8 * * *"
timezone: "Asia/Tokyo"
- name: nighttime
schedule: "0 22 * * *"
timezone: "Asia/Tokyo"
patch:
minReplicas: 2 # 最低稼働数を減らす。
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # 簡単にスケールしないよう保守的なメトリクスにする。
このYAMLの場合、昼(daytime)は最低稼働数4、最大稼働数10でCPU平均50%のメトリクスでスケールしますが、夜(nighttime)は最低稼働数1、最大稼働数10でCPU平均70%のメトリクスでスケールするようにHPAを調整するようになっています。
(実際のPodの増減はこのOperatorでなくHPAが行います!)
昼は急なトラフィックに備えて負荷が低くても4 Podは最低稼働させておき、急なトラフィックでCPU使用率が高くなった時にできるだけ早くスケールをさせる一方で、夜は急なトラフィックがない想定で1 Podのみ稼働させておき多少のトラフィックの増加ではスケールしないようになります。
一方で最大稼働数は夜でも10なので、万一本当に夜に利用者が定常的に増えた場合でも対応はできるようになっています。
まだ作ったばかりで動作が安定していないところもありますが、実現したいことやコンセプトへのフィードバックなどあればぜひ教えてください!