Skip to main content

Karpenter 운영 및 삭제

설치된 Karpenter의 상태를 확인하고 노드 정책, 버전 업데이트 및 삭제를 관리합니다.

상태 확인​

Karpenter 컨트롤러와 주요 리소스의 상태를 확인합니다.

Karpenter 상태 확인
kubectl -n karpenter-kakaocloud get deployment,pod
kubectl get kcnodeclass
kubectl get nodepool
kubectl get nodeclaims
kubectl get nodes -l karpenter.sh/nodepool

리소스가 준비되지 않았거나 노드 생성·회수가 지연되면 Karpenter 문제 해결에서 이벤트와 로그를 확인합니다.

노드 생성 및 회수 정책 설정​

NodePool의 requirements와 limits로 노드 생성 조건과 리소스 상한을 설정합니다. 클러스터 전체 상한은 제공되지 않으므로 모든 NodePool에 limits를 지정합니다.

주요 설정은 다음과 같습니다.

설정위치설명
인스턴스 조건spec.template.spec.requirements인스턴스 유형, 가용 영역, CPU, 메모리 등의 후보를 제한
리소스 상한spec.limitsNodePool이 생성할 수 있는 CPU, 메모리 및 GPU 총량 제한
통합 정책spec.disruption.consolidationPolicy비어 있거나 사용량이 낮은 노드의 회수 기준 설정
통합 대기 시간spec.disruption.consolidateAfter통합 조건이 충족된 후 회수 전까지 대기할 시간
노드 만료spec.template.spec.expireAfter노드를 교체할 최대 사용 기간, 기본값 720h
종료 유예spec.template.spec.terminationGracePeriod노드 drain에 허용할 최대 시간

인스턴스 유형이나 가용 영역을 제한하려면 requirements에 다음 키를 추가합니다.

목적requirement 키값 예시
인스턴스 유형node.kubernetes.io/instance-typem2a.large
가용 영역topology.kubernetes.io/zonekr-central-2-a
인스턴스 패밀리karpenter.kakaocloud.com/instance-familym2a
vCPUkarpenter.kakaocloud.com/instance-cpu4
메모리karpenter.kakaocloud.com/instance-memory16384(MiB)

KCNodeClass의 서브넷과 다른 가용 영역을 지정하거나 조건을 지나치게 제한하면 노드가 생성되지 않을 수 있습니다. 다른 클라우드 공급자의 requirement 키는 사용하지 않습니다.

consolidationPolicy는 WhenEmpty 또는 WhenEmptyOrUnderutilized로 설정할 수 있습니다. 잦은 생성과 회수를 방지하려면 워크로드의 특성을 고려하여 consolidateAfter를 설정합니다.

PodDisruptionBudget의 ALLOWED DISRUPTIONS가 0이거나 파드에 karpenter.sh/do-not-disrupt annotation이 있으면 노드 회수가 지연될 수 있습니다.

expireAfter에 따른 만료는 중단 예산이나 do-not-disrupt로 차단되지 않습니다. 장시간 실행되는 작업에는 충분한 만료 시간 또는 Never를 설정합니다.

로드 밸런서에 연결된 워크로드는 복제본, readiness probe, PodDisruptionBudget 및 종료 유예 시간을 구성하고, 노드 회수 중에도 트래픽이 정상 처리되는지 검증합니다.

Karpenter Provider의 기본 비용 값은 실제 청구 요금이 아닌 인스턴스 선택을 위한 상대 값입니다. 실제 요금이 가장 낮은 인스턴스가 항상 선택되는 것은 아니므로 Virtual Machine 서비스 요금 및 쿼터를 기준으로 비용을 확인합니다.

Karpenter가 생성한 Virtual Machine의 이름과 설명은 변경하지 않습니다. 소유권 확인과 잔여 인스턴스 식별에 사용되므로 변경하면 인스턴스 회수에 실패할 수 있습니다.

모니터링 및 알림 설정​

Prometheus Operator가 설치된 클러스터에서는 Karpenter Provider의 메트릭과 알림 규칙을 사용할 수 있습니다. serviceMonitor.enabled와 prometheusRule.enabled의 기본값은 auto이며, 관련 CRD가 있을 때만 오브젝트가 생성됩니다.

serviceMonitor.additionalLabels와 prometheusRule.additionalLabels를 Prometheus의 선택 조건에 맞게 설정합니다. 레이블이 일치하지 않으면 메트릭과 알림 규칙이 적용되지 않습니다.

karpenter-monitoring-values.yaml
serviceMonitor:
enabled: true
additionalLabels:
release: <PROMETHEUS_RELEASE_LABEL>

prometheusRule:
enabled: true
additionalLabels:
release: <PROMETHEUS_RELEASE_LABEL>
alertLabels:
team: <TEAM_NAME>
service: karpenter
runbookBaseURL: <RUNBOOK_URL>

현재 설치 값을 유지하여 모니터링 설정을 적용합니다.

Karpenter 모니터링 설정 적용
helm upgrade karpenter-provider-kakaocloud \
oci://ke-container-registry.kr-central-2.kcr.dev/ke-helm-public/karpenter-provider-kakaocloud \
--version '<INSTALLED_CHART_VERSION>' \
--namespace karpenter-kakaocloud \
--reuse-values \
-f karpenter-monitoring-values.yaml

Kubernetes 버전 및 워커 이미지와 관련된 주요 알림은 다음과 같습니다.

  • KarpenterNodeClassKubernetesVersionSkewed (info): 워커 버전이 컨트롤 플레인보다 한 단계 낮은 상태가 지속됩니다. KCNodeClass 버전을 맞추고 노드를 교체합니다.
  • KarpenterNodeClassKubernetesVersionDeprecated (info): 사용 중인 워커 버전을 Kubernetes Engine에서 더 이상 제공하지 않습니다. 지원 버전으로 변경할 일정을 수립합니다.
  • KarpenterNodeClassImagesRetained (warning): 현재 버전의 이미지를 조회하지 못해 이전에 확인한 이미지를 사용 중입니다. 지원 버전으로 변경하거나 검증된 이미지 ID를 지정합니다.

info 알림은 즉시 장애 대응이 필요한 상태를 뜻하지 않습니다. 알림을 외부로 전달하려면 prometheusRule.alertLabels와 일치하는 Alertmanager 경로와 수신 대상을 설정합니다.

Kubernetes 버전 업데이트​

Kubernetes 버전 업데이트 순서

컨트롤 플레인 업데이트 전에 모든 Karpenter 노드를 현재 컨트롤 플레인과 같은 마이너 버전으로 맞춥니다. NotReady 상태와 등록 중인 노드를 포함해 한 대라도 버전이 다르면 업데이트 요청이 거부됩니다.

  1. Karpenter 노드의 Kubernetes 버전을 확인합니다.

    Karpenter 노드 Kubernetes 버전 확인
    kubectl get nodes -l karpenter.sh/nodepool
  2. 현재 컨트롤 플레인보다 한 단계 낮은 노드가 있으면 해당 KCNodeClass의 spec.bootstrap.kubernetesVersion을 현재 컨트롤 플레인 버전으로 변경합니다.

    KCNodeClass Kubernetes 버전 변경
    kubectl edit kcnodeclass <KCNODECLASS_NAME>
  3. 기존 노드의 드리프트 교체가 완료되고, 모든 Karpenter 노드가 현재 컨트롤 플레인과 같은 마이너 버전인지 확인합니다.

  4. Kubernetes Engine 컨트롤 플레인을 업데이트합니다. 업데이트 중에는 KCNodeClass의 KubernetesVersionReady와 ImagesReady가 False가 되어 신규 노드 생성이 일시적으로 중단될 수 있으며, 기존 노드와 파드는 계속 실행됩니다.

  5. 클러스터가 안정된 상태로 돌아오고 KCNodeClass의 KubernetesVersionReady와 ImagesReady가 True인지 확인합니다.

    KCNodeClass 조건 확인
    kubectl get kcnodeclass <KCNODECLASS_NAME> \
    -o jsonpath='{range .status.conditions[*]}{.type}{"\t"}{.status}{"\t"}{.reason}{"\n"}{end}'
  6. KCNodeClass의 spec.bootstrap.kubernetesVersion을 새 컨트롤 플레인 버전으로 변경하고 노드가 순차적으로 교체되는지 확인합니다.

spec.bootstrap.kubernetesVersion을 변경하면 해당 KCNodeClass로 생성된 노드가 드리프트 교체 대상이 됩니다. 변경 전에 워크로드의 복제본 수, PodDisruptionBudget 및 중단 가능 시간을 확인합니다.

지원 종료된 Kubernetes 버전을 사용하는 경우​

Kubernetes Engine에서 특정 Kubernetes 버전의 신규 제공을 종료해도 해당 버전을 사용 중인 KCNodeClass는 계속 동작합니다. 기존 노드뿐 아니라 신규 노드도 생성할 수 있습니다.

지원 종료 상태는 KCNodeClass의 KubernetesVersionDeprecated=True 조건과 WorkerVersionNotOffered reason으로 확인합니다. Kubernetes Event와 KarpenterNodeClassKubernetesVersionDeprecated 알림에도 표시됩니다.

지원 종료된 버전은 새 KCNodeClass를 생성하거나 기존 KCNodeClass의 버전을 변경할 때 지정할 수 없습니다. 컨트롤 플레인과의 호환성을 확인한 후 Kubernetes Engine에서 제공하는 버전으로 업데이트합니다.

지정한 버전에 맞는 워커 이미지를 조회할 수 없으면 Karpenter는 이전에 확인한 이미지를 사용합니다. 이때 ImagesReady=True, reason은 ImagesRetained로 표시되며 신규 노드 생성은 계속됩니다.

이 상태는 자동으로 해제되지 않습니다. 지원 버전으로 변경하거나 spec.imageID에 검증된 워커 이미지 ID를 지정합니다.

Karpenter Provider 업그레이드​

Provider를 업그레이드하기 전에 모든 KCNodeClass의 워커 버전이 컨트롤 플레인과 같거나 한 단계 낮은지 확인합니다.

허용 범위를 벗어난 KCNodeClass는 업그레이드 후 Ready=False가 되어 신규 노드를 생성할 수 없습니다. 해당 버전을 변경하고 노드 교체를 완료한 뒤 업그레이드합니다.

현재 설정을 백업하고 릴리스 정보를 확인합니다.

Karpenter 리소스 백업
kubectl get nodepool -o yaml > nodepools-before-upgrade.yaml
kubectl get kcnodeclass -o yaml > kcnodeclasses-before-upgrade.yaml
helm get values karpenter-provider-kakaocloud \
-n karpenter-kakaocloud > karpenter-values-before-upgrade.yaml

Helm은 업그레이드할 때 crds 디렉터리의 CRD를 자동으로 갱신하지 않습니다. Provider 릴리스에서 CRD 변경을 안내하는 경우 새 차트의 CRD를 먼저 적용합니다.

Karpenter CRD 업데이트
helm pull \
oci://ke-container-registry.kr-central-2.kcr.dev/ke-helm-public/karpenter-provider-kakaocloud \
--version '<NEW_CHART_VERSION>' \
--untar

kubectl apply -f karpenter-provider-kakaocloud/crds/

현재 설치 값을 유지하여 Provider를 업그레이드합니다.

Karpenter Provider 업그레이드
helm upgrade karpenter-provider-kakaocloud \
oci://ke-container-registry.kr-central-2.kcr.dev/ke-helm-public/karpenter-provider-kakaocloud \
--version '<NEW_CHART_VERSION>' \
--namespace karpenter-kakaocloud \
--reuse-values \
--wait \
--timeout 10m

설치 시 controller.image.* 값을 직접 지정한 경우 --reuse-values에 의해 기존 이미지 설정이 유지될 수 있습니다. 새 차트에 포함된 컨트롤러 이미지를 사용하려면 기존 이미지 재정의 값을 제거하거나 새 이미지 값을 함께 지정합니다.

업그레이드 후 컨트롤러 파드, KCNodeClass와 NodePool의 Ready 상태, 신규 노드 생성과 회수를 확인합니다. 롤백이 필요한 경우 helm history로 리비전을 확인한 후 helm rollback을 실행합니다.

IAM 액세스 키 및 서명 키 변경​

Provider 업그레이드 중에는 서명 키 Secret을 변경하거나 다시 생성하지 않습니다.

IAM 액세스 키를 교체할 때는 새 키로 Secret을 갱신하고 컨트롤러를 재시작합니다. KCNodeClass가 Ready 상태를 유지하는지 확인한 후 기존 키를 폐기합니다.

서명 키를 교체해야 할 때는 기존 키를 키링에서 제거하지 않은 상태로 새 키를 추가하고 새 키를 activeKeyID로 지정합니다. 기존 키로 생성된 인스턴스가 모두 교체된 것을 확인한 후에만 이전 키를 제거합니다.

Karpenter 리소스 삭제​

Kubernetes Engine 클러스터를 유지할지 삭제할지에 따라 아래 두 절차 중 하나만 따릅니다.

클러스터를 유지하는 경우​

Karpenter 노드는 관리형 노드 풀에 포함되지 않습니다. Kubernetes Engine 노드 삭제 API 대신 NodeClaim을 삭제하여 노드를 회수합니다.

먼저 모든 NodePool의 CPU 상한을 0으로 변경하여 새 노드 생성을 차단합니다. NodePool별로 실행하며, 작업 중 새 파드는 Pending 상태로 남을 수 있습니다.

신규 노드 생성 차단
kubectl get nodepool
kubectl patch nodepool <NODEPOOL_NAME> --type merge \
-p '{"spec":{"limits":{"cpu":"0"}}}'
삭제 순서

NodeClaim과 인스턴스가 모두 삭제된 후 Karpenter Provider의 Helm 릴리스를 삭제합니다. 컨트롤러를 먼저 삭제하면 인스턴스와 볼륨이 남아 요금이 계속 부과될 수 있습니다.

  1. Karpenter 노드에서 실행 중인 워크로드를 다른 노드로 이전하거나 삭제합니다.

  2. NodeClaim을 삭제합니다. 컨트롤러가 노드를 drain한 뒤 연결된 인스턴스를 삭제합니다. NodePool이 여러 개라면 각각 실행합니다.

    NodeClaim 삭제
    kubectl delete nodeclaims \
    -l karpenter.sh/nodepool=<NODEPOOL_NAME>
  3. NodeClaim과 Karpenter 노드가 모두 삭제되었는지 확인합니다. 카카오클라우드 콘솔의 Virtual Machine > 인스턴스와 볼륨에서도 잔여 리소스를 확인합니다.

    NodeClaim 및 노드 삭제 확인
    kubectl get nodeclaims
    kubectl get nodes -l karpenter.sh/nodepool

    삭제가 지연되면 PodDisruptionBudget, do-not-disrupt annotation 및 해당 NodeClaim의 이벤트를 확인합니다.

  4. NodePool과 KCNodeClass를 삭제한 뒤 Karpenter Provider를 제거합니다. 다른 NodePool이 참조하는 KCNodeClass는 삭제하지 않습니다.

    Karpenter 리소스 삭제
    kubectl delete nodepool <NODEPOOL_NAME>
    kubectl delete kcnodeclass <KCNODECLASS_NAME>
    helm uninstall karpenter-provider-kakaocloud \
    --namespace karpenter-kakaocloud
  5. 인스턴스와 볼륨이 남아 있지 않은지 다시 확인한 후 네임스페이스를 삭제하고, Karpenter 전용 IAM 액세스 키를 폐기합니다.

    Karpenter 네임스페이스 삭제
    kubectl delete namespace karpenter-kakaocloud

CRD와 서명 키 백업까지 정리하려면 CRD 및 서명 키 정리를 참고하시기 바랍니다.

Argo CD와 같은 GitOps 도구를 사용한다면 NodeClaim과 인스턴스가 모두 삭제된 뒤 NodePool 매니페스트를 저장소에서 제거합니다.

클러스터를 삭제하는 경우​

클러스터를 삭제할 때는 NodeClaim을 개별 삭제하지 않고 아래 절차를 따릅니다. Karpenter가 생성한 Virtual Machine도 삭제 대상에 포함됩니다.

다만 이름이나 설명이 변경되었거나 NodeClaim과 연결되지 않은 인스턴스, 별도로 유지하도록 설정한 볼륨은 남을 수 있습니다. 삭제 후 잔여 리소스를 반드시 확인합니다.

  1. 삭제 후 남은 리소스를 식별할 수 있도록 NodeClaim 이름과 provider ID를 저장합니다. 카카오클라우드 콘솔에서 Karpenter 인스턴스와 연결된 볼륨의 이름 및 ID도 기록합니다.

    삭제 전 NodeClaim 정보 저장
    kubectl get nodeclaims \
    -o custom-columns='NODECLAIM:.metadata.name,PROVIDER_ID:.status.providerID' \
    > karpenter-before-cluster-delete.txt
  2. Karpenter Provider를 삭제하고 컨트롤러 파드가 종료되었는지 확인합니다.

    Karpenter Provider 종료 확인
    helm uninstall karpenter-provider-kakaocloud \
    --namespace karpenter-kakaocloud

    kubectl -n karpenter-kakaocloud get pods \
    -l app.kubernetes.io/name=karpenter-provider-kakaocloud
  3. Kubernetes Engine 콘솔 또는 API에서 클러스터를 삭제합니다. Karpenter 인스턴스가 남아 있는 동안 클러스터가 Deleting 상태에 머무를 수 있습니다.

  4. 클러스터 삭제 후 카카오클라우드 콘솔의 Virtual Machine > 인스턴스와 볼륨에서 남은 리소스를 확인합니다. 자동으로 삭제되지 않은 리소스가 있다면 잔여 리소스 식별에 따라 해당 클러스터의 리소스인지 확인한 뒤 정리합니다.

  5. Karpenter 전용 IAM 액세스 키를 폐기합니다. 다른 용도로도 사용하는 키는 폐기하지 않습니다.