Kubernetes/EKS Study

[5주차] EKS Autoscaling

백곰곰 2023. 5. 24. 22:59
728x90
반응형

이번 주는 EKS를 조금 더 유연하게 사용할 수 있는 scaling 방법에 대해 알아보았습니다.

EKS에서 scaling 대상은 node와 pod가 있습니다. 각각 어떤 솔루션이 있는지 살펴보겠습니다.

실습 시 제일 하단에 있는 '사전 설치 툴'을 설치한 뒤 진행이 필요합니다.

Node

Cluster Autoscaler

- metric server에서 제공하는 metric을 기반으로 노드그룹의 ASG 수를 조정합니다.

- pending 상태인 pod가 생기면 노드 수를 늘리고 사용량이 낮다면 노드 수를 줄입니다.

 

Cluster Autoscaler 설치

설치 전에 먼저 nodegroup의 ASG 최대값을 조정합니다.

bash
$ export ASG_NAME=$(aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='myeks']].AutoScalingGroupName" --output text) $ aws autoscaling update-auto-scaling-group --auto-scaling-group-name ${ASG_NAME} --min-size 3 --desired-capacity 3 --max-size 4 $ aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='myeks']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" --output table ----------------------------------------------------------------- | DescribeAutoScalingGroups | +------------------------------------------------+----+----+----+ | eks-ng1-bcc426b3-fc49-263c-9632-9f264a271b6d | 3 | 3 | 4 | +------------------------------------------------+----+----+----+

이제 Cluster Autoscaler를 설치해보겠습니다.

bash
$ curl -s -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml $ sed -i "s/<YOUR CLUSTER NAME>/$CLUSTER_NAME/g" cluster-autoscaler-autodiscover.yaml $ kubectl apply -f cluster-autoscaler-autodiscover.yaml serviceaccount/cluster-autoscaler created clusterrole.rbac.authorization.k8s.io/cluster-autoscaler created role.rbac.authorization.k8s.io/cluster-autoscaler created clusterrolebinding.rbac.authorization.k8s.io/cluster-autoscaler created rolebinding.rbac.authorization.k8s.io/cluster-autoscaler created deployment.apps/cluster-autoscaler created

Cluster Autoscaler의 정상 동작 여부는 Over-provisioning을 설정하며 확인해보겠습니다.

 

Over-provisioning

- Cluster Autoscaler를 사용할 때 노드가 생성되는 시간이 있어 신규 pod는 pending 상태에 머물게 됩니다. 이때 더 빠르게 pod 배포가 필요할 때 미리 노드를 띄워두는 방법을 사용할 수 있습니다.

- PriorityClass 라는 객체를 활용해서 pod에 우선순위를 정하고 우선순위가 낮은 pod를 미리 만들어 노드를 확보하는 방식입니다.

- 실제 리소스가 부족할 때 우선 순위가 낮은 pod가 evict되고 우선 순위가 높은 pod가 배포됩니다.

 

Over-provisioning 실습

먼저 우선순위가 낮은 PriorityClass와 deployment를 배포합니다.

Cluster Autoscaler의 동작도 확인하기 위해 pod가 노드의 메모리를 많이 차지할 수 있게 설정했습니다.

bash
$ cat <<EOT > low-priority-class.yaml apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: pause-pods value: -1 globalDefault: false description: "Priority class used by pause-pods for overprovisioning." EOT $ kubectl apply -f low-priority-class.yaml $ cat <<EOT > low-priority-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: pause-pods spec: replicas: 3 selector: matchLabels: run: pause-pods template: metadata: labels: run: pause-pods spec: priorityClassName: pause-pods containers: - name: reserve-resources image: registry.k8s.io/pause resources: requests: memory: "3Gi" ## 사용 중인 nodegroup ec2 스펙에 맞게 조정 EOT $ kubectl apply -f low-priority-deployment.yaml

pod를 배포한 후 노드의 자원이 부족한 것을 확인할 수 있습니다.

bash
$ kubectl get po NAME READY STATUS RESTARTS AGE pause-pods-69f8b747b4-6m5bt 1/1 Running 0 4s pause-pods-69f8b747b4-hnwpr 1/1 Running 0 4s pause-pods-69f8b747b4-szmjq 0/1 Pending 0 4s $ ./eks-node-viewer --resources cpu,memory ip-192-168-1-43.ap-northeast-2.compute.internal cpu ███████████░░░░░░░░░░░░░░░░░░░░░░░░ 32% (10 pods) t3.medium/$0.0520 On-Demand - Ready memory ██████████░░░░░░░░░░░░░░░░░░░░░░░░░ 28% ip-192-168-3-11.ap-northeast-2.compute.internal cpu ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 12% (8 pods) t3.medium/$0.0520 On-Demand - Ready memory █████████████████████████████████░░ 95% ip-192-168-2-62.ap-northeast-2.compute.internal cpu ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 6% (4 pods) t3.medium/$0.0520 On-Demand - Ready memory ████████████████████████████████░░░ 93%

시간이 조금 지나면 노드가 3개에서 4개로 증가하고 pod도 배포되는 것을 볼 수 있습니다.

bash
$ kubectl get po NAME READY STATUS RESTARTS AGE pause-pods-69f8b747b4-6m5bt 1/1 Running 0 82s pause-pods-69f8b747b4-hnwpr 1/1 Running 0 82s pause-pods-69f8b747b4-szmjq 1/1 Running 0 82s $ ./eks-node-viewer --resources cpu,memory ip-192-168-1-43.ap-northeast-2.compute.internal cpu ███████████░░░░░░░░░░░░░░░░░░░░░░░░ 32% (10 pods) t3.medium/$0.0520 On-Demand - Ready memory ██████████░░░░░░░░░░░░░░░░░░░░░░░░░ 28% ip-192-168-3-11.ap-northeast-2.compute.internal cpu ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 12% (8 pods) t3.medium/$0.0520 On-Demand - Ready memory █████████████████████████████████░░ 95% ip-192-168-2-62.ap-northeast-2.compute.internal cpu ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 6% (4 pods) t3.medium/$0.0520 On-Demand - Ready memory ████████████████████████████████░░░ 93% ip-192-168-3-244.ap-northeast-2.compute.internal cpu ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 6% (4 pods) t3.medium/$0.0520 On-Demand - Ready memory ████████████████████████████████░░░ 93%

 

그 다음 우선순위가 높은 PriorityClass와 deployment를 배포합니다.

bash
$ cat <<EOT > high-priority-class.yaml apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000 globalDefault: false description: "Priority class used for high priority Pods only." EOT $ kubectl apply -f high-priority-class.yaml $ cat <<EOT > high-priority-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 resources: requests: memory: "500Mi" ports: - containerPort: 80 priorityClassName: high-priority # Priority Class specified EOT $ kubectl apply -f high-priority-deployment.yaml

노드의 자원이 부족해지는 상황을 만들기 위해 deployment의 replica 수를 조정합니다.

이미 ASG의 최대값과 동일한 노드 수가 실행중이기 때문에 노드의 자원이 부족할 때 우선순위가 낮은 pod가 evict되는 것을 예상할 수 있습니다.

bash
$ kubectl scale deployment nginx-deployment --replicas 5 $ kubectl get po NAME READY STATUS RESTARTS AGE nginx-deployment-5c98788955-5rr2g 1/1 Running 0 19s nginx-deployment-5c98788955-pz656 1/1 Running 0 19s nginx-deployment-5c98788955-rppdv 1/1 Running 0 87s nginx-deployment-5c98788955-rq4qs 1/1 Running 0 19s nginx-deployment-5c98788955-zr8g2 1/1 Running 0 87s pause-pods-69f8b747b4-6m5bt 1/1 Running 0 4m22s pause-pods-69f8b747b4-hnwpr 1/1 Running 0 4m22s pause-pods-69f8b747b4-vtxfc 0/1 Pending 0 19s

예상과 같이 기존 우선순위가 낮은 pod가 pending 상태로 변하고 우선순위가 높은 신규 pod가 생성되는 것을 볼 수 있습니다.

Pending 상태인 pod에는 아래와 같은 메세지를 확인할 수 있습니다.

bash
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal NotTriggerScaleUp 3m50s cluster-autoscaler pod didn't trigger scale-up: 1 max node group size reached Warning FailedScheduling 21s (x4 over 3m55s) default-scheduler 0/4 nodes are available: 4 Insufficient memory. preemption: 0/4 nodes are available: 4 No preemption victims found for incoming pod.

Karpenter

- Cluster Autoscaler 보다 노드 생성 시간이 적게 걸려 최근에 많이 사용되는 autoscaler입니다.

- 다양한 노드 타입을 활용하여 현재 필요한 사용량에 맞게 비용 최적화된 노드 구성을 해줍니다.

 

Karpenter 실습

karpenter는 신규 클러스터를 생성하여 실습을 진행하겠습니다. ( vpc, ec2 등 기본 네트워크 설정 : cloudformation yaml)

bash
export | egrep 'ACCOUNT|AWS_|CLUSTER' | egrep -v 'SECRET|KEY' # 환경변수 설정 export KARPENTER_VERSION=v0.27.5 export TEMPOUT=$(mktemp) echo $KARPENTER_VERSION $CLUSTER_NAME $AWS_DEFAULT_REGION $AWS_ACCOUNT_ID $TEMPOUT # CloudFormation 스택으로 IAM Policy, Role, EC2 Instance Profile 생성 curl -fsSL https://karpenter.sh/"${KARPENTER_VERSION}"/getting-started/getting-started-with-karpenter/cloudformation.yaml > $TEMPOUT \ && aws cloudformation deploy \ --stack-name "Karpenter-${CLUSTER_NAME}" \ --template-file "${TEMPOUT}" \ --capabilities CAPABILITY_NAMED_IAM \ --parameter-overrides "ClusterName=${CLUSTER_NAME}"

클러스터 생성

bash
eksctl create cluster -f - <<EOF --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ${CLUSTER_NAME} region: ${AWS_DEFAULT_REGION} version: "1.24" tags: karpenter.sh/discovery: ${CLUSTER_NAME} iam: withOIDC: true serviceAccounts: - metadata: name: karpenter namespace: karpenter roleName: ${CLUSTER_NAME}-karpenter attachPolicyARNs: - arn:aws:iam::${AWS_ACCOUNT_ID}:policy/KarpenterControllerPolicy-${CLUSTER_NAME} roleOnly: true iamIdentityMappings: - arn: "arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME}" username: system:node:{{EC2PrivateDNSName}} groups: - system:bootstrappers - system:nodes managedNodeGroups: - instanceType: m5.large amiFamily: AmazonLinux2 name: ${CLUSTER_NAME}-ng desiredCapacity: 2 minSize: 1 maxSize: 10 iam: withAddonPolicies: externalDNS: true ## Optionally run on fargate # fargateProfiles: # - name: karpenter # selectors: # - namespace: karpenter EOF

karpenter 설치

bash
$ export CLUSTER_ENDPOINT="$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output text)" $ export KARPENTER_IAM_ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT_ID}:role/${CLUSTER_NAME}-karpenter" $ echo $CLUSTER_ENDPOINT $KARPENTER_IAM_ROLE_ARN
bash
$ helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter --version ${KARPENTER_VERSION} --namespace karpenter --create-namespace \ --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \ --set settings.aws.clusterName=${CLUSTER_NAME} \ --set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${CLUSTER_NAME} \ --set settings.aws.interruptionQueueName=${CLUSTER_NAME} \ --set controller.resources.requests.cpu=1 \ --set controller.resources.requests.memory=1Gi \ --set controller.resources.limits.cpu=1 \ --set controller.resources.limits.memory=1Gi \ --wait $ kubectl get-all -n karpenter NAME NAMESPACE AGE configmap/config-logging karpenter 37s configmap/karpenter-global-settings karpenter 37s configmap/kube-root-ca.crt karpenter 37s endpoints/karpenter karpenter 37s pod/karpenter-6c6bdb7766-5mcpn karpenter 37s pod/karpenter-6c6bdb7766-5vj2t karpenter 37s secret/karpenter-cert karpenter 37s secret/sh.helm.release.v1.karpenter.v1 karpenter 37s serviceaccount/default karpenter 37s serviceaccount/karpenter karpenter 37s service/karpenter karpenter 37s deployment.apps/karpenter karpenter 37s replicaset.apps/karpenter-6c6bdb7766 karpenter 37s lease.coordination.k8s.io/karpenter-leader-election karpenter 29s endpointslice.discovery.k8s.io/karpenter-2hjxb karpenter 37s poddisruptionbudget.policy/karpenter karpenter 37s rolebinding.rbac.authorization.k8s.io/karpenter karpenter 37s role.rbac.authorization.k8s.io/karpenter karpenter 37s

provisioner 생성

bash
$ cat <<EOF | kubectl apply -f - apiVersion: karpenter.sh/v1alpha5 kind: Provisioner metadata: name: default spec: requirements: - key: karpenter.sh/capacity-type operator: In values: ["spot"] limits: resources: cpu: 1000 providerRef: name: default ttlSecondsAfterEmpty: 30 --- apiVersion: karpenter.k8s.aws/v1alpha1 kind: AWSNodeTemplate metadata: name: default spec: subnetSelector: karpenter.sh/discovery: ${CLUSTER_NAME} securityGroupSelector: karpenter.sh/discovery: ${CLUSTER_NAME} EOF $ kubectl get awsnodetemplates,provisioners NAME AGE awsnodetemplate.karpenter.k8s.aws/default 17s NAME AGE provisioner.karpenter.sh/default 17s

이제 pod를 생성하여 karpetner로 노드가 생성되는지 확인해보겠습니다.

bash
$ cat <<EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: inflate spec: replicas: 0 selector: matchLabels: app: inflate template: metadata: labels: app: inflate spec: terminationGracePeriodSeconds: 0 containers: - name: inflate image: public.ecr.aws/eks-distro/kubernetes/pause:3.7 resources: requests: cpu: 1 EOF $ kubectl scale deployment inflate --replicas 5 $ kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller ... 2023-05-24T13:10:08.014Z DEBUG controller.provisioner.cloudprovider created launch template {"commit": "698f22f-dirty", "provisioner": "default", "launch-template-name": "karpenter.k8s.aws/3594526214815891012", "launch-template-id": "lt-0a274807620307b36"} 2023-05-24T13:10:10.717Z INFO controller.provisioner.cloudprovider launched instance {"commit": "698f22f-dirty", "provisioner": "default", "id": "i-00429eff0a28e5bd5", "hostname": "ip-192-168-109-187.ap-northeast-2.compute.internal", "instance-type": "c4.2xlarge", "zone": "ap-northeast-2c", "capacity-type": "spot", "capacity": {"cpu":"8","ephemeral-storage":"20Gi","memory":"14208Mi","pods":"58"}} 2023-05-24T13:06:45.504Z DEBUG controller discovered kube dns {"commit": "698f22f-dirty", "kube-dns-ip": "10.100.0.10"} 2023-05-24T13:06:45.504Z DEBUG controller discovered version {"commit": "698f22f-dirty", "version": "v0.27.5"} 2023/05/24 13:06:45 Registering 2 clients 2023/05/24 13:06:45 Registering 2 informer factories 2023/05/24 13:06:45 Registering 3 informers 2023/05/24 13:06:45 Registering 5 controllers 2023-05-24T13:06:45.505Z INFO controller Starting server {"commit": "698f22f-dirty", "path": "/metrics", "kind": "metrics", "addr": "[::]:8080"} 2023-05-24T13:06:45.505Z INFO controller Starting server {"commit": "698f22f-dirty", "kind": "health probe", "addr": "[::]:8081"} I0524 13:06:45.606733 1 leaderelection.go:248] attempting to acquire leader lease karpenter/karpenter-leader-election... 2023-05-24T13:06:45.628Z INFO controller Starting informers... {"commit": "698f22f-dirty"}

신규 노드가 spot 타입으로 생성된 것을 볼 수 있습니다.

bash
$ kubectl get node --label-columns=eks.amazonaws.com/capacityType,karpenter.sh/capacity-type,node.kubernetes.io/instance-type NAME STATUS ROLES AGE VERSION CAPACITYTYPE CAPACITY-TYPE INSTANCE-TYPE ip-192-168-109-187.ap-northeast-2.compute.internal Ready <none> 77s v1.24.13-eks-0a21954 spot c4.2xlarge ip-192-168-28-174.ap-northeast-2.compute.internal Ready <none> 13m v1.24.13-eks-0a21954 ON_DEMAND m5.large ip-192-168-76-145.ap-northeast-2.compute.internal Ready <none> 13m v1.24.13-eks-0a21954 ON_DEMAND m5.large

이번에는 fargate를 사용해서 pod를 띄워보겠습니다.

iam role 생성

bash
$ cat << EOF > AmazonEKSFargatePodExecutionRole-policy.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Condition": { "ArnLike": { "aws:SourceArn": "arn:aws:eks:ap-northeast-2:$AWS_ACCOUNT_ID:fargateprofile/$CLUSTER_NAME/*" } }, "Principal": { "Service": "eks-fargate-pods.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF $ aws iam create-role \ --role-name AmazonEKSFargatePodExecutionRole \ --assume-role-policy-document file://AmazonEKSFargatePodExecutionRole-policy.json $ aws iam attach-role-policy \ --policy-arn arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy \ --role-name AmazonEKSFargatePodExecutionRole

fargate profile 생성

bash
$ export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="eksctl-$CLUSTER_NAME-cluster/SubnetPrivateAPNORTHEAST2A" --query "Subnets[0].[SubnetId]" --output text) $ export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="eksctl-$CLUSTER_NAME-cluster/SubnetPrivateAPNORTHEAST2C" --query "Subnets[0].[SubnetId]" --output text) $ export PubSubnet3=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="eksctl-$CLUSTER_NAME-cluster/SubnetPrivateAPNORTHEAST2D" --query "Subnets[0].[SubnetId]" --output text) ## 테스트용 namespace 생성 $ kubectl create ns karpenter-test $ aws eks create-fargate-profile \ --fargate-profile-name karpenter-test \ --cluster-name $CLUSTER_NAME \ --pod-execution-role-arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/AmazonEKSFargatePodExecutionRole \ --subnets $PubSubnet1 $PubSubnet2 $PubSubnet3 \ --selectors namespace=karpenter-test

karpenter-test ns에 pod를 배포합니다.

bash
$ cat <<EOT > pod.yaml apiVersion: v1 kind: Pod metadata: name: nginx namespace: karpenter-test spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 EOT $ kubectl apply -f pod.yaml $ kubectl get po -n karpenter-test NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 3m17s $ kubectl describe po nginx -n karpenter-test ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning LoggingDisabled 34s fargate-scheduler Disabled logging because aws-logging configmap was not found. configmap "aws-logging" not found Normal Scheduled 1s fargate-scheduler Successfully assigned karpenter-test/nginx to fargate-ip-192-168-173-121.ap-northeast-2.compute.internal

노드를 확인해보면 fargate 노드가 생성된 것을 확인할 수 있습니다.

bash
$ kubectl get node --label-columns=eks.amazonaws.com/capacityType,karpenter.sh/capacity-type,node.kubernetes.io/instance-type NAME STATUS ROLES AGE VERSION CAPACITYTYPE CAPACITY-TYPE INSTANCE-TYPE fargate-ip-192-168-173-121.ap-northeast-2.compute.internal Ready <none> 3m54s v1.24.12-eks-f4dc2c0 ip-192-168-28-174.ap-northeast-2.compute.internal Ready <none> 53m v1.24.13-eks-0a21954 ON_DEMAND m5.large ip-192-168-76-145.ap-northeast-2.compute.internal Ready <none> 53m v1.24.13-eks-0a21954 ON_DEMAND m5.large

EKS에서 add-on으로 제공되는 coredns, LB Controller 등도 fargate에 배포가 가능합니다.

추후에 해당 실습도 진행해보도록 하겠습니다.


Pod

HPA

- metric을 기반으로 pod 수를 늘리고 줄입니다.

- Deployment, StatefulSet에 적용이 가능합니다.

 

KEDA

- metric이 아닌 이벤트 기반으로 scaling이 가능합니다.

- 특정 시간에 pod 수를 조정하는 것도 가능합니다.

VPA

- 필요에 따라 pod의 cpu, memory 스펙을 조정합니다.

- pod가 재생성되니 주의가 필요합니다. (pod evict)

 

VPA 설치

bash
$ git clone https://github.com/kubernetes/autoscaler.git $ cd ~/autoscaler/vertical-pod-autoscaler/ # openssl 버전 확인 및 업그레이드 $ openssl version $ OpenSSL 1.0.2k-fips 26 Jan 2017 $ yum install openssl11 -y $ openssl11 version OpenSSL 1.1.1g FIPS 21 Apr 2020 # 스크립트파일내에 openssl11 수정 $ sed -i 's/openssl/openssl11/g' ~/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/gencerts.sh # Vertical Pod Autoscaler 설치 $ ./hack/vpa-up.sh $ kubectl get crd | grep autoscaling verticalpodautoscalercheckpoints.autoscaling.k8s.io 2023-05-23T13:01:30Z verticalpodautoscalers.autoscaling.k8s.io 2023-05-23T13:01:30Z

VPA 예제

예제를 아래와 같이 배포했을 때 pod가 vpa에 의해 재생성되는 것을 볼 수 있습니다.

bash
$ cd ~/autoscaler/vertical-pod-autoscaler/ $ kubectl apply -f examples/hamster.yaml && kubectl get vpa -w verticalpodautoscaler.autoscaling.k8s.io/hamster-vpa created deployment.apps/hamster created NAME MODE CPU MEM PROVIDED AGE hamster-vpa Auto 1s hamster-vpa Auto 587m 262144k True 9s hamster-vpa Auto 587m 262144k True 69s $ kubectl get deploy -o wide -w NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR hamster 2/2 2 2 28s hamster registry.k8s.io/ubuntu-slim:0.1 app=hamster hamster 1/2 1 1 68s hamster registry.k8s.io/ubuntu-slim:0.1 app=hamster hamster 1/2 2 1 68s hamster registry.k8s.io/ubuntu-slim:0.1 app=hamster hamster 2/2 2 2 69s hamster registry.k8s.io/ubuntu-slim:0.1 app=hamster

위 예제에서는 pod가 순차적으로 vpa에 의해 재생성되지만 동시에 기존 pod가 종료될 가능성도 있기 때문에 추가적인 설정을 해보겠습니다.

방법 1) updatePolicy

bash
$ vi examples/hamster.yaml --- 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 updatePolicy: updateMode: "Auto" minReplicas: 1 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"

replica 수가 2개인 deployment에 대해 vpa를 설정했고, 최소 1개의 pod를 유지하기 위해 아래 설정을 추가했습니다.

bash
updatePolicy: updateMode: "Auto" minReplicas: 1

 

방법 2) PDB

pod가 evict 될 때 최소 pod를 유지하기 위해 PDB를 사용하는 것처럼 VPA에 pdb를 같이 사용해보겠습니다.

먼저 아래와 같이 pdb를 생성합니다.

bash
apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: hamster-pdb spec: minAvailable: 1 selector: matchLabels: app: hamster

그리고 기존 example/hamster.yaml 파일로 배포한 자원을 삭제하고 updatePolicy 부분을 삭제한 뒤에 다시 배포하겠습니다.

bash
$ kubectl delete -f examples/hamster.yaml
bash
$ vi examples/hamster.yaml --- 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 # updatePolicy: # updateMode: "Auto" # minReplicas: 1 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"
bash
$ kubectl apply -f examples/hamster.yaml && kubectl get vpa -w

위 예제에서는 별도의 설정없이도 pod가 동시에 종료되는 현상이 없어서 updatePolicy와 PDB를 테스트하기에 적합하지는 않지만, 두 방법 모두 정상 동작하는 것을 확인했습니다.

 

CPA

  • 클러스터 규모에 따라 pod 수를 늘릴 필요가 있는 컴포넌트들에 사용합니다.
  • 노드 수에 따라 pod 수를 자동으로 증가하게 설정할 수 있습니다.

사전 설치 툴

실습 중 사전에 설치가 필요한 툴 설치 방법입니다.

EKS Node Viewer 설치 및 사용 예

bash
$ yum install -y go $ go install github.com/awslabs/eks-node-viewer/cmd/eks-node-viewer@latest $ cd ~/go/bin $ ./eks-node-viewer 3 nodes (675m/5790m) 11.7% cpu █████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ $0.156/hour | $113.880/month 9 pods (0 pending 9 running 9 bound) ip-192-168-1-195.ap-northeast-2.compute.internal cpu ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 12% (3 pods) t3.medium/$0.0520 On ip-192-168-2-244.ap-northeast-2.compute.internal cpu ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 12% (3 pods) t3.medium/$0.0520 On ip-192-168-3-150.ap-northeast-2.compute.internal cpu ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 12% (3 pods) t3.medium/$0.0520 On Press any key to quit

metric server 설치

bash
$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

이상으로 5주차 내용 정리를 마치겠습니다.

해당 문서에 포함되지 않은 실습은 추후에 별도 글로 정리해보겠습니다.

 

참고 문서

728x90

'Kubernetes > EKS Study' 카테고리의 다른 글

[6주차] EKS Security  (0) 2023.06.11
[4주차] EKS Observability  (0) 2023.05.21
[3주차] EKS Storage  (0) 2023.05.09
EKS에서 볼륨 snapscheduler 설치하기  (0) 2023.05.09
EKS에서 pvc로 생성한 ebs에 태그 추가하기  (0) 2023.05.09