Ssoon

[5주차] EKS Autoscaling - KARPENTER - CONSOLIDATION 본문

AWS EKS Workshop Study

[5주차] EKS Autoscaling - KARPENTER - CONSOLIDATION

구구달스 2023. 5. 25. 10:39
CloudNet@ 팀의 AWS EKS Workshop Study 5주차 정리입니다.
# Karpenter Workshop 의 내용입니다.

Karpenter consolidation은 Karpenter의 기능 중 하나로, Kubernetes 클러스터에서 리소스를 효율적으로 사용하고, 여러 작은 파드를 단일 물리적 호스트에 결합하여 리소스를 공유하는 방법을 제공합니다.

 

일반적으로, 여러 파드가 동작하는 동안 각각 독립적인 가상 머신 또는 호스트에 할당됩니다. 그러나 일부 작은 파드의 경우에는 개별적인 가상 머신에 할당되는 것은 비효율적일 수 있습니다. 예를 들어, 작은 파드의 경우 호스트 리소스의 일부만 사용하므로 리소스 낭비가 발생할 수 있습니다.

 

Karpenter consolidation은 이러한 리소스 낭비를 최소화하기 위해 작은 파드를 단일 물리적 호스트에 결합하는 방식을 채택합니다. 이를 통해 호스트 리소스를 더 효율적으로 사용할 수 있고, 더 많은 파드를 단일 호스트에서 실행함으로써 클러스터의 가용 리소스를 최적화합니다.

Karpenter consolidation은 파드의 배치 및 스케줄링 결정에 영향을 줍니다. 작은 파드는 기존의 독립적인 가상 머신 대신에 적절한 호스트에 결합되어 배치됩니다. 이를 통해 리소스의 공유와 효율적인 활용을 실현할 수 있습니다.

Karpenter consolidation은 Kubernetes 클러스터의 성능과 확장성을 향상시키는 데 도움을 주며, 리소스 사용량을 최적화하여 비용을 절감할 수 있습니다.


이전 섹션에서는 특정 ttlSecondsAfterEmpty로 구성된 기본 제공자를 설정했습니다. 

이는 비어 있는 노드의 ttlSecondsAfterEmpty 이후 노드를 제거하도록 Karpenter에 지시합니다. 

자동화된 deprovisioning 는 ProvisionerSpec .ttlSecondsAfterEmpty, .ttlSecondsUntilExpired 및 .consolidation.enabled 필드를 통해 구성됩니다. 구성되지 않은 경우 Karpenter는 기본값을 지정하지 않고 노드를 종료하지 않습니다.

Consolidation이라는 노드를 deprovisioning 하도록 Karpenter를 구성하는 또 다른 방법이 있습니다. 

이 모드는 마이크로서비스와 같은 워크로드에 선호되며 ttlSecondsAfterEmpty 설정과 호환되지 않습니다. 

consolidation mode 로 설정하면 Karpenter는 워크로드가 클러스터의 다른 노드에서 실행될 때 노드를 제거할 수 있는 시기와 워크로드의 변경으로 인해 노드를 더 저렴한 변형으로 교체할 수 있는 시기를 식별하여 클러스터 비용을 적극적으로 절감합니다.


  • 먼저 기본 프로비저너 구성을 변경합니다.
cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  consolidation:
    enabled: true
  labels:
    intent: apps
  requirements:
    - key: karpenter.sh/capacity-type
      operator: In
      values: ["on-demand"]
    - key: karpenter.k8s.aws/instance-size
      operator: NotIn
      values: [nano, micro, small, medium, large]
  limits:
    resources:
      cpu: 1000
      memory: 1000Gi
  ttlSecondsUntilExpired: 2592000
  providerRef:
    name: default
---
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: default
spec:
  subnetSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  securityGroupSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  tags:
    KarpenerProvisionerName: "default"
    NodeType: "karpenter-workshop"
    IntentLabel: "apps"
EOF

  • 환경을 초기 상태로 설정합니다. 먼저 inflate 애플리케이션을 3개의 복제본으로 확장하여 노드를 프로비저닝합니다.
kubectl scale deployment inflate --replicas 3

  • 10개의 복제본으로 확장하여 노드를 프로비저닝합니다.
kubectl scale deployment inflate --replicas 10


inflate deployment 를 replicas 을 6으로 변경합니다.

kubectl scale deployment inflate --replicas 6

4개의 포드가 종료되었습니다. 이로 인해 Karpenter는 xlarge 노드를 삭제하고 2xlarge 용량에 남아 있는 6개의 팟을 통합하여 클러스터 중단을 줄이면서 비용을 줄이는 작업을 수행했습니다.

Karpenter에는 클러스터 consolidation 을 위한 두 가지 메커니즘이 있습니다.

  • Deletion - 모든 pods 가 클러스터에 있는 다른 노드의 여유 용량에서 실행될 수 있는 경우 노드를 삭제할 수 있습니다.
  • Replace - 모든 pods 가 클러스터에 있는 다른 노드의 여유 용량과 더 저렴한 단일 교체 노드의 조합에서 실행될 수 있는 경우 노드를 교체할 수 있습니다.

잠재적으로 deleted 되거나 replaced 될 수 있는 노드가 여러 개 있는 경우 Karpenter는 terminate 를 선호하여 워크로드를 전반적으로 방해하는 노드를 통합하도록(consolidate) 선택합니다.

  • 더 적은 포드를 실행하는 노드
  • 곧 만료될 노드
  • 우선 순위가 낮은 포드가 있는 노드

replicas 을 3 으로 변경합니다.

kubectl scale deployment inflate --replicas 3

  • 이 경우 Karpenter가 Replace 주문을 발행하고 2xlarge 인스턴스 대신 xlarge 인스턴스로의 consolidation 을 사용할 것입니다.
  • 먼저 새 xlarge 인스턴스가 생성 및 시작되고 마지막으로 2xlarge 인스턴스가 종료되는 단계입니다.


replicas 을 10으로 변경합니다. on-demand 와 spot 을 모두 지원하도록 프로비저너를 변경합니다.

kubectl scale deployment inflate --replicas 10

  • 이전 사례에서처럼 추가 7개 포드를 배치하기 위해 새로운 2xlarge 노드를 선택합니다.

프로비저너에 변경 사항을 적용하기 위해 이번에는 온디맨드와 스팟을 모두 사용하여 기본 프로비저너를 재배포합니다.

cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  # Enables consolidation which attempts to reduce cluster cost by both removing un-needed nodes and down-sizing those
  # that can't be removed.  Mutually exclusive with the ttlSecondsAfterEmpty parameter.
  consolidation:
    enabled: true
  labels:
    intent: apps
  requirements:
    - key: karpenter.sh/capacity-type
      operator: In
      values: ["on-demand","spot"]
    - key: karpenter.k8s.aws/instance-size
      operator: NotIn
      values: [nano, micro, small, medium, large]
  limits:
    resources:
      cpu: 1000
      memory: 1000Gi
  ttlSecondsUntilExpired: 2592000
  providerRef:
    name: default
---
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: default
spec:
  subnetSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  securityGroupSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  tags:
    KarpenerProvisionerName: "default"
    NodeType: "karpenter-workshop"
    IntentLabel: "apps"
EOF

  • 기본 설정을 제공하지 않는 deployments 의 경우 Karpenter는 프로비저너가 spot 및 on-demand 인스턴스를 허용하는 경우 spot 오퍼링을 우선 순위로 지정합니다. 
  • 프로비저너가 변경되면 consolidation 정책도 재평가되고 이러한 변경의 결과로 Karpenter가 클러스터의 노드를 on-demand 에서 spot 으로 변경합니다. 
controller.deprovisioning       deprovisioning via consolidation replace, terminating 2 nodes ip-192-168-118-56.ap-northeast-2.compute.internal/c5a.xlarge/on-demand, ip-192-168-40-236.ap-northeast-2.compute.internal/c5a.2xlarge/on-demand and replacing with spot node from types c4.4xlarge, m5ad.4xlarge, c6i.4xlarge, c6i.8xlarge, m5a.4xlarge and 23 other(s) {"commit": "982c35f"}
  • 먼저 새 spot 인스턴스가 생성된 다음 교체 대상으로 선택된 on-demand 인스턴스가 terminated 됩니다. 


inflate 서비스를 replicas 을 3 으로 변경합니다.

kubectl scale deployment inflate --replicas 3
  • 스팟 노드의 경우 Karpenter는 삭제 consolidation 메커니즘만 사용합니다. 
  • 스팟 노드를 더 저렴한 스팟 노드로 대체하지 않습니다. 사실상 이 단계에서는 클러스터에 변경 사항이 발생하지 않습니다.

클러스터에서 Consolidation 이벤트를 방지할 수 있는 다른 시나리오는 무엇입니까?

  • Karpenter 노드 deprovision 요청이 작동하지 않는 몇 가지 경우가 있습니다. 여기에는 Pod Disruption Budgets 및 do-not-evict annotation set 가 있는 pods 가 포함됩니다.
  • Karpenter는 backoff retry eviction 전략을 사용하여 Pod Disruption Budgets(PDB)을 준수합니다. pods 는 강제로 삭제되지 않으므로 종료에 실패한 포드는 노드 deprovisioning 를 방지합니다.
  • Kubernetes PDB를 사용하면 pod eviction 요청이 생성될 때 중단으로부터 보호해야 하는 Deployment, ReplicationController, ReplicaSet 또는 StatefulSet의 양을 지정할 수 있습니다.
Pod Disruption Budgets(PDB)는 Kubernetes에서 사용되는 정책 중 하나로, 파드(Pod)의 중단을 제어하기 위해 사용되는 개념입니다. PDB를 설정하면 파드 그룹에 대한 중단 제한을 설정할 수 있습니다. PDB는 클러스터 관리자가 안정성 요구 사항을 설정하고 파드 그룹을 보호하기 위해 사용됩니다. PDB를 사용하면 클러스터의 노드 중단, 유지 보수 작업, 확장 작업 등의 시나리오에서 파드의 안정성과 가용성을 보장할 수 있습니다.

 

노드에 karpenter.sh/do-not-evict: true 주석이 있는 포드가 존재하고 노드 삭제 요청이 있는 경우 Karpenter는 해당 노드에서 포드를 비우거나(drain) 노드 삭제를 시도하지 않습니다. 

do-not-evict annotation 이 있는 포드가 있는 노드는 consolidation 대상으로 간주되지 않지만 consolidation 할 수 있는 다른 노드에서 포드를 실행하기 위해 사용되지 않은 용량이 고려됩니다.

Consolidation 은 스케줄링 시뮬레이션 결과 다음과 같은 이유로 노드의 포드를 다른 노드에서 실행할 수 없다고 판단하는 경우 노드를 consolidate 할 수 없습니다.

  • 파드 간 affinity/anti-affinity
  • 토폴로지 확산 constraints
  • 또는 이행할 수 없는 다른 일정 제한.

마지막으로 Karpenter consolidation 은 컨트롤러(예: ReplicaSet)가 소유하지 않은 pods 를 실행 중인 노드를 통합하려고 시도하지 않습니다.


replicas 을 0으로 변경합니다.

kubectl scale deployment inflate --replicas 0

[ 정리 ]

  • Consolidation 은 두 가지 상황에서 클러스터의 전체 비용을 줄이는 데 도움이 됩니다. 노드의 용량을 다른 노드에 안전하게 분배할 수 있는 경우 삭제가 발생할 수 있습니다. Replace 는 노드를 더 작은 노드로 교체하여 클러스터 비용을 줄일 수 있을 때 발생합니다.

  • Consolidation 은 여러 노드를 고려하지만 한 번에 하나의 노드에서만 작동합니다. 선택한 노드는 클러스터의 중단을 최소화하는 노드입니다.

  • Consolidation 삭제에는 인스턴스가 on-demand 에서 spot 으로 이동하는 이벤트도 포함되지만 karpenter는 중단(interruptions) 수준에 영향을 미칠 수 있으므로 스팟 노드를 더 작게 만들기 위해 교체를 트리거하지 않습니다.

  • Karpenter는 cordon 및 drain 모범 사례를 사용하여 노드를 종료(terminate)합니다. 더 안전하게 만들기 위해 Karpenter는 파이널라이저(finalizer)를 추가하여 kubernetes delete node 명령이 클러스터에서 노드를 안전하게 제거하는 정상적인 종료를 초래합니다.
Comments