概要
KubernetesでPodをオートスケーリングをしてみる。
ここではMinikube環境を利用したが、その他の環境の場合は適宜読み替えてください。
手動でスケーリングさせる方法はこちら
【KubernetesでPodをスケーリングさせる】その1 - 手動スケーリング
Nodeをスケーリングさせることもできるが、ここでは触れない。
参考:Kuberentes クラスタのオートスケール
目次
環境
- CentOS 7.6
- Minikube v1.1.1
- Kubernetes v1.14.3
関連記事
Deploymentの仕組み
KubernetesのDeploymentについて事前に理解しておくことを推奨。
Deploymentの仕組み
事前準備
metrics-serverのインストール
metrics-serverを入れないと、以下のコマンドなどが利用できず、リソースのチェックができない。
$ sudo kubectl top node
error: metrics not available yet
オートスケーリングをする際にもリソースのチェックをするため、metrics-serverが必要となる。
minikubeのaddonで用意されているので、有効化する。
$ sudo minikube addons enable metrics-server
✅ metrics-server was successfully enabled
minikubeを利用していない場合は、以下を参考に入れる。
ちなみにHeapsterはKubernetes 1.11で非推奨になったらしい。
https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-apis
Fetching metrics from Heapster is deprecated as of Kubernetes 1.11.
これでkubectl top
コマンドが利用できるようになった。
metrics-serverインストール直後ではerror: metrics not available yet
となる可能性があるので、その場合は少し待つ。
$ sudo kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
minikube 92m 1% 2276Mi 14%
# podが存在していない場合は何も返ってこない
$ sudo kubectl top pods
NAME CPU(cores) MEMORY(bytes)
http-deployment-545bd7d765-9ghmf 0m 39Mi
各種定義
Deployment
kind: Deployment
apiVersion: apps/v1
metadata:
name: http-deployment
spec:
selector:
matchLabels:
########################################################
# deploymentの.spec.selector.matchLabels.appの値と、
# 後述のservice.ymlの.spec.selector.appの値を合わせることで、
# serviceからdeploymentにリクエストを流すことが可能となる。
########################################################
app: http-app
# podの設定
# ここでは触れないが、このPodTemlateの部分に変更があったときに、ローリングアップデートが実行される
template:
metadata:
labels:
app: http-app
spec:
containers:
# Dockerコンテナ名
- name: http-container
# 利用するDockerイメージ
image: php:7.0-apache
# localイメージ利用。ただし、localに指定したイメージが存在しない場合はレポジトリを参照する
imagePullPolicy: IfNotPresent
# Podのリソース定義
resources:
# PodをDeployする際に、必要とするリソースを指定できる仕組み。枠外(*1)を参照
requests:
memory: 64Mi
cpu: 250m
# 該当のPodのリソース使用量の上限を設定することができる。枠外(*2)を参照
limits:
memory: 128Mi
cpu: 500m
ports:
# service.ymlで定義する外部公開用port設定の箇所と名前を合わせることでbindされる
# nameは15文字以内でないとエラーになる
- name: ha-inner-port
# コンテナ内のport
containerPort: 80
# mountするディレクトリ:コンテナ側の設定
volumeMounts:
- name: documentroot
mountPath: /var/www/html
# mountするディレクトリ:ホストOS側の設定
volumes:
- name: documentroot
hostPath:
path: /home/username/containers/web/html
(*1)Resource Requestsとは
- PodをDeployする際に、必要とするリソースを指定できる仕組み
- Podの利用上限リソースを定義するものではない(そちらはResource Limitを利用する)
- 指定したリソースが確保されるわけではなく、PodをDeployする際に必要なリソースがあるか確認し、不足していればDeployされない
- nodeのリソースはチェックせず、Resource Requestsで指定したリソースしか見ないので、nodeのリソースが不足していてもDeployしようとする。その際は、該当のPodはPending状態となる
(*2)Resource Limitsとは
- 該当のPodのリソース使用量の上限を設定することができる
- nodeのリソースに空きがあっても、該当のPodではResource Limitsの内容で制限される
- nodeのリソース上限を超えた設定ができる
- CPUの場合、処理遅延が起きるだけで、特に問題はない
- メモリの場合、コンテナのプロセスがKillされる
- Podの設定で、
restart policy
がAlways、もしくはOnFailure
が設定されていた場合は、コンテナは自動で再起動される - PodのStatusが
CrashLoopBackOff
になっている場合は、コンテナ再起動が繰り返されている可能性があるので要注意。PodのRESTARTSで再起動回数が分かる
- Podの設定で、
- Resource Limitsを指定しない場合、リソース上限は無制限となる
参考:KubernetesのResource RequestsとResource Limitsについて
Service
kind: Service
apiVersion: v1
metadata:
# service名
name: http-service
spec:
selector:
########################################################
# 前述のdeploymentの.spec.selector.matchLabels.appの値と、
# service.ymlの.spec.selector.appの値を合わせることで、
# serviceからdeploymentにリクエストを流すことが可能となる。
########################################################
app: http-app
ports:
- name: ha-outer-port
# 外部公開するport
port: 8080
# deployment.ymlで定義したport名と合わせることでbindされる
targetPort: ha-inner-port
type: NodePort
HorizontalPodAutoscaler
オートスケーリングの定義をする。
2019/06現在、apiVersionの最新はautoscaling/v1
だが、autoscaling/v2beta1
と書式が異なるので、両方書いておく。
参考:API version
2018/5/9時点ではCPU使用率のautoscalingのみがstableとなっていてautoscaling/v1で提供されています。メモリ使用率によるスケールやカスタムメトリクスでのスケールはautoscaling/v2beta1で提供されています。autoscaling/v2 のリリース時期については現在はまだ未確定のようです。
autoscaling/v2beta1
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: http-autoscaling
namespace: default
spec:
# オートスケーリング対象を定義
scaleTargetRef:
kind: Deployment
apiVersion: apps/v1
# 対象のdeployment名を定義する
name: http-deployment
# 最小レプリカ数
minReplicas: 1
# 最大レプリカ数
maxReplicas: 5
# スケーリングをする条件
metrics:
- type: Resource
resource:
name: cpu
# CPU使用率が常に10%になるように指定。超えたらオートスケーリングする。
targetAverageUtilization: 10
autoscaling/v1
CPU使用率の定義方法が異なる。
v1
ではmetrics
は利用できないため、v2beta1
の書式でcreateを実行すると、以下のエラーが出る。
$ sudo kubectl create -f autoscaling.yml
error: error validating "autoscaling.yml": error validating data: ValidationError(HorizontalPodAutoscaler.spec): unknown field "metrics" in io.k8s.api.autoscaling.v1.HorizontalPodAutoscalerSpec; if you choose to ignore these errors, turn validation off with --validate=false
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: http-autoscaling
namespace: default
spec:
# オートスケーリング対象を定義
scaleTargetRef:
kind: Deployment
apiVersion: apps/v1
# 対象のdeployment名を定義する
name: http-deployment
# 最小レプリカ数
minReplicas: 1
# 最大レプリカ数
maxReplicas: 5
# スケーリングをする条件
# すべてのPodの平均CPU使用率の目標値(%の値を設定する)
targetCPUUtilizationPercentage: 10
その他のAPI Resource(kind)については以下を参照
作成
$ sudo kubectl create -f deployment.yml -f service.yml -f autoscaling.yml
deployment.extensions/http-deployment created
service/http-service created
horizontalpodautoscaler.autoscaling/http-autoscaling created
確認
作成されたことを確認。
$ sudo kubectl get all
NAME READY STATUS RESTARTS AGE
pod/http-deployment-545bd7d765-hmqnh 1/1 Running 0 4s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/http-service NodePort 10.108.236.223 <none> 8080:31212/TCP 4s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 31h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/http-deployment 1/1 1 1 4s
NAME DESIRED CURRENT READY AGE
replicaset.apps/http-deployment-545bd7d765 1 1 1 4s
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/http-autoscaling Deployment/http-deployment <unknown>/10% 1 5 0 4s
負荷のかかるプログラムを作成
以下のPHPプログラムを実行して負荷をかけ、オートスケーリングをさせる。
deployment.ymlのvolumesで定義した、コンテナにマウントした領域に設置する。
<?php
$max = 1*1000*1000*1000;
$x = 0;
for ($i=0; $i<=$max; $i++) {
$x += $i;
}
echo $x . "\n";
echo "done\n";
負荷のかかるプログラムを実行
実行前にPodの数を確認。Podは1つしかない。
$ sudo kubectl get pod
NAME READY STATUS RESTARTS AGE
http-deployment-545bd7d765-hmqnh 1/1 Running 0 18s
プログラムを実行する。
$ curl $(sudo minikube service http-service --url)/autoscaling.php
500000000500000000
done
プログラムを実行後の状況を確認
autoscaling.ymlで定義した、最大レプリカ数 maxReplicas: 5
の通り、Podの数が5つになった。
リソースのチェックは30秒ごとに行っているらしいので、スケールアウトされるまでは少しタイムラグがある。
$ sudo kubectl get pod
NAME READY STATUS RESTARTS AGE
http-deployment-545bd7d765-9wlg7 1/1 Running 0 77s
http-deployment-545bd7d765-bcgqs 1/1 Running 0 77s
http-deployment-545bd7d765-cgnn2 1/1 Running 0 77s
http-deployment-545bd7d765-hmqnh 1/1 Running 0 3m19s
http-deployment-545bd7d765-ww2h2 1/1 Running 0 62s
プログラムが停止後、しばらくしたらPodの数が最小レプリカ数 minReplicas: 1
の通り、Podが1つに戻った。
$ sudo kubectl get pod
NNAME READY STATUS RESTARTS AGE
http-deployment-545bd7d765-hmqnh 1/1 Running 0 11m
オートスケーリングのアルゴリズムについては以下を参照
TargetNumOfPods = ceil(sum(CurrentPodsCPUUtilization) / Target)