I got IT

EKS Autoscaling - 2 (Node level) 본문

AWS/EKS

EKS Autoscaling - 2 (Node level)

joshhoxy 2025. 3. 9. 04:25

※ 해당 글은 CloudNet@ gasida 님의 EKS 스터디 내용을 참고하여 작성하였습니다.

5. CAS - Cluster Autoscaler

5.1 Cluster Autoscaler 란 ?

위 과정 까지는 파드레벨의 오토스케일링 이었다면 지금부터는 노드 레벨의 오토스케일링에 대해서 다뤄보겠습니다. Cluster Autoscaler 이하 CAS 는쿠버네티스 공식 지원 기능으로 다음 링크를 참고 바랍니다.

https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md

  1. 작동 방식:
    • CAS는 클러스터의 노드 그룹을 기반으로 작동하며, Auto Scaling Group(ASG)과 같은 클라우드 제공자의 추상화 계층을 활용합니다.
    • Pending 상태의 Pod이 있을 때, 노드 그룹에서 사전 정의된 노드 유형을 추가하거나 제거하여 클러스터 크기를 조정합니다.
  2. 특징:
    • 노드 그룹별로 동작하며, 특정 노드 유형으로만 확장 가능.
    • 여러 클라우드 제공자(GCP, AWS, Azure 등)를 지원.
    • 확장 속도가 상대적으로 느림(클라우드 제공자 계층에 의존).
    • Spot 인스턴스를 지원하지만 제한적.
  3. 장점:
    • 다중 클라우드 환경에서 사용 가능.
    • 안정적이고 오랜 기간 검증된 도구.
  4. 단점:
    • 노드 그룹 관리가 복잡할 수 있음.
    • 실시간 워크로드 요구 사항에 대한 세부적인 조정이 어려움.

💡 CAS Auto-Discovery ?

Auto-Discovery는 노드 그룹(Auto Scaling Groups, ASG)을 자동으로 탐지하고 관리하는 기능입니다. 이 기능은 클러스터의 확장 및 축소를 간소화하며, 수동으로 노드 그룹을 지정할 필요 없이 태그 기반으로 노드 그룹을 자동으로 인식하도록 설정됩니다.

5.2 CAS 실습

5.2.1 CAS requirements 확인

CAS는 CSP 종속적이기 때문에 AWS 환경에서 사용중이라면 ec2에 태그를 미리 세팅해 주어야 합니다.

저희는 위 실습환경 구성에서 이미 설정이 되어있기 때문에 따로 작업할 필요 없이 확인만 해줍니다.

**# EKS 노드에 이미 아래 tag가 들어가 있음**
# k8s.io/cluster-autoscaler/enabled : true
# k8s.io/cluster-autoscaler/myeks : owned
aws ec2 describe-instances  --filters Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node --query "Reservations[*].Instances[*].Tags[*]" --output json | jq
**aws ec2 describe-instances  --filters Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node --query "Reservations[*].Instances[*].Tags[*]" --output yaml**
...
- Key: k8s.io/cluster-**autoscaler**/myeks
      Value: owned
- Key: k8s.io/cluster-**autoscaler**/enabled
      Value: 'true'
...

 

 

CAS 는 기본적으로 AWS autoscaling(ASG)를 사용하므로 해당 정보에 대해 확인해 봅니다.

# aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='클러스터이름']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" --output table
aws autoscaling describe-auto-scaling-groups \
    --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='myeks']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" \
    --output table

# MaxSize 6개로 수정
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 6

# 확인
aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='myeks']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" --output table

5.2.2 CAS 배포하기

# 배포 : Deploy the Cluster Autoscaler (CAS)
curl -s -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

sed -i -e "s|<YOUR CLUSTER NAME>|$CLUSTER_NAME|g" cluster-autoscaler-autodiscover.yaml
kubectl apply -f cluster-autoscaler-autodiscover.yaml

# 확인
kubectl get pod -n kube-system | grep cluster-autoscaler
kubectl describe deployments.apps -n kube-system cluster-autoscaler
kubectl describe deployments.apps -n kube-system cluster-autoscaler | grep node-group-auto-discovery
      --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/myeks

# (옵션) cluster-autoscaler 파드가 동작하는 워커 노드가 퇴출(evict) 되지 않게 설정
kubectl -n kube-system annotate deployment.apps/cluster-autoscaler cluster-autoscaler.kubernetes.io/safe-to-evict="false"

cloud-provider로 AWS 를 사용합니다.

 

 

⚠️ auto-discovery 설정을 위해 클러스터 이름 지정 및 사전 태그 작업이 반드시 필요합니다.

5.2.3 CAS 동작 시키기

# 모니터링 
kubectl get nodes -w
while true; do kubectl get node; echo "------------------------------" ; date ; sleep 1; done
while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------"; date; sleep 1; done

# Deploy a Sample App
# We will deploy an sample nginx application as a ReplicaSet of 1 Pod
cat << EOF > nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-to-scaleout
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        service: nginx
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx-to-scaleout
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 500m
            memory: 512Mi
EOF
kubectl apply -f nginx.yaml
kubectl get deployment/nginx-to-scaleout

# Scale our ReplicaSet
# Let’s scale out the replicaset to 15
kubectl scale --replicas=15 deployment/nginx-to-scaleout && date

# 확인
kubectl get pods -l app=nginx -o wide --watch
kubectl -n kube-system logs -f deployment/cluster-autoscaler

# 노드 자동 증가 확인
kubectl get nodes
aws autoscaling describe-auto-scaling-groups \
    --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='myeks']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" \
    --output table

eks-node-viewer --resources cpu,memory
혹은
eks-node-viewer

# [운영서버 EC2] 최근 1시간 Fleet API 호출 확인 - Link
# https://ap-northeast-2.console.aws.amazon.com/cloudtrailv2/home?region=ap-northeast-2#/events?EventName=CreateFleet
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=CreateFleet \
  --start-time "$(date -d '1 hour ago' --utc +%Y-%m-%dT%H:%M:%SZ)" \
  --end-time "$(date --utc +%Y-%m-%dT%H:%M:%SZ)"

# (참고) Event name : UpdateAutoScalingGroup
# https://ap-northeast-2.console.aws.amazon.com/cloudtrailv2/home?region=ap-northeast-2#/events?EventName=UpdateAutoScalingGroup

모니터링 띄워놓은 상태에서 kubectl scale --replicas=15 deployment/nginx-to-scaleout && date 파드 레플리카를 늘려줍니다.

 

순식간에 노드가 6대로 증가하는 것을 확인할 수 있습니다.

 

kube-ops viewer에도 확인이 가능합니다.

 

eks-node-viewer로 좀더 직관적으로 확인할 수도 있습니다.

eks-node-viewer --extra-labels topology.kubernetes.io/zone,eks-node-viewer/node-age

 

AWS 트레일을 살펴보면 autoscaling 사용자가 createFleet 이벤트를 발생 시킨것을 볼 수 있습니다.

5.3 CAS 실습 자원 삭제

# 디플로이먼트 삭제
kubectl delete -f nginx.yaml && date

# [scale-down] 노드 갯수 축소 : 기본은 10분 후 scale down 됨, 물론 아래 flag 로 시간 수정 가능 >> 그러니 디플로이먼트 삭제 후 10분 기다리고 나서 보자!
# By default, cluster autoscaler will wait 10 minutes between scale down operations, 
# you can adjust this using the --scale-down-delay-after-add, --scale-down-delay-after-delete, 
# and --scale-down-delay-after-failure flag. 
# E.g. --scale-down-delay-after-add=5m to decrease the scale down delay to 5 minutes after a node has been added.

# 터미널1
watch -d kubectl get node

💡 노드레벨의 스케일 다운(인)은 파드레벨의 스케일 다운보다 훨씬 오래 걸립니다.

6. CPA - Cluster Proportional Autoscaler

6.1 CPA 란?

CPA는 노드 수 증가에 비례하여 성능 처리가 필요한 애플리케이션(컨테이너/파드)를 수평으로 자동 확장합니다.

노드 수에 따라 몇개의 파드를 설정할 것인 지 등을 설정할 수 있습니다.

6.1.1 CPA 특징

  1. 노드 기반 스케일링:
    • CPA는 클러스터 내 스케줄 가능한 노드 수코어 수를 모니터링하여 워크로드의 Pod 복제본 수를 조정합니다.
    • 클러스터 크기에 비례하여 워크로드가 확장 또는 축소됩니다.
  2. 프로포셔널 스케일링:
    • CPA는 클러스터 크기와 워크로드 간의 비례 관계를 설정하여, 클러스터 크기가 변경될 때 워크로드가 이에 맞게 자동으로 조정되도록 합니다.
    • 예: 노드가 10개에서 20개로 증가하면, Pod 복제본 수도 2배로 증가.
  3. ConfigMap 기반 설정:
    • CPA의 스케일링 매개변수는 ConfigMap을 통해 제공됩니다.
    • ConfigMap은 주기적으로 갱신되며 최신 스케일링 매개변수를 반영합니다.
  4. Metrics API 불필요:
    • CPA는 Kubernetes Metrics API나 Metrics Server에 의존하지 않습니다. 대신, Golang API 클라이언트를 사용해 Kubernetes API 서버에서 직접 데이터를 가져옵니다.
  5. 단순한 구조:
    • CPA는 단순한 작동 모델을 가지고 있어 설정과 유지보수가 쉽습니다.
    • CoreDNS와 같은 시스템 구성 요소처럼 클러스터 크기에 따라 스케일링이 필요한 워크로드에 적합합니다.
  6. 스케일링 방식 지원:
    • Linear Scaling: 노드 수에 비례하여 복제본 수를 선형적으로 조정.
    • Ladder Scaling: 특정 노드 수 범위에 따라 복제본 수를 단계적으로 조정.

💡 즉 복잡한 계산식이나 알고리즘을 통해서 스케줄링을 하는 것이 아니라 고정적인 규칙(정의)대로 스케줄링을 하는 것이라고 보면 됩니다.

6.2 CPA 실습

해당 실습은 Helm을 통해 배포하고 config를 통해 규칙을 적용합니다. 이때 config 를 살펴보면 노드 개수에 정비례하여 파드가 하나씩 증가하도록 설정한 것을 볼수 있습니다.

#
helm repo add cluster-proportional-autoscaler https://kubernetes-sigs.github.io/cluster-proportional-autoscaler

# CPA규칙을 설정하고 helm차트를 릴리즈 필요
helm upgrade --install cluster-proportional-autoscaler cluster-proportional-autoscaler/cluster-proportional-autoscaler

# nginx 디플로이먼트 배포
cat <<EOT > cpa-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        resources:
          limits:
            cpu: "100m"
            memory: "64Mi"
          requests:
            cpu: "100m"
            memory: "64Mi"
        ports:
        - containerPort: 80
EOT
kubectl apply -f cpa-nginx.yaml

# CPA 규칙 설정
cat <<EOF > cpa-values.yaml
config:
  ladder:
    nodesToReplicas:
      - [1, 1]
      - [2, 2]
      - [3, 3]
      - [4, 3]
      - [5, 5]
options:
  namespace: default
  target: "deployment/nginx-deployment"
EOF
kubectl describe cm cluster-proportional-autoscaler

# 모니터링
watch -d kubectl get pod

****# helm 업그레이드
helm upgrade --install cluster-proportional-autoscaler -f cpa-values.yaml cluster-proportional-autoscaler/cluster-proportional-autoscaler

# 노드 5개로 증가
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 5 --desired-capacity 5 --max-size 5
aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='myeks']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" --output table

# 노드 4개로 축소
aws autoscaling update-auto-scaling-group --auto-scaling-group-name ${ASG_NAME} --min-size 4 --desired-capacity 4 --max-size 4
aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='myeks']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" --output table

노드가 증가하자 파드가 따라서 증가합니다.

 

참고로 다음과 같이 CPU/Memory 고정 값을 통한 스케일링 규칙도 설정 가능합니다.

 "coresToReplicas":
      [
        [ 1, 1 ],
        [ 64, 3 ],
        [ 512, 5 ],
        [ 1024, 7 ],
        [ 2048, 10 ],
        [ 4096, 15 ]
      ],

 

7. 실습 환경 정리

지금까지 진행한 실습 환경을 모두 정리합니다.

EKS 운영서버에서 아래 명령어를 실행합니다.

# eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME
nohup sh -c "eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME" > /root/delete.log 2>&1 &

# (옵션) 삭제 과정 확인
tail -f delete.log

카펜터는 다른 실습환경이 필요하므로 우선 기존의 실습환경을 먼저 삭제해줍니다.

'AWS > EKS' 카테고리의 다른 글

EKS Security - ECR Enhanced Scanning  (0) 2025.03.16
EKS Autoscaling - 3 (Karpenter)  (0) 2025.03.09
EKS Autoscaling - 1 (Pod level)  (0) 2025.03.08
EKS 모니터링  (1) 2025.03.02
EKS Basic Concepts  (0) 2025.02.08