AWS 기술 블로그

Karpenter 통합을 이용한 Kubernetes 컴퓨팅 비용 최적화

​​본 게시글은 AWS Containers Blog의 Optimizing your Kubernetes compute costs with Karpenter consolidation by Lukonde Mwila를 한국어 번역 및 편집하였습니다.

소개

Karpenter는 Kubernetes에서 최적 노드 선택에 관련된 문제를 해결하기 위해 개발 되었습니다. Karpenter의 what-you-need-when-you-need-it(필요한 시기에 필요한 리소스를 조달 하는) 모델은 pod의 요구 사항을 기반으로 클러스터에 컴퓨팅 용량을 추가하는 것으로 Kubernetes에서 컴퓨팅 리소스를 관리하는 프로세스를 간소화 해줍니다. 최근 워크로드 통합 기능이 출시되면서 Karpenter는 이제 pod의 배치를 지속적으로 모니터링하고 최적화하여 인스턴스 리소스 사용률을 향상시키고 컴퓨팅 비용을 낮춰 줍니다.

본 게시글 에서는 Karpenter의 워크로드 통합 기능을 둘러보고, 실습 예제를 통해 Kubernetes 데이터 플레인 비용에 미치는 영향을 알아봅니다.

Karpenter 워크로드 통합

이전 버전의 Karpenter에서는 데몬셋이 아닌 pod가 없는 워커 노드만 제거 할 수 있었습니다. 시간이 지남에 따라 워크로드가 다시 스케줄링 되면 일부 워커 노드는 사용률이 낮아질 수 있습니다. 워크로드 통합 기능은 pod의 리소스 및 스케줄링 제약 조건을 준수하면서도, 최소 수량의 가장 저렴한 인스턴스로 워크로드들을 통합하여 Karpenter의 효율적이면서도 비용 효과적인 자동 스케일링 비전을 좀 더 현실화하는 것을 목표로 합니다. 워크로드 통합 기능은 Karpenter가 관리하는 Custom Resource인 Provisioner에 별도의 설정을 통해서 활성화할 수 있습니다. Provisioner는 EKS 클러스터에서 Karpenter 가 관리하는 노드의 라이프 사이클을 책임집니다. Provisioner를 통해서 사용자는 노드의 용량 제한 조건뿐만 아니라 시간 기반 만료 기능 및 워크로드의 통합과 같은 동작까지도 정의할 수 있습니다. Provisioner에서 워크로드 통합 기능이 활성화되면 Karpenter는 클러스터 워크로드를 지속적으로 모니터링하여 노드 사용률 및 비용 효율성을 높이기 위해 컴퓨팅 용량을 통합할 기회를 찾습니다. Karpenter는 지정한 모든 스케줄링 제약 조건 (pod affinity rules, topology spread constraints 등)도 준수합니다. Karpenter는 워크로드 요구 사항에 따라 노드를 프로비저닝하기 때문에 이를 정확하게 지정해 주는 것이 중요합니다. 그러기 위해서는 pod에 필요한 CPU 및 메모리 요청을 모두 추가해야 합니다. 이렇게 하면 리소스 고갈 또는 독점을 방지하는데 도움이 되는데, 특히 클러스터에서 여러 워크로드를 함께 실행할 때 도움이 됩니다. 더욱이 이는 Karpenter의 워크로드 통합 기능이 효과적으로 작동하는 데에 중요한 요구 사항입니다.

전제 조건

본 게시글의 예제를 수행하려면 다음과 같은 설정이 필요합니다.:

  • AWS에서 Kubernetes 클러스터 프로비저닝
  • 클러스터 오토스케일링을 위한 Karpenter 설치
  • eks-node-viewer 설치

이러한 구성을 자동화하려면 Karpenter를 클러스터의 애드온으로 배포하는 예제를 포함하는 Amazon EKS Blueprints for Terraform을 사용할 수 있습니다. 본 게시글의 예제를 수행하기 위해서 Terraform 소스 코드를 수정할 필요가 없습니다

Provisioners

Karpenter는 Provisioner Custom Resource Definition(CRD)을 기반으로 노드를 제어합니다. Provisioner는 컴퓨팅 용량, 인스턴스 유형, 추가적인 kubelet 설정, 리소스 제한 설정 및 기타 노드 라이프 사이클 사양과 같은 것을 지정하는 구성 파일입니다. 각각의 사용에 따라 클러스터에 여러 Provisioner 설정들을 배포할 수 있으며 서로 중복되지 않는 한 사용할 수 있습니다.

Amazon EKS Blueprints의 examples/karpenter/provisioners 폴더에 예제 Provisioner가 있습니다. 이번에 우리는 Node.js 예제 애플리케이션인 express-test를 위한 단일 Provisioner로 실습을 진행합니다. 따라서 예제 애플리케이션의 모든 pod는 전용 Provisioner가 클러스터에 배포되지 않는 한 스케줄 되지 않습니다.

Provisioner 파일은 다음과 같은 코드로 제공됩니다:

Provisioner

apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: express-test
spec:
  # 워크로드 통합을 활성화하여 불필요한 노드를 제거하고, 제거할 수 없는 경우에는 그 크기를 줄여 클러스터의 비용을 절감합니다. 
  # ttlSecondsAfterEmpty 설정과는 상호 배타적입니다.
  consolidation:
    enabled: true
  requirements:
    - key: "karpenter.sh/capacity-type" # 지정하지 않으면 AWS cloud provider 웹훅이 기본값으로 on-demand 설정 합니다.
      operator: In
      values: ["spot", "on-demand"]
    - key: "karpenter.k8s.aws/instance-cpu"
      operator: In 
      values: ["c", "m", "r"]
  provider:
    instanceProfile: KarpenterNodeInstanceProfile-alpha
    subnetSelector:
      karpenter.sh/discovery: 'alpha'
    securityGroupSelector:
      karpenter.sh/discovery/alpha: 'alpha'
  labels:
    managedBy: carpenter

kubectl apply -f provisioner.yaml 명령을 사용하여 이 파일을 저장하고 클러스터에 배포할 수 있습니다.

실습

워크로드 통합 예제

이 섹션에서는 각 pod에 하나의 CPU 코어, topology spread constraints 조건이 있는 express-test 애플리케이션을 배포합니다. 이에 더해 워크로드 매니페스트는 이전 단계에서 생성한 Provisioner가 관리하는 컴퓨팅 리소스에 스케줄 되도록 pod에 대한 nodeSelector 규칙을 지정합니다. Karpenter가 초기 노드들을 어떻게 프로비저닝하는지 확인한 후, Deployment를 변경하여 레플리카 개수를 업데이트하고 이 변경사항에 대응하는 Karpenter의 워크로드 통합을 추적합니다.

애플리케이션의 리소스 매니페스트는 다음 코드에서 지정됩니다.

Application manifest

apiVersion: apps/v1
kind: Deployment
metadata:
  name: express-test
spec:
  replicas: 20
  selector:
    matchLabels:
      app: express-test
  template:
    metadata:
      labels:
        app: express-test
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: "topology.kubernetes.io/zone"
        whenUnsatisfiable: ScheduleAnyway
        labelSelector:
          matchLabels:
            app: express-test
      nodeSelector:
        karpenter.sh/provisioner-name: express-test
      containers:
        - name: express-test
          image: lukondefmwila/express-test:1.1.4
          resources:
            requests:
              cpu: "1"
              memory: "64Mi"

Deployment를 저장하고, kubectl apply -f deployment.yaml 명령을 통해 클러스터에 적용할 수 있습니다.

그 후에는 eks-node-viewer를 사용하여 Karpenter 노드의 컴퓨팅 사용량 및 비용을 볼 수 있습니다.

Karpenter는 매니페스트에 지정된 컴퓨팅 요구사항과 스케줄링 제약 조건을 충족하는 3개의 노드 (t3.2xlarge 인스턴스 2대 및 c6a.2xlarge 1대 )를 클러스터에 프로비저닝 했습니다. 이는 8개의 CPU 코어가 있는 Spot 인스턴스이며, 각 노드는 별도의 가용 영역 (AZ)인 eu-west-1a, eu-west-1b, eu-west-1c에 프로비저닝 되었습니다. Karpenter는 20개의 (다른 여러 AZ에 분산된) 레플리카에서 요청한 CPU 코어와 데몬셋 CPU 사용량 및 kubelet을 위해 예약된 리소스를 고려하여 노드를 추가했습니다.

위의 스크린 샷에서와 같이 eks-node-viewer CLI 도구는 현재 노드 구성에서 월별로 얼마나 비용이 발생할지 보여줍니다.

다음 단계는 원래의 Deployment 매니페스트를 수정하는 것입니다. 아래와 같이 레플리카 수를 20에서 10으로 줄이고, 이에 따라 요청된 리소스 사용률이 감소합니다.

Application manifest

apiVersion: apps/v1
kind: Deployment
metadata:
  name: express-test
spec:
  replicas: 10
  ...

다시한번 kubectl apply -f deployment.yaml 명령을 통해 이러한 변경 사항을 배포할 수 있습니다.

이 시점에서 노드들의 사용률이 떨어지게 됩니다. 이전에 Karpenter는 20 개의 레플리카를 고려하여 각각 약 8개의 CPU가 사용 가능한 세 개의 노드를 추가했습니다. 이제 클러스터 비용을 줄일 수 있는 유일한 방법은 사용률이 낮은 노드를 제거하는 것입니다. 먼저 노드를 격리하고 해당 노드에서 pod들을 비웁니다.

노드를 계속 모니터링하면 이러한 일련의 이벤트가 발생하는 것을 확인할 수 있습니다. 마지막으로 pod들은 남아있는 두 개의 Spot 인스턴스에 스케줄 됩니다. 이러한 변경 사항의 결과는 다음의 이미지에서 볼 수 있습니다.

결과적으로 워크로드 통합이 활성화 된 Karpenter는 애플리케이션 워크로드를 위해 정의된 리소스 요구사항들과 topology spread constraints 들을 만족 하면서도, 세 개 중 하나의 인스턴스를 제거하여 클러스터의 컴퓨팅 비용을 최적화했습니다. 위 스크린 샷에서 보여 주는 것처럼 해당 워크로드의 데이터 플레인 비용이 감소했습니다.

운영 환경에서는 Karpenter와 함께 kubecost와 같은 도구를 사용하여 Kubernetes 비용을 모니터링하고 관리하는 것이 권장됩니다. Amazon EKS에서 비용 모니터링을 위해 kubecost를 설정하는 방법은 사용자 가이드를 참고하시기 바랍니다.

실습 리소스 정리

추가적으로 비용이 발생하지 않도록 하기 위해는 본 게시글의 예제를 위해 생성 한 모든 인프라를 제거해야 합니다. 먼저 Karpenter에 의해 생성된 노드들을 삭제해야 합니다. 이 노드들은 Provisioner CRD에 의해 관리되므로 Kubernetes 클러스터 내부에서 삭제할 수 있습니다. 그 외 나머지 인프라들은 Terraform을 통해 삭제할 수 있습니다. 터미널에서 정확한 폴더에 위치하고 있는지 확인한 후에 terraform destroy 명령을 실행해야 합니다. Amazon EKS Blueprint의 정리 단계를 따르는 방법도 있습니다.

결론

본 게시글에서는 Karpenter의 새로운 워크로드 통합 기능과 리소스 요청에 대한 모범 사례를 따르는 방법을 조합하여 Kubernetes의 데이터 플레인 비용을 줄이는 방법을 살펴봤습니다.

다음은 이 주제와 연관되어 참고하면 좋은 게시글 들 입니다:

Karpenter for Kubernetes | Karpenter vs Cluster Autoscaler

Karpenter consolidation in Kubernetes

Karpenter에 대해 자세히 알아보려면 이 문서를 읽어 보시고, Kubernetes 슬랙 채널 #karpenter 커뮤니티에 가입하시기 바랍니다.

Junhwan An

Junhwan An

안준환 솔루션즈 아키텍트는 다양한 분야의 애플리케이션 개발과 클라우드 인프라 구축 및 운영 경험을 바탕으로 고객이 AWS의 여러 서비스들을 효율적으로 이용할 수 있도록 도와드리고 있습니다.

Jungsub Shin

Jungsub Shin

신정섭 솔루션즈 아키텍트는 다양한 워크로드에 대한 개발 경험을 바탕으로 고객이 최적의 솔루션을 선택하여 비즈니스 성과를 달성할 수 있도록 고객과 함께 효율적인 아키텍처를 구성하는 역할을 수행하고 있습니다. 현재 AWS의 Container TFC에서 활동하고 있습니다.