この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
おはようございます、加藤です。CKAを受けようと思っていましたが、勉強する時間もとれず、申し込みが英語でまるで理解できなかったのでチキって辞めました。 というわけで、EKSでHorizontal Pod Autoscaling と Cluster Autoscaler を設定してみました。
説明
Horizontal Pod Autoscaling
Horizontal Pod Autoscaler - Kubernetes
Horizontal Pod Autoscaling(以降、HPA)はCPU負荷などメトリクスに応じてDeploymentに命令を送りReplica数を制御する機能です。 コンテナに与えるリソースは変えずに、同時実行を増減させます。つまり、スケールイン/アウトを行います。
Horizontal Pod Autoscaler で利用可能なメトリクスは下記があります。 1
- Resource
- CPU/メモリのリソース
- Object
- Kubernetes Objectのメトリクス(例: Ingressのhits/s)
- Pods
- Podのメトリクス(例: Podのコネクション数
- External
- Kubernetes外のメトリクス(例: LBのQPS、Cloud Pub/Subの溜まっているメッセージ数)
そして、EKSでHPAを使うには、Kubernetes Metrics Serverをインストールする必要があります。
Cluster Autoscaler
Cluster Autoscaler(以降、CA)はWorkerNodesのAutoscalingを行う機能です。この機能は現在NodeのCPU負荷などではなく、Pending状態のPodを検知してスケールアウトを行います。 EKSのWorkerNodesはAmazon EC2 Auto Scaling(以降、EC2 Auto Scaling)で構築しますが、スケーリングポリシーは設定しません。 CAからEC2 Auto Scalingに対して、希望するキャパシティを指定する事でAutoscalingを行います。
やってみた
前提
- EKS環境が構築されている
- Helmがインストールされている
Metrics Server
EKSにMetrics Serverをインストールします。
helm install stable/metrics-server --version 2.6.0 --name metrics-server --namespace kube-system
HPA
DeploymentとHorizontalPodAutoscalerのマニフェストファイルを作成してapplyします。
sample-hpa.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deployment
spec:
replicas: 3
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- image: busybox
name: sample-deployment
command: ["dd", "if=/dev/zero", "of=/dev/null"] # CPUを100%使うように
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: sample-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: sample-deployment
minReplicas: 1
maxReplicas: 30
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50
kubectl apply -f sample-hpa.yaml
メトリクスの取得状況を確認します。
kubectl get hpa -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
sample-hpa Deployment/sample-deployment <unknown>/50% 1 30 3 47s
sample-hpa Deployment/sample-deployment 199%/50% 1 30 3 90s
最初は、と表示されますが、しばらく待っているとメトリクスが表示されます。表示されたら、Ctrl+C
で抜けてください。
Pending状態になっているPodが存在するか確認します。
kubectl get po | grep Pending
もし、Nodesに十分なリソースがあり全て起動している場合は、下記の値を増やしてください。
sample-hpa.yaml
maxReplicas: 30
WorkerNodesのIAMロール
CAはWorkerNodesの上で動き、CAからEC2 Auto Scalingの制御を行います。つまりWorkerNodesのIAMロールにアクセスする権限を与える必要があります。 下記のIAMポリシーを作成して、アタッチします。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeTags",
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup"
],
"Resource": "*"
}
]
}
なお、autoscaling:DescribeTags
は--node-group-auto-discovery
でAuto Scaling Groupを自動検出する時以外は本来不要です。
autoscaler/README.md at master · kubernetes/autoscaler
CA
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/v1beta1
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", "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"]
verbs: ["watch", "list", "get"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["watch", "list", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
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"]
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["cluster-autoscaler-status"]
verbs: ["delete", "get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
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/v1beta1
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: extensions/v1beta1
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
spec:
serviceAccountName: cluster-autoscaler
containers:
- image: k8s.gcr.io/cluster-autoscaler:v1.2.2
name: cluster-autoscaler
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 100m
memory: 300Mi
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=aws
- --skip-nodes-with-local-storage=false
- --nodes=<MIN>:<MAX>:<ASG NAME>
env:
- name: AWS_REGION
value: <AWS_REGION>
volumeMounts:
- name: ssl-certs
mountPath: /etc/ssl/certs/ca-certificates.crt
readOnly: true
imagePullPolicy: "Always"
volumes:
- name: ssl-certs
hostPath:
path: "/etc/ssl/certs/ca-bundle.crt"
いくつか変更する必要があるパラメータがあります。
EC2 Auto Scalingの設定を元に設定してください。
- --nodes=<MIN>:<MAX>:<ASG NAME>
EKSが動いているリージョンを設定します。
env:
- name: AWS_REGION
value: <AWS_REGION>
applyします。
kubectl apply -f sample-ca.yaml
ログでスケールアップの計画を確認します。
kubectl logs -f deployment/cluster-autoscaler -n kube-system | grep "scale-up plan"
I0423 02:23:07.675641 1 scale_up.go:292] Final scale-up plan: [{<ASG NAME> 3->4 (max: 6)}]
I0423 02:24:21.913766 1 scale_up.go:292] Final scale-up plan: [{<ASG NAME> 4->5 (max: 6)}]
動作確認
EC2 Auto Scaling のコンソールで状態を確認してみます。
a user request explicitly set group desired capacity changing the desired capacity from 3 to 4.
ユーザーつまりCAからの要求によってdesired capacity
が変更されて、Autoscalingが発生しています。
Podの稼働状態を確認してみます。
kubectl get po
NAME READY STATUS RESTARTS AGE
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 24m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 24m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m
sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 24m
すべてのSTATUSがRunning
です。
HPAは、targetAverageUtilization
で指定したメトリクスに収まる様にAutoscalingします。今回はCPU使用率 50%に設定したので、平均使用率が50%になるまでスケールアウトし続けます。
ですが、今回は100%に張り付く様にコマンドを指定しているので、いくらスケールアウトしても平均使用率は下がりません。
MAXPODS
に達してこれ以上スケールアウトが行われなくなりました。
kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
sample-hpa Deployment/sample-deployment 116%/50% 1 30 30 25m
CAによるスケールインを確認します。立ち上げたコンテナを全て終了させます。
kubectl delete -f sample-hpa.yaml
ログでスケールインの計画を確認します。
kubectl logs -f deployment/cluster-autoscaler -n kube-system | grep "Scale-down: removing"
I0423 03:52:25.073390 1 scale_down.go:594] Scale-down: removing empty node ip-XX-X-XX-XXX.ap-northeast-1.compute.internal
I0423 03:52:25.073425 1 scale_down.go:594] Scale-down: removing empty node ip-XX-X-XX-XXX.ap-northeast-1.compute.internal
あとがき
EKSでAutoscalingってどうするのか調べる必要があり、まとめてみました。 今回は適当ですが、metrics-serverなど、namespace: kube-system で動かすようなシステムリソースは専用のNodeGroup作ったほうが良いなと思いました。 また、スケールイン周りの動きの深いところが理解しきれていないです、CA→EC2 Auto Scalingに希望キャパシティを減らす命令を出す際に、CA側でどうやって削除されるインスタンスを特定しているのかなどがわかっていないです。
調べながらのブログ化だったので間違いもあるかも知れません、ツッコミや追記した方が良い情報があれば、ぜひコメントをお願います!
参考文献
1: Kubernetes 完全ガイド 著者 青山真也 発行所 株式会社インプレス ISBN978-4-295-00480-6 C3005