본문 바로가기
Orchestration/Kubernetes

AWS EKS AutoScaling 속도 비교(Cluster Autoscaler vs Kerpenter)

by wlsdn3004 2023. 10. 22.
728x90
반응형

 

Auto Scaling Group(ASG)와 Karpenter의 auto scaling이 발생하는 속도에서 꽤 많은 차이를 보인다.
그렇다면, ASG를 사용하는 환경에서 속도를 줄일 수 있는 방법은 없을까? 생각하다 한 가지 기능을 발견하여 테스트해 보았다. 바로 Warm Pool 기능이다.

Auto Scaling Group(ASG)의 Warm Pool
기능은 노드를 미리 초기화하고, 초기화된 노드는 시작되었다가 중지(Stop) 상태로 대기하게 된다. 그런 상태에서 Scale-out이 발생하여 desired 값이 증가하면 중지 상태로 대기하고 있던 노드를 구동시킨다.

 

Warm Pool에 있는 노드는 대기 상태이기 때문에 Scale-out 발생하는 데 필요한 시간을 줄일 수 있고, 대기 상태에 있는 노드는 추가 비용을 발생시키지 않기 때문에 비용 효율적으로 관리할 수 있다.

 

아래 그림 참고.

Auto Scaling Group warm pool

왼쪽은 일반적인 nodegroup ASG 구성이고 오른쪽은 warm pool 기능을 사용하는 ASG 구성이다.

warm pool instance는 시작된 후 userdata에 의해 EKS 노드에 조인되고 중지되어 NodeReady 상태로 대기하고 있는 것이다.

 

warm pool로 대기 중인 노드는 시작되어 EKS 클러스터 워커노드로 조인된 후 중지되는 방식이기 때문에 시작된 후 중지되는 사이에 Pod가 해당 노드에 배포되면 지속적인 Terminating 상태로 남게 된다. 이때 Pod는 ip를 할당받고 있는 상태이기 때문에 ip가 여유롭지 않은 환경이라면 주의해야 한다.

 

본 글에서는 Auto Scaling Group Warm Pool 기능 구성 후 Karpenter, Auto Scaling Group, Auto Scaling Group Warm Pool  3가지 구성의 Auto Scaling 속도를 비교해 보려 한다.

 

실습


전제 조건

구성 환경

  • AWS EKS : 1.24.17
  • Terraform : v1.6.6

구성 버전

  • Custer Autoscaler: 1.26.2
  • Karpenter : 0.31.0 

 

 

 

1. Auto Scaling Group구성 및 Warm Pool 설정


아래는 테라폼으로 launch_template, auto scaling group을 생성한 코드이다.

variable "size" {
  description = "ASG size configuration"
  type = object({
    desired = number
    max     = number
    min     = number
  })
  default = {
    desired = 2
    max     = 3
    min     = 1
  }
}

data "template_file" "userdata" {

  template = file("resource/userdata.sh")

  vars = {
    cluster_name        = aws_eks_cluster.eks.name
    endpoint            = aws_eks_cluster.eks.endpoint
    cluster_auth_base64 = aws_eks_cluster.eks.certificate_authority.0.data
  }
}

resource "aws_launch_template" "warm-pool-template" {
  name_prefix = "wlsdn-test--warm-pool-nodegroup"
  image_id = data.aws_ami.eks-worker.id
  instance_type          = "c5.large"
  key_name               = "test-key"
  vpc_security_group_ids = var.security_group
  user_data              = base64encode(data.template_file.userdata.rendered)

  iam_instance_profile {
    name = aws_iam_instance_profile.warm-pool.name
  }

  block_device_mappings {
    device_name = "/dev/xvda"
    ebs {
      volume_size           = 20
      delete_on_termination = true
      volume_type           = "gp2"
    }
  }
}

resource "aws_autoscaling_group" "managed-nodes-warm-pool-asg" {
  name                      = "wlsdn-eks-nodegroup-warm-pool-asg"
  desired_capacity          = var.size.desired
  max_size                  = var.size.max
  min_size                  = var.size.min
  health_check_grace_period = 15
  health_check_type         = "EC2"
  force_delete              = true

  launch_template {
    id      = aws_launch_template.warm-pool-template.id
    version = "$Latest"
  }

  vpc_zone_identifier = [aws_subnet.private-subnet1.id, aws_subnet.private-subnet2.id, aws_subnet.private-subnet3.id]
  warm_pool {
    pool_state                  = "Stopped"
    min_size                    = "1"
    max_group_prepared_capacity = "1"
  }
  
  timeouts {
    delete = "15m"
  }
  
  tag {
    key                 = "kubernetes.io/cluster/${var.cluster_name}"
    propagate_at_launch = true
    value               = "owned"
  }
  tag {
    key                 = "k8s.io/cluster-autoscaler/enable"
    propagate_at_launch = true
    value               = "true"
  }
  tag {
    key                 = "k8s.io/cluster-autoscaler/${var.cluster_name}"
    propagate_at_launch = true
    value               = "owned"
  }


}

 

잘 생성되었는지 AWS console에서 확인한다.

  • EC2 > Auto Scaling 그룹 > {ASG 이름} > 인스턴스 관리

2개의 노드가 Running 상태이고, 1개의 노드는 Warm Pool 인스턴스에서 관리되며 Stop 상태로 대기하고 있는 상태이다.

 

kubectl 명령으로 확인해 보면 NotReady 상태의 노드가 확인되는데, Warm Pool 설정으로 하나의 노드가 추가 구동 되어 EKS에 워커노드로 조인된 후 중지로 남은 상태인 것이다.

$ kubectl get no
NAME                                               STATUS     ROLES    AGE   VERSION
ip-192-xxxxxxxx.ap-northeast-2.compute.internal    Ready      <none>   70m   v1.24.17-eks-43840fb
ip-192-xxxxxxxx.ap-northeast-2.compute.internal    Ready      <none>   69m   v1.24.17-eks-43840fb
ip-192-xxxxxxxx.ap-northeast-2.compute.internal    NotReady   <none>   60m   v1.24.17-eks-43840fb

 

2.  Auto Scaling 속도 비교


2-1. Scale out 속도 비교

아래는 Karpenter에 의해 노드가 scale out 되고 Pod가 생성되는 시간이다.

Events:
  Type     Reason            Age    From               Message
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  42s    default-scheduler  0/2 nodes are available: 2 Insufficient cpu, 2 Insufficient memory. preemption: 0/2 nodes are available: 2 No preemption victims found for incoming pod.
  Normal   Nominated         41s    karpenter          Pod should schedule on: machine/default-njp6j
  Normal   Scheduled         8s     default-scheduler  Successfully assigned default/nginx-6bf9dbff7d-crc9v to ip-192-168-7-107.ap-northeast-2.compute.internal
  Normal   Pulling           7s     kubelet            Pulling image "nginx:latest"
  Normal   Pulled            1s     kubelet            Successfully pulled image "nginx:latest" in 6.342940648s
  Normal   Created           1s     kubelet            Created container nginx
  Normal   Started           0s     kubelet            Started container nginx

Karpenter로 동작하는 환경에서 Pod가 start 되기까지 전체 42초가 걸리는 걸 확인할 수 있다.

 

아래는 Cluster Autoscaler에 의해 노드가 scale out 되고 Pod가 생성되는 시간이다. 

Events:
  Type     Reason            Age   From                Message
  ----     ------            ----  ----                -------
  Warning  FailedScheduling  68s   default-scheduler   0/2 nodes are available: 2 Insufficient memory. preemption: 0/2 nodes are available: 2 No preemption victims found for incoming pod.
  Normal   TriggeredScaleUp  64s   cluster-autoscaler  pod triggered scale-up: [{eks-wlsdn-eks-nodegroup-00c5a5cd-8185-aaa6-90ac-cea3b8737366 2->3 (max: 3)}]
  Normal   Scheduled         8s    default-scheduler   Successfully assigned default/nginx-6bf9dbff7d-kvhzh to ip-192-168-8-120.ap-northeast-2.compute.internal
  Normal   Pulling           7s    kubelet             Pulling image "nginx:latest"
  Normal   Pulled            0s    kubelet             Successfully pulled image "nginx:latest" in 6.691035377s
  Normal   Created           0s    kubelet             Created container nginx
  Normal   Started           0s    kubelet             Started container nginx

Cluster Autoscaler로 동작하는 환경에서 Pod가 start 되기까지 전체 68가 걸리는 걸 확인할 수 있다.

 

아래는 ASG의 warm pool 상태에서 Cluster Autoscaler에 의해 노드가 scale out 되고 Pod가 생성되는 시간이다.  

Events:
  Type     Reason                  Age   From                Message
  ----     ------                  ----  ----                -------
  Warning  FailedScheduling        47s   default-scheduler   0/3 nodes are available: 1 node(s) had untolerated taint {node.kubernetes.io/unreachable: }, 2 Insufficient memory. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod.
  Normal   TriggeredScaleUp        41s   cluster-autoscaler  pod triggered scale-up: [{wlsdn-eks-nodegroup-warm-pool-asg 2->3 (max: 3)}]
  Normal   Scheduled               20s   default-scheduler   Successfully assigned default/nginx-6bf9dbff7d-vndbk to ip-192-168-6-178.ap-northeast-2.compute.internal
  Warning  FailedCreatePodSandBox  19s   kubelet             Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "2badff3af8920ccf439c074ae58da22b96b9e34eaa39519062453d69ff29cb98": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: Error received from AddNetwork gRPC call: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 127.0.0.1:50051: connect: connection refused"
  Normal   Pulling                 6s    kubelet             Pulling image "nginx:latest"
  Normal   Pulled                  0s    kubelet             Successfully pulled image "nginx:latest" in 6.595667595s
  Normal   Created                 0s    kubelet             Created container nginx
  Normal   Started                 0s    kubelet             Started container nginx

ASG의 warm pool로 설정된 환경에서 Pod가 start 되기까지 전체 47가 걸리는 걸 확인할 수 있다.

 

scale out 속도 차이 결과

  • Karpenter : 42초 >  Cluster Autoscaler(Warm Pool) : 47초  >  Cluster Autoscaler : 68초 

 

 

2-2. Scale in 속도 비교

두 제품 모두 비어있는 노드가 감지되면 30초 후에 Scale in 되도록 설정 후 테스트 하였다.

  • Karpenter 옵션
    • ttlSecondsAfterEmpty: 30
  • Cluster Autoscaler 옵션
    • --scale-down-unneeded-time=30s

 

아래는 Karpenter에 의해 노드가 scale in 되고 노드가 삭제되는 시간을 측정한 것이다.

$ kubectl logs -n karpenter deploy/karpenter -f
...
2023-10-24T06:06:15.456Z        DEBUG   controller.machine.disruption   marking empty   {"commit": "322822a", "machine": "default-26t9h"}
2023-10-24T06:06:47.217Z        INFO    controller.deprovisioning       deprovisioning via emptiness delete, terminating 1 machines ip-192-168-6-44.ap-northeast-2.compute.internal/c5.large/on-demand        {"commit": "322822a"}
2023-10-24T06:06:47.310Z        INFO    controller.termination  cordoned node   {"commit": "322822a", "node": "ip-192-168-6-44.ap-northeast-2.compute.internal"}
2023-10-24T06:06:47.691Z        INFO    controller.termination  deleted node    {"commit": "322822a", "node": "ip-192-168-6-44.ap-northeast-2.compute.internal"}
2023-10-24T06:06:48.027Z        INFO    controller.machine.termination  deleted machine {"commit": "322822a", "machine": "default-26t9h", "provisioner": "default", "node": "ip-192-168-6-44.ap-northeast-2.compute.internal", "provider-id": "aws:///ap-northeast-2b/i-0510xxxxxxx"}
  1. 06분 15초에 삭제 명령 후 30초 동안 대기 
  2. 06분 47초에 삭제 감지 및 삭제 시작
  3. 06분 48초에 삭제 완료

전체 33초가 걸리는 걸 확인할 수 있다.

다음은 Cluster Autoscaler에 의해 노드가 scale in 되고 노드가 삭제되는 시간을 측정한 것이다.

$ kubectl logs -n kube-system deploy/cluster-autoscaler -f
...
I1024 05:57:59.329599       1 nodes.go:84] ip-192-168-6-88.ap-northeast-2.compute.internal is unneeded since 2023-10-24 05:57:49.277545087 +0000 UTC m=+179.765064944 duration 30.051491745s
I1024 05:57:59.354523       1 delete.go:103] Successfully added ToBeDeletedTaint on node ip-192-168-6-88.ap-northeast-2.compute.internal
I1024 05:57:59.354552       1 actuator.go:161] Scale-down: removing empty node "ip-192-168-6-88.ap-northeast-2.compute.internal"
I1024 05:57:59.354795       1 event_sink_logging_wrapper.go:48] Event(v1.ObjectReference{Kind:"Node", Namespace:"", Name:"ip-192-168-6-88.ap-northeast-2.compute.internal", UID:"32b6e1af-7259-4649-b77f-521a810e127c", APIVersion:"v1", ResourceVersion:"1884078", FieldPath:""}): type: 'Normal' reason: 'ScaleDown' marked the node as toBeDeleted/unschedulable
I1024 05:57:59.355008       1 actuator.go:244] Scale-down: waiting 5s before trying to delete nodes
I1024 05:57:59.365594       1 event_sink_logging_wrapper.go:48] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"kube-system", Name:"cluster-autoscaler-status", UID:"b75c3801-f56e-4d33-a0f4-8e49910776ab", APIVersion:"v1", ResourceVersion:"1884079", FieldPath:""}): type: 'Normal' reason: 'ScaleDownEmpty' Scale-down: removing empty node "ip-192-168-6-88.ap-northeast-2.compute.internal"
I1024 05:58:04.536062       1 auto_scaling_groups.go:311] Terminating EC2 instance: i-006e78851436dc4dd
I1024 05:58:04.536080       1 aws_manager.go:161] DeleteInstances was called: scheduling an ASG list refresh for next main loop evaluation
I1024 05:58:04.536206       1 event_sink_logging_wrapper.go:48] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"kube-system", Name:"cluster-autoscaler-status", UID:"b75c3801-f56e-4d33-a0f4-8e49910776ab", APIVersion:"v1", ResourceVersion:"1884120", FieldPath:""}): type: 'Normal' reason: 'ScaleDownEmpty' Scale-down: empty node ip-192-168-6-88.ap-northeast-2.compute.internal removed

  1. 57분 29초에 삭제 명령 후 30초 동안 대기 -> 로그 참고
  2. 57분 59초에 삭제 감지 후 5초 대기  -> 로그 참고
  3. 58분 04초에 삭제 시작 (ASG Desired 값 축소) -> 로그 및 그림 참고
  4. 58분 49초에 삭제 완료  -> 그림 참고

전체 80초가 걸리는 걸 확인할 수 있다.

 

scale in 속도 차이 결과

  • Karpenter : 33초 >  Cluster Autoscaler : 80초 

 

마치며


현재 환경에서 테스트 결과를 통해 Karpenter의 Auto Scaling 속도가 가장 빠른 걸 확인할 수 있었다. 또한, Auto Scaling Group에서 Warm Pool을 구성하면 scale out 속도가 개선됨을 확인할 수 있었다. Auto Scaling 속도는 실행할 때마다 또는 환경에 따라 약간씩 다를 수 있으니 참고하자.

반응형

댓글