はじめに
Kubernetes のオートスケーリングに関して、あまり動かす機会がなかったのでこの機にまとめて取り組んでみようかと思います。
Kubernetes とオートスケーリング
Kubernetes に限らず、負荷状況に応じた適切なリソース配置やインフラのコスト管理を自動的に行うために、オートスケーリングに取り組むことがあると思います。
Kubernetes では、以下のスケール手法が主に使われます。
種類 | 対象のリソース | スケールの方向 | 概要 |
---|---|---|---|
Horizontal Pod Autoscaler(HPA) | Pod | 水平方向 | 負荷の増減に対応するために Pod の数を自動的に増減する |
Vertical Pod Autoscaler(VPA) | Pod | 垂直方向 | 負荷の増減に対応するために Pod に設定されたリソースリクエストを上書きする |
Cluster Autoscaler(CA) | Node | 水平方向 | 負荷の増減に対応するためにクラスタを構成するノードの台数を調整する |
上記であげたスケール手法以外にも、Multi-dimensional Pod Autoscaler(MPA)と呼ばれる水平垂直スケールする仕組みがコミュニティで検討されていたり、Karpentar などのオートスケールに用いられるツールなどが存在しますが、本記事ではスコープ外とさせていただきます。
Walk through w/ OKE
今回は、Oracle Container Engine for Kubernetes(OKE)を用いて、上述した Kubernetes におけるオートスケーリング手法(HPA, VPA, CA)を一通り試してみます。
前提
本記事は、Kubernetes v1.29.1 にて動作確認を行いました。また、HPA, VPA で必要な metrics-server は事前に Kubernetes クラスタに対してデプロイ済みなものとします。
HPA
に基づいて進めていきます。まずは、metrics-server がデプロイされていることを確認します。
$ kubectl -n kube-system get deploy metrics-server
NAME READY UP-TO-DATE AVAILABLE AGE
metrics-server 1/1 1 1 37h
スケール対象となるサンプルワークロードをデプロイします。
kubectl -n example apply -f https://k8s.io/examples/application/php-apache.yaml
中身は以下のようになっています。(resources.requests.cpu: 200m
, resources.limits.cpu: 500m
)
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
このアプリケーションに対して、平均の CPU 使用率が 50%を維持するように Pod の数を 1~10 個の間で調整する HPA リソースを以下のように定義します。
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache-hpa
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
targetCPUUtilizationPercentage: 50
これもクラスタにデプロイしておきます。
kubectl -n example apply -f php-apache-hpa.yaml
HPA リソースを確認してみると、以下のようになっています。
$ kubectl -n example get hpa -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 0%/50% 1 10 1 87s
対象のアプリケーションに対して、別の Pod から負荷をかけていきます。
$ kubectl -n example run -it --rm load-generator --image=busybox -- /bin/sh
/ # while true; do wget -q -O- http://php-apache; done
OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!, ...
php-apache に対して、負荷がかかると HPA リソースが平均の CPU 使用率を 50%に維持するためにレプリカ数を増やしていることを確認することができます。
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 0%/50% 1 10 1 30m
php-apache-hpa Deployment/php-apache 18%/50% 1 10 1 30m
php-apache-hpa Deployment/php-apache 250%/50% 1 10 1 30m
php-apache-hpa Deployment/php-apache 249%/50% 1 10 4 31m
php-apache-hpa Deployment/php-apache 99%/50% 1 10 5 31m
php-apache-hpa Deployment/php-apache 88%/50% 1 10 5 31m
php-apache-hpa Deployment/php-apache 70%/50% 1 10 5 31m
# ... 省略 ...
VPA
に基づいて進めていきます。まずは、VPA を実施するために必要なリソースをクラスタ上に構築します。Autoscaler のソースコードをダウンロードします。
git clone https://github.com/kubernetes/autoscaler.git
次に、コード内で提供されているスクリプトを用いて必要なリソースをデプロイします。
cd autoscaler/vertical-pod-autoscaler; ./hack/vpa-up.sh
VPA で必要なリソースがデプロイされていることを確認します。
$ kubectl -n example get pods | grep -i vpa
vpa-admission-controller-548b84c8c8-vd49f 1/1 Running 0 37h
vpa-recommender-8f4b9d68c-bjk6j 1/1 Running 0 37h
vpa-updater-5c88cd9cb6-xpcs8 1/1 Running 0 37h
デプロイされている各リソースの概要は以下の通りです。
名前 | 概要 |
---|---|
Recommender | リソースの使用量をモニターし、コンテナに推奨される CPU、メモリのリクエスト値(resources.requests.cpu , resources.requests.memory )を提供する |
Updater | リソースが正しくない Pod をチェックして削除し、更新されたリクエスト値で Pod を再作成できるようにする |
Admission Plugin(Admission Controller) | 新しい Pod に正しいリソース・リクエスト値を設定する |
VPA 用のサンプルアプリケーションをデプロイします。
kubectl -n example apply -f examples/hamster.yaml
現在、垂直スケール時には、Pod の再起動が発生するため起動された Pod に割り当てられたリソース・リクエストを参照するために Pod の状態を watch しておきます。
$ kubectl -n example get pods -l app=hamster -w
NAME READY STATUS RESTARTS AGE
hamster-c6967774f-6kmz8 1/1 Running 0 9s
hamster-c6967774f-fgb8c 1/1 Running 0 9s
hamster-c6967774f-fgb8c 1/1 Running 0 75s
hamster-c6967774f-fgb8c 1/1 Terminating 0 75s
hamster-c6967774f-fgb8c 1/1 Terminating 0 75s
hamster-c6967774f-67dhv 0/1 Pending 0 0s
hamster-c6967774f-67dhv 0/1 Pending 0 0s
hamster-c6967774f-67dhv 0/1 ContainerCreating 0 0s
hamster-c6967774f-67dhv 1/1 Running 0 2s # これ
新しく作成された Pod のリソース・リクエストを参照してみます。
kubectl -n example describe pods hamster-c6967774f-67dhv
実行結果
Requests:
cpu: 587m
memory: 262144k
必要なリソース量が計算され、それに上書きされ新しく Pod が起動していることを確認することができました。
ちなみに、hamster.yaml
は以下のようになっています。
# This config creates a deployment with two pods, each requesting 100 millicores
# and trying to utilize slightly above 500 millicores (repeatedly using CPU for
# 0.5s and sleeping 0.5s).
# It also creates a corresponding Vertical Pod Autoscaler that adjusts the
# requests.
# Note that the update mode is left unset, so it defaults to "Auto" mode.
---
apiVersion: "autoscaling.k8s.io/v1"
kind: VerticalPodAutoscaler
metadata:
name: hamster-vpa
spec:
# recommenders field can be unset when using the default recommender.
# When using an alternative recommender, the alternative recommender's name
# can be specified as the following in a list.
# recommenders:
# - name: 'alternative'
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: hamster
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 50Mi
maxAllowed:
cpu: 1
memory: 500Mi
controlledResources: ["cpu", "memory"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hamster
spec:
selector:
matchLabels:
app: hamster
replicas: 2
template:
metadata:
labels:
app: hamster
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
containers:
- name: hamster
image: registry.k8s.io/ubuntu-slim:0.1
resources:
requests:
cpu: 100m
memory: 50Mi
command: ["/bin/sh"]
args:
- "-c"
- "while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done"
resourcePolicy
で記載されている通り、100 ミリコア ~ 1 コア、50Mi ~ 500Mi の間に垂直にスケールします。
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 100m
memory: 50Mi
maxAllowed:
cpu: 1
memory: 500Mi
controlledResources: ["cpu", "memory"]
Deployment の Resource Requests を参照してみると、以下のように設定されていますが CPU もメモリも意図的にリソース不足になるように設定されているみたいです。
resources:
requests:
cpu: 100m
memory: 50Mi
CA
に基づいて進めていきます。OKE クラスタからノード・プールに対してアクションをするために必要な IAM ポリシーの設定は割愛させていただきます。また、OKE クラスタは以下のようにオートスケールの対象外のノード・プールと対象のノード・プールが設定されていることを前提として進めます。
まずは、CA を実現するために必要なリソースをクラスタにデプロイします。
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
name: cluster-autoscaler
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-autoscaler
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
rules:
- apiGroups: [""]
resources: ["events", "endpoints"]
verbs: ["create", "patch"]
- apiGroups: [""]
resources: ["pods/eviction"]
verbs: ["create"]
- apiGroups: [""]
resources: ["pods/status"]
verbs: ["update"]
- apiGroups: [""]
resources: ["endpoints"]
resourceNames: ["cluster-autoscaler"]
verbs: ["get", "update"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["watch", "list", "get", "patch", "update"]
- apiGroups: [""]
resources:
- "pods"
- "services"
- "replicationcontrollers"
- "persistentvolumeclaims"
- "persistentvolumes"
verbs: ["watch", "list", "get"]
- apiGroups: ["extensions"]
resources: ["replicasets", "daemonsets"]
verbs: ["watch", "list", "get"]
- apiGroups: ["policy"]
resources: ["poddisruptionbudgets"]
verbs: ["watch", "list"]
- apiGroups: ["apps"]
resources: ["statefulsets", "replicasets", "daemonsets"]
verbs: ["watch", "list", "get"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses", "csinodes"]
verbs: ["watch", "list", "get"]
- apiGroups: ["batch", "extensions"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "patch"]
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["create"]
- apiGroups: ["coordination.k8s.io"]
resourceNames: ["cluster-autoscaler"]
resources: ["leases"]
verbs: ["get", "update"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["watch", "list"]
- apiGroups: ["storage.k8s.io"]
resources: ["csidrivers", "csistoragecapacities"]
verbs: ["watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["create","list","watch"]
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"]
verbs: ["delete", "get", "update", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-autoscaler
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-autoscaler
subjects:
- kind: ServiceAccount
name: cluster-autoscaler
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cluster-autoscaler
subjects:
- kind: ServiceAccount
name: cluster-autoscaler
namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
app: cluster-autoscaler
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '8085'
spec:
serviceAccountName: cluster-autoscaler
containers:
- image: lhr.ocir.io/oracle/oci-cluster-autoscaler:1.29.0-10
name: cluster-autoscaler
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 100m
memory: 300Mi
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=oci
- --max-node-provision-time=25m
- --nodes=1:2:ocid1.nodepool.oc1.uk-london-1.aaaaaaaaaqqfcvolpdrndsvgp4fnyly52sntduhbt7gkt5guynhezlqk2kla
- --scale-down-delay-after-add=10m
- --scale-down-unneeded-time=10m
- --unremovable-node-recheck-timeout=5m
- --balance-similar-node-groups
- --balancing-ignore-label=displayName
- --balancing-ignore-label=hostname
- --balancing-ignore-label=internal_addr
- --balancing-ignore-label=oci.oraclecloud.com/fault-domain
imagePullPolicy: "Always"
env:
- name: OKE_USE_INSTANCE_PRINCIPAL
value: "true"
- name: OCI_SDK_APPEND_USER_AGENT
value: "oci-oke-cluster-autoscaler"
ServiceAccount, ClusterRole, Role, ClusterRoleBinding, RoleBinding は置いておいて、重要なのは Deployment に設定しているパラメータ群です。とりあえずの動作確認に必要な箇所のみに絞って解説します。
まずは、イメージ名です。CA の実態は Deployment なのでデプロイするコンテナイメージを指定する必要があります。これは、OCI のリージョンと Kubernetes のバージョンによって決定されるもので、どのイメージを使えば良いかはステップ 2: Cluster Autoscaler 構成ファイルのコピーおよびカスタマイズに記載があります。
image: lhr.ocir.io/oracle/oci-cluster-autoscaler:1.29.0-10
次に、CA の対象となるノード・プールを指定します。今回は、指定のノード・プール内で負荷に応じて最大 2 台のノードがプロビジョニングされるように設定してみました。
- --nodes=1:2:ocid1.nodepool.oc1.uk-london-1.aaaaaaaaaqqfcvolpdrndsvgp4fnyly52sntduhbt7gkt5guynhezlqk2kla
変更後に、CA 用の関連リソースをデプロイします。
kubectl apply -f cluster-autoscaler.yaml
Cluster Autoscaler が正常に動作しているかどうかを確認します。
$ kubectl -n kube-system logs -f deployment.apps/cluster-autoscaler
# ... 省略 ...
I0521 06:34:08.169007 1 static_autoscaler.go:642] Starting scale down
I0521 06:34:18.182579 1 static_autoscaler.go:290] Starting main loop
I0521 06:34:18.183085 1 oci_manager.go:451] did not find node pool for reference: {AvailabilityDomain:UK-LONDON-1-AD-1 Name:10.0.10.230 CompartmentID:ocid1.compartment.oc1..aaaaaaaac5t2rwhyzq6fm6pepwdn6gc434ymir7sgvh4ac4sd5sre4altoka InstanceID:ocid1.instance.oc1.uk-london-1.anwgiljrssl65iqc2kmgxagkfepoxgts4cfq53o7n5wq7mg3fbn737h5iqcq NodePoolID:ocid1.nodepool.oc1.uk-london-1.aaaaaaaarbie6tyvecy7jgyhybjv5tbjjja2fomiexkfgobn3nasgahvhftq InstancePoolID: PrivateIPAddress:10.0.10.230 PublicIPAddress: Shape:VM.Standard.E4.Flex}
I0521 06:34:18.183443 1 oci_manager.go:451] did not find node pool for reference: {AvailabilityDomain:UK-LONDON-1-AD-1 Name:10.0.10.230 CompartmentID:ocid1.compartment.oc1..aaaaaaaac5t2rwhyzq6fm6pepwdn6gc434ymir7sgvh4ac4sd5sre4altoka InstanceID:ocid1.instance.oc1.uk-london-1.anwgiljrssl65iqc2kmgxagkfepoxgts4cfq53o7n5wq7mg3fbn737h5iqcq NodePoolID:ocid1.nodepool.oc1.uk-london-1.aaaaaaaarbie6tyvecy7jgyhybjv5tbjjja2fomiexkfgobn3nasgahvhftq InstancePoolID: PrivateIPAddress:10.0.10.230 PublicIPAddress: Shape:VM.Standard.E4.Flex}
I0521 06:34:18.183555 1 filter_out_schedulable.go:63] Filtering out schedulables
I0521 06:34:18.183569 1 filter_out_schedulable.go:120] 0 pods marked as unschedulable can be scheduled.
I0521 06:34:18.183586 1 filter_out_schedulable.go:83] No schedulable pods
I0521 06:34:18.183592 1 filter_out_daemon_sets.go:40] Filtering out daemon set pods
I0521 06:34:18.183597 1 filter_out_daemon_sets.go:49] Filtered out 0 daemon set pods, 0 unschedulable pods left
I0521 06:34:18.183643 1 static_autoscaler.go:547] No unschedulable pods
I0521 06:34:18.183671 1 static_autoscaler.go:570] Calculating unneeded nodes
I0521 06:34:18.183682 1 oci_manager.go:451] did not find node pool for reference: {AvailabilityDomain:UK-LONDON-1-AD-1 Name:10.0.10.230 CompartmentID:ocid1.compartment.oc1..aaaaaaaac5t2rwhyzq6fm6pepwdn6gc434ymir7sgvh4ac4sd5sre4altoka InstanceID:ocid1.instance.oc1.uk-london-1.anwgiljrssl65iqc2kmgxagkfepoxgts4cfq53o7n5wq7mg3fbn737h5iqcq NodePoolID:ocid1.nodepool.oc1.uk-london-1.aaaaaaaarbie6tyvecy7jgyhybjv5tbjjja2fomiexkfgobn3nasgahvhftq InstancePoolID: PrivateIPAddress:10.0.10.230 PublicIPAddress: Shape:VM.Standard.E4.Flex}
I0521 06:34:18.183719 1 pre_filtering_processor.go:57] Node 10.0.10.230 should not be processed by cluster autoscaler (no node group config)
I0521 06:34:18.183731 1 pre_filtering_processor.go:67] Skipping 10.0.10.245 - node group min size reached (current: 1, min: 1)
I0521 06:34:18.183810 1 static_autoscaler.go:617] Scale down status: lastScaleUpTime=2024-05-21 01:32:45.031796054 +0000 UTC m=-3579.148444691 lastScaleDownDeleteTime=2024-05-21 02:43:00.955313331 +0000 UTC m=+636.775072576 lastScaleDownFailTime=2024-05-21 01:32:45.031796054 +0000 UTC m=-3579.148444691 scaleDownForbidden=false scaleDownInCooldown=false
I0521 06:34:18.183893 1 static_autoscaler.go:642] Starting scale down
I0521 06:34:26.187926 1 reflector.go:800] k8s.io/client-go/informers/factory.go:159: Watch close - *v1.CSIStorageCapacity total 7 items received
I0521 06:34:26.271998 1 reflector.go:800] k8s.io/client-go/informers/factory.go:159: Watch close - *v1.Pod total 0 items received
I0521 06:34:28.196453 1 static_autoscaler.go:290] Starting main loop
I0521 06:34:28.197010 1 oci_manager.go:451] did not find node pool for reference: {AvailabilityDomain:UK-LONDON-1-AD-1 Name:10.0.10.230 CompartmentID:ocid1.compartment.oc1..aaaaaaaac5t2rwhyzq6fm6pepwdn6gc434ymir7sgvh4ac4sd5sre4altoka InstanceID:ocid1.instance.oc1.uk-london-1.anwgiljrssl65iqc2kmgxagkfepoxgts4cfq53o7n5wq7mg3fbn737h5iqcq NodePoolID:ocid1.nodepool.oc1.uk-london-1.aaaaaaaarbie6tyvecy7jgyhybjv5tbjjja2fomiexkfgobn3nasgahvhftq InstancePoolID: PrivateIPAddress:10.0.10.230 PublicIPAddress: Shape:VM.Standard.E4.Flex}
I0521 06:34:28.197290 1 oci_manager.go:451] did not find node pool for reference: {AvailabilityDomain:UK-LONDON-1-AD-1 Name:10.0.10.230 CompartmentID:ocid1.compartment.oc1..aaaaaaaac5t2rwhyzq6fm6pepwdn6gc434ymir7sgvh4ac4sd5sre4altoka InstanceID:ocid1.instance.oc1.uk-london-1.anwgiljrssl65iqc2kmgxagkfepoxgts4cfq53o7n5wq7mg3fbn737h5iqcq NodePoolID:ocid1.nodepool.oc1.uk-london-1.aaaaaaaarbie6tyvecy7jgyhybjv5tbjjja2fomiexkfgobn3nasgahvhftq InstancePoolID: PrivateIPAddress:10.0.10.230 PublicIPAddress: Shape:VM.Standard.E4.Flex}
I0521 06:34:28.197335 1 filter_out_schedulable.go:63] Filtering out schedulables
I0521 06:34:28.197359 1 filter_out_schedulable.go:120] 0 pods marked as unschedulable can be scheduled.
I0521 06:34:28.197368 1 filter_out_schedulable.go:83] No schedulable pods
I0521 06:34:28.197373 1 filter_out_daemon_sets.go:40] Filtering out daemon set pods
I0521 06:34:28.197377 1 filter_out_daemon_sets.go:49] Filtered out 0 daemon set pods, 0 unschedulable pods left
I0521 06:34:28.197449 1 static_autoscaler.go:547] No unschedulable pods
I0521 06:34:28.197471 1 static_autoscaler.go:570] Calculating unneeded nodes
I0521 06:34:28.197497 1 oci_manager.go:451] did not find node pool for reference: {AvailabilityDomain:UK-LONDON-1-AD-1 Name:10.0.10.230 CompartmentID:ocid1.compartment.oc1..aaaaaaaac5t2rwhyzq6fm6pepwdn6gc434ymir7sgvh4ac4sd5sre4altoka InstanceID:ocid1.instance.oc1.uk-london-1.anwgiljrssl65iqc2kmgxagkfepoxgts4cfq53o7n5wq7mg3fbn737h5iqcq NodePoolID:ocid1.nodepool.oc1.uk-london-1.aaaaaaaarbie6tyvecy7jgyhybjv5tbjjja2fomiexkfgobn3nasgahvhftq InstancePoolID: PrivateIPAddress:10.0.10.230 PublicIPAddress: Shape:VM.Standard.E4.Flex}
I0521 06:34:28.197510 1 pre_filtering_processor.go:57] Node 10.0.10.230 should not be processed by cluster autoscaler (no node group config)
I0521 06:34:28.197519 1 pre_filtering_processor.go:67] Skipping 10.0.10.245 - node group min size reached (current: 1, min: 1)
I0521 06:34:28.197573 1 static_autoscaler.go:617] Scale down status: lastScaleUpTime=2024-05-21 01:32:45.031796054 +0000 UTC m=-3579.148444691 lastScaleDownDeleteTime=2024-05-21 02:43:00.955313331 +0000 UTC m=+636.775072576 lastScaleDownFailTime=2024-05-21 01:32:45.031796054 +0000 UTC m=-3579.148444691 scaleDownForbidden=false scaleDownInCooldown=false
# ... 省略 ...
のようなログが継続的に出力されていれば OK です。ここから、サンプルワークロードをデプロイする前にノード数がスケールすることを確認するためにノードの状況を watch しておきます。
$ kubectl get nodes -w
NAME STATUS ROLES AGE VERSION
10.0.10.230 Ready node 14d v1.29.1
10.0.10.245 Ready node 21h v1.29.1
次に、サンプルワークロードをデプロイします。今回は 100 個のレプリカ数を持つ Nginx の Deployment とします。
kubectl -n create deployment nginx-deployment --replicas=100 --image nginx:latest
Deployment の状況を watch しておきます。
kubectl -n example get deployment nginx-deployment -w
しばらく経過すると、Pod をプロビジョニングするためにノード数が増えていることを確認できます。(OCI 内で Compute Instance のプロビジョンングが行われるため、そこそこ時間がかかります)
NAME STATUS ROLES AGE VERSION
10.0.10.230 Ready node 14d v1.29.1
10.0.10.245 Ready node 21h v1.29.1
10.0.10.245 Ready node 21h v1.29.1
10.0.10.3 NotReady <none> 0s v1.29.1
10.0.10.3 NotReady <none> 0s v1.29.1
10.0.10.3 NotReady <none> 0s v1.29.1
10.0.10.3 NotReady <none> 0s v1.29.1
10.0.10.3 NotReady <none> 2s v1.29.1
10.0.10.3 NotReady <none> 10s v1.29.1
10.0.10.3 NotReady <none> 31s v1.29.1
10.0.10.3 NotReady node 34s v1.29.1
10.0.10.230 Ready node 14d v1.29.1
10.0.10.3 NotReady node 2m3s v1.29.1
10.0.10.3 NotReady node 2m13s v1.29.1
10.0.10.3 NotReady node 2m13s v1.29.1
10.0.10.245 Ready node 21h v1.29.1
10.0.10.3 Ready node 2m34s v1.29.1
# ... 省略 ...
終わりに
細かいことはさておき Kubernetes で使われるオートスケーリングの手法について OKE を用いて試してみました。
参考