Karpenter 소개 – 오픈 소스 고성능 Kubernetes 클러스터 오토스케일러
이제 Karpenter를 프로덕션에 적용할 준비를 마쳤습니다. Karpenter는 AWS로 구축된 유연한 오픈 소스의 고성능 Kubernetes 클러스터 오토스케일러입니다. 애플리케이션 로드의 변화에 대응하여 적절한 크기의 컴퓨팅 리소스를 신속하게 실행함으로써 애플리케이션 가용성과 클러스터 효율성을 개선할 수 있습니다. 또한 Karpenter는 애플리케이션의 요구 사항을 충족하는 컴퓨팅 리소스를 적시에 제공하며, 앞으로 클러스터의 컴퓨팅 리소스 공간을 자동으로 최적화하여 비용을 절감하고 성능을 개하게 됩니다.
Karpenter 이전에는 Kubernetes 사용자가 Amazon EC2 Auto Scaling 그룹과 Kubernetes Cluster Autoscaler를 사용하는 애플리케이션을 지원하기 위해 클러스터의 컴퓨팅 파워를 동적으로 조정해야 했습니다. AWS를 사용하는 Kubernetes 고객 중 거의 절반이 Kubernetes Cluster Autoscaler를 사용하여 클러스터 Auto Scaling을 구성하기가 어렵고 구성할 수 있는 범위가 제한적이라고 토로합니다.
Karpenter가 클러스터에 설치되면 Karpenter는 예약되지 않은 포드의 전체 리소스 요청을 관찰하고 새 노드를 시작하고 종료하는 결정을 내림으로써 예약 대기 시간과 인프라 비용을 줄입니다. 이를 위해 Karpenter는 Kubernetes 클러스터 내의 이벤트를 관찰한 다음 Amazon EC2와 같은 기본 클라우드 공급자의 컴퓨팅 서비스로 명령을 전송합니다.
Karpenter는 Apache License 2.0을 통해 라이선스가 부여되는 오픈 소스 프로젝트입니다. 모든 주요 클라우드 공급업체 및 온프레미스 환경을 포함하여, 모든 환경에서 실행되는 모든 Kubernetes 클러스터와 함께 작동하도록 설계되었습니다. 추가 클라우드 공급자를 구축하거나 핵심 프로젝트 기능을 개선하는 데 있어 여러분의 참여를 기다립니다. 버그를 찾거나, 제안 사항이 있거나, 참여하고 싶은 부분이 있다면 GitHub에서 저희와 협력해 주시기 바랍니다.
AWS에서 Karpenter 시작하기
Kubernetes 클러스터에서 Karpenter를 시작하려면 사용 가능한 컴퓨팅 용량이 있는지 확인하고 퍼블릭 리포지토리에서 제공하는 Helm 차트를 사용하여 설치하세요. 또한 Karpenter를 사용하려면 선택한 공급자에 컴퓨팅 리소스를 프로비저닝할 수 있는 권한이 필요합니다.
기본 Karpenter 프로비저너가 클러스터에 설치되면, 클러스터의 컴퓨팅 리소스 부족으로 인해 예약할 수 없는, 들어오는 Kubernetes 포드를 관찰하고 예약 및 리소스 요구 사항에 맞게 새 리소스를 자동으로 시작합니다.
여기서는 AWS에서 Karpenter 시작하기의 내용을 바탕으로 Amazon EKS 클러스터에서 Karpenter 사용을 빠르게 시작하는 방법을 보여 드리고자 합니다. 이를 위해서는 AWS Command Line Interface(AWS CLI), kubectl, eksctl, Helm(Kubernetes의 패키지 관리자)을 설치해야 한다. 이들 도구를 설정한 후 eksctl
을 사용하여 클러스터를 생성합니다. 이 예제 구성 파일은 하나의 초기 노드가 있는 기본 클러스터를 지정합니다.
cat <<EOF > cluster.yaml
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: eks-karpenter-demo
region: us-east-1
version: "1.20"
managedNodeGroups:
- instanceType: m5.large
amiFamily: AmazonLinux2
name: eks-kapenter-demo-ng
DesiredCapacity: 1
minSize: 1
maxSize: 5
EOF
$ eksctl create cluster -f cluster.yaml
Karpenter 자체는 자체 관리형 노드 그룹, 관리형 노드 그룹 또는 AWS Fargate를 비롯하여 어디에서나 실행할 수 있습니다. Karpenter는 계정에 EC2 인스턴스를 프로비저닝합니다.
다음으로 Karpenter 컨트롤러가 문서에 따라 인스턴스를 시작하는 등의 권한을 얻으려면, 필요한 AWS CloudFormation 템플릿과 서비스 계정을 위한 IAM 역할(IRSA)을 사용하여 필요한 AWS Identity and Access Management(IAM) 리소스를 생성해야 합니다. 또한 Karpenter를 클러스터에 배포하려면 Helm 차트를 설치해야 합니다.
$ helm repo add karpenter https://charts.karpenter.sh
$ helm repo update
$ helm upgrade --install --skip-crds karpenter karpenter/karpenter --namespace karpenter
--create-namespace --set serviceAccount.create=false --version 0.5.0
--set controller.clusterName=eks-karpenter-demo
--set controller.clusterEndpoint=$(aws eks describe-cluster --name eks-karpenter-demo --query "cluster.endpoint" --output json)
--wait # for the defaulting webhook to install before creating a Provisioner
Karpenter 프로비저너는 클러스터에서 Karpenter의 동작을 구성할 수 있게 해주는 Kubernetes 리소스입니다. 기본 프로비저너를 만들면 Karpenter가 클러스터에서 컴퓨팅 리소스를 프로비저닝하는 데 필요한 설정 외에 추가 사용자 지정 없이, 인스턴스 유형, 영역, 아키텍처, 운영 체제, 인스턴스 구매 유형 등의 노드 속성을 자동으로 검색합니다. 명시적인 비즈니스 요구 사항이 아닌 경우 이러한 spec:requirements를 정의할 필요가 없습니다.
cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: default
spec:
#프로비저닝된 노드의 파라미터를 제한하는 요구 사항
#연산자 { In, NotIn }은 값을 포함하거나 제외할 수 있도록 하기 위해 지원됨
requirements:
- key: node.k8s.aws/instance-type #If not included, all instance types are considered
operator: In
values: ["m5.large", "m5.2xlarge"]
- key: "topology.kubernetes.io/zone" #If not included, all zones are considered
operator: In
values: ["us-east-1a", "us-east-1b"]
- key: "kubernetes.io/arch" #If not included, all architectures are considered
values: ["arm64", "amd64"]
- key: " karpenter.sh/capacity-type" #If not included, the webhook for the AWS cloud provider will default to on-demand
operator: In
values: ["spot", "on-demand"]
provider:
instanceProfile: KarpenterNodeInstanceProfile-eks-karpenter-demo
ttlSecondsAfterEmpty: 30
EOF
ttlSecondsAfterEmpty
값은 Karpenter가 빈 노드를 종료하도록 구성합니다. 이 값을 사용 중지하면 사용률이 낮아도 노드가 축소되지 않습니다. 자세한 내용은 Karpenter 사이트의 프로비저너 사용자 지정 리소스 정의(CRD)를 참조하세요.
이제 Karpenter가 활성화되어 클러스터에서 노드 프로비저닝을 시작할 준비가 되었습니다. 배포를 사용하여 포드를 생성하고 그에 따른 Karpenter 프로비저닝 노드의 동작을 관찰합니다.
$ kubectl create deployment --name inflate
--image=public.ecr.aws/eks-distro/kubernetes/pause:3.2
배포를 확장하고 Karpenter 컨트롤러의 로그를 확인해 보겠습니다.
$ kubectl scale deployment inflate --replicas 10
$ kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)
2021-11-23T04:46:11.280Z INFO controller.allocation.provisioner/default Starting provisioning loop {"commit": "abc12345"}
2021-11-23T04:46:11.280Z INFO controller.allocation.provisioner/default Waiting to batch additional pods {"commit": "abc123456"}
2021-11-23T04:46:12.452Z INFO controller.allocation.provisioner/default Found 9 provisionable pods {"commit": "abc12345"}
2021-11-23T04:46:13.689Z INFO controller.allocation.provisioner/default Computed packing for 10 pod(s) with instance type option(s) [m5.large] {"commit": " abc123456"}
2021-11-23T04:46:16.228Z INFO controller.allocation.provisioner/default Launched instance: i-01234abcdef, type: m5.large, zone: us-east-1a, hostname: ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:46:16.265Z INFO controller.allocation.provisioner/default Bound 9 pod(s) to node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:46:16.265Z INFO controller.allocation.provisioner/default Watching for pod events {"commit": "abc12345"}
프로비저너의 컨트롤러가 포드 변경 사항을 수신하여 새 인스턴스를 시작하고 프로비저닝 가능한 포드를 새 노드에 바인딩했습니다.
이제 배포를 삭제합니다. 30초 후(ttlSecondsAfterEmpty = 30
), Karpenter는 빈 노드를 종료해야 합니다.
$ kubectl delete deployment inflate
$ kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)
2021-11-23T04:46:18.953Z INFO controller.allocation.provisioner/default Watching for pod events {"commit": "abc12345"}
2021-11-23T04:49:05.805Z INFO controller.Node Added TTL to empty node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:49:35.823Z INFO controller.Node Triggering termination after 30s for empty node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:49:35.849Z INFO controller.Termination Cordoned node ip-192-168-116-109.ec2.internal {"commit": "abc12345"}
2021-11-23T04:49:36.521Z INFO controller.Termination Deleted node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
kubectl로 노드를 삭제하면, Karpenter는 해당 인스턴스를 적절하게 묶고, 드레이닝하고, 종료합니다. 내부적으로 Karpenter는 모든 포드가 드레이닝되고 인스턴스가 종료될 때까지 삭제를 차단하는 종료자를 노드 객체에 추가합니다.
주요 사항
Kapenter 기능에 관해 유의해야 할 점을 몇 가지 소개합니다.
가속 컴퓨팅: Karpenter는 모든 종류의 Kubernetes 애플리케이션과 호환되지만, 다양한 컴퓨팅 리소스를 신속하게 프로비저닝하고 프로비저닝 해제해야 하는 사용 사례에 특히 적합합니다. 예를 들어 여기에는 기계 학습 모델을 훈련하거나 시뮬레이션을 실행하거나 복잡한 재무 계산을 수행하기 위한 배치 작업이 포함됩니다. 가속화된 EC2 인스턴스가 필요한 사용 사례에 대해 nvidia.com/gpu, amd.com/gpu, and aws.amazon.com/neuron의 사용자 지정 리소스를 활용할 수 있습니다.
프로비저너 호환성: Kapenter 프로비저너는 Amazon EKS 관리형 노드 그룹 및 EC2 Auto Scaling 그룹과 같은 정적 용량 관리 솔루션과 호환되도록 설계되었습니다. 프로비저너, 동적 용량과 정적으로 관리되는 용량을 모두 포함하는 혼합 모델 또는 완전 정적 접근 방식을 사용하여 전체 용량을 관리하도록 선택할 수 있습니다. Karpenter와 Kubernetes Cluster Autoscaler를 동시에 사용하지 않는 것이 좋습니다. 두 시스템 모두 예약 불가능한 포드에 대한 대응으로 노드를 확장하기 때문입니다. 함께 구성한 경우 두 시스템 모두 이러한 포드의 인스턴스를 시작하거나 종료하기 위해 경합합니다.
Karpenter 커뮤니티 가입
Karpenter의 커뮤니티는 누구에게나 열려 있습니다. 커뮤니티에서 워킹 그룹 미팅에 참여하거나 관심 있는 향후 릴리스에 대한 로드맵을 살펴보세요. 앞서 말했듯이 버그 리포트, 새로운 기능, 수정 사항, 추가 문서 등 모든 형태의 참여를 환영합니다.
Karpenter에 대해 자세히 알아보려면 AWS Container Day의 문서 및 데모 동영상을 참조하세요.
– Channy