Auto Scaling Group(ASG)와 Karpenter의 auto scaling이 발생하는 속도에서 꽤 많은 차이를 보인다.
그렇다면, ASG를 사용하는 환경에서 속도를 줄일 수 있는 방법은 없을까? 생각하다 한 가지 기능을 발견하여 테스트해 보았다. 바로 Warm Pool 기능이다.
Auto Scaling Group(ASG)의 Warm Pool 기능은 노드를 미리 초기화하고, 초기화된 노드는 시작되었다가 중지(Stop) 상태로 대기하게 된다. 그런 상태에서 Scale-out이 발생하여 desired 값이 증가하면 중지 상태로 대기하고 있던 노드를 구동시킨다.
Warm Pool에 있는 노드는 대기 상태이기 때문에 Scale-out 발생하는 데 필요한 시간을 줄일 수 있고, 대기 상태에 있는 노드는 추가 비용을 발생시키지 않기 때문에 비용 효율적으로 관리할 수 있다.
아래 그림 참고.
왼쪽은 일반적인 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 클러스터
- Terraform CLI 도구
- Cluster Autoscaler 구성
- [Karpenter 구성]
구성 환경
- AWS EKS : 1.24.17
- Terraform : v1.6.6
구성 버전
- Custer Autoscaler: 1.26.2
- Karpenter : 0.31.0
실습 절차
1. Auto Scaling Group구성 및 Warm Pool 설정2. Auto Scaling 속도 비교
2-1. Scale out 속도 비교
2-2. Scale in 속도 비교
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"}
- 06분 15초에 삭제 명령 후 30초 동안 대기
- 06분 47초에 삭제 감지 및 삭제 시작
- 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
- 57분 29초에 삭제 명령 후 30초 동안 대기 -> 로그 참고
- 57분 59초에 삭제 감지 후 5초 대기 -> 로그 참고
- 58분 04초에 삭제 시작 (ASG Desired 값 축소) -> 로그 및 그림 참고
- 58분 49초에 삭제 완료 -> 그림 참고
전체 80초가 걸리는 걸 확인할 수 있다.
scale in 속도 차이 결과
- Karpenter : 33초 > Cluster Autoscaler : 80초
마치며
현재 환경에서 테스트 결과를 통해 Karpenter의 Auto Scaling 속도가 가장 빠른 걸 확인할 수 있었다. 또한, Auto Scaling Group에서 Warm Pool을 구성하면 scale out 속도가 개선됨을 확인할 수 있었다. Auto Scaling 속도는 실행할 때마다 또는 환경에 따라 약간씩 다를 수 있으니 참고하자.
'Orchestration > Kubernetes' 카테고리의 다른 글
K8sGPT 사용하여 Kubernetes 문제 해결하기 (0) | 2024.07.03 |
---|---|
Karpenter로 AWS EKS 환경에 AutoScaling 구현하기 (0) | 2023.10.18 |
AWS EKS 노드그룹 자동 시작, 중지하기 (0) | 2023.10.17 |
EKS add-on(vpc-cni) 업그레이드 이슈 (0) | 2023.05.24 |
EKS Pod 전용 Security group (SecurityGroupPolicy) (0) | 2023.05.18 |
댓글