이 문서에서는 리소스 사용률 및 비용 효율성을 최적화하기 위해 AKS(Azure Kubernetes Service) NAP(노드 자동 프로비저닝)에 대한 노드 중단 정책을 구성하는 방법을 설명합니다.
중단 구성 예제
다음은 비용 최적화와 안정성의 균형을 맞추는 NodePool에 대한 일반적인 중단 구성입니다.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
disruption:
# Consolidate underutilized nodes to optimize costs
consolidationPolicy: WhenEmptyOrUnderutilized
# Wait 30 seconds before consolidating
consolidateAfter: 30s
# Replace nodes every 7 days to get fresh instances
expireAfter: 168h
# Rate limit disruptions
budgets:
- nodes: "10%" # Allow 10% of nodes to be disrupted at once
- nodes: "0" # Block all disruptions during business hours
schedule: "0 9 * * 1-5"
duration: 8h
노드 중단 개요
노드의 워크로드가 축소되면 노드 자동 프로비저닝은 노드 풀 사양의 중단 규칙을 사용하여 해당 노드를 제거하는 시기와 방법을 결정하고 워크로드를 보다 효율적으로 다시 예약할 수 있습니다. 노드 자동 프로비전은 주로 통합 을 사용하여 최적의 Pod 배치를 위해 노드를 삭제하거나 대체합니다.
노드 자동 프로비전은 사양에 따라 노드를 최적화해야 하는 시기를 자동으로 제어하거나 , 를 사용하여 kubectl delete node
노드를 수동으로 제거할 수 있습니다.
제어 흐름
Karpenter는 각 노드에서 Kubernetes 종료자를 설정하고 프로비전하는 노드 클레임을 설정합니다. 종료자는 기본 NodeClaim을 제거하기 전에 종료 컨트롤러가 노드를 오염시키고 드레이닝하는 동안 노드 개체의 삭제를 차단합니다.
중단 방법
NAP는 자동으로 중단에 적합한 노드를 검색하고 필요할 때 교체를 스핀업합니다. 다음을 통해 중단을 트리거할 수 있습니다.
- 자동화된 메서드: 만료, 드리프트 및 통합
- 수동 메서드: kubectl을 통한 노드 삭제
- 외부 시스템: 노드 개체에 대한 요청 삭제
자동화된 중단 방법
만료
노드는 NodePool spec.disruption.expireAfter
의 값에 지정된 연령에 도달한 후 만료되고 중단된 것으로 표시됩니다.
spec:
disruption:
expireAfter: 24h # Expire nodes after 24 hours
통합
NAP는 다음 시기를 식별하여 클러스터 비용을 적극적으로 절감합니다.
- 노드가 비어 있으므로 제거할 수 있습니다.
- 워크로드가 다른 노드에서 실행될 때 노드를 제거할 수 있습니다.
- 노드를 더 저렴한 변형으로 바꿀 수 있습니다.
통합에는 다음 세 가지 메커니즘이 순서대로 수행됩니다.
- 빈 노드 통합 - 완전히 빈 노드를 병렬로 삭제합니다.
- 다중 노드 통합 - 여러 노드 삭제, 단일 대체 시작 가능
- 단일 노드 통합 - 단일 노드를 삭제하고 대체를 시작할 수 있습니다.
드리프트
Drift는 NodePool/AKSNodeClass의 변경 내용을 처리합니다. Drift의 경우 NodePool/AKSNodeClass의 값은 설정된 것과 동일한 방식으로 NodeClaimTemplateSpec/AKSNodeClassSpec에 반영됩니다. NodeClaim은 자체 소유 NodePool/AKSNodeClass의 값이 NodeClaim의 값과 일치하지 않는 경우 드리프트로 검색됩니다. Pod에 대한 업스트림 deployment.spec.template
관계와 마찬가지로 Karpenter는 NodeClaimTemplateSpec의 해시를 사용하여 소유 노드 풀 및 AKSNodeClass에 주석을 달고 드리프트를 확인합니다. 일부 특수 사례는 Karpenter 또는 CloudProvider 인터페이스를 통해 검색되며 NodeClaim/Instance/NodePool/AKSNodeClass 변경으로 트리거됩니다.
드리프트의 특수 사례
특별한 경우 드리프트는 여러 값에 해당할 수 있으며 다르게 처리해야 합니다. 확인된 필드의 드리프트는 CRD(사용자 지정 리소스 정의)를 변경하지 않고 드리프트가 발생하거나 CRD 변경으로 인해 드리프트가 발생하지 않는 경우를 만들 수 있습니다. 예를 들어 NodeClaim에 node.kubernetes.io/instance-type: Standard_D2s_v3
요구 사항이 있고 요구 사항이 변경 node.kubernetes.io/instance-type In [Standard_D2s_v3]
node.kubernetes.io/instance-type In [Standard_D2s_v3, Standard_D4s_v3]
되면 해당 값이 여전히 새 요구 사항과 호환되기 때문에 NodeClaim이 표류하지 않습니다. 반대로 NodeClaim이 NodeClaim imageFamily를 사용하지만 spec.imageFamily
필드가 변경된 경우 Karpenter는 NodeClaim을 드리프트로 검색하고 해당 사양을 충족하도록 노드를 회전합니다.
NodePool
분야 |
---|
spec.template.spec.requirements |
AKSNodeClass
몇 가지 예는 다음과 같습니다.
분야 |
---|
spec.vnetSubnetID |
spec.imageFamily |
VNet 서브넷 ID 드리프트
중요합니다
spec.vnetSubnetID
필드는 드리프트 검색을 트리거할 수 있지만 이 필드를 하나의 유효한 서브넷에서 다른 유효한 서브넷으로 수정하는 작업은 지원되지 않습니다. 이 필드는 초기 구성 중에 잘못되었거나 잘못된 서브넷 식별자를 수정하기 위한 이스케이프 해치를 제공하기 위해서만 변경할 수 있습니다.
ARM 템플릿을 통해 만든 기존 AKS NodePools와 달리 Karpenter는 ARM에서 제공하는 확장된 유효성 검사 없이 노드를 즉시 프로비전하는 CRD(사용자 지정 리소스 정의)를 적용합니다.
고객은 클러스터의 CIDR(클래스리스 Inter-Domain 라우팅) 범위를 이해하고 구성할 vnetSubnetID
때 충돌이 발생하지 않도록 할 책임이 있습니다.
유효성 검사 차이점:
- ARM 템플릿 NodePools: 포괄적인 CIDR(클래스리스 Inter-Domain 라우팅) 충돌 검색 및 네트워크 유효성 검사 포함
- Karpenter CRD: 자동 유효성 검사 없이 즉시 변경 내용 적용 - 고객 실사가 필요합니다.
고객 책임: 수정하기 전에 다음을 vnetSubnetID
확인합니다.
- 사용자 지정 서브넷이 클러스터 Pod CIDR, 서비스 CIDR 또는 Docker 브리지 CIDR과 충돌하지 않음
- 크기 조정 요구 사항에 충분한 IP 주소 용량
- 적절한 네트워크 연결 및 라우팅 구성
지원되는 사용 사례: 잘못된 서브넷 식별자(ID)만 수정
- 노드 프로비저닝을 방지하는 잘못된 형식의 서브넷 참조 수정
- 존재하지 않거나 액세스할 수 없는 서브넷을 가리키는 서브넷 식별자 업데이트
지원되지 않는 사용 사례: 유효한 서브넷 간 서브넷 마이그레이션
- 네트워크 재구성을 위해 서브넷 간에 노드 이동
- 용량 또는 성능상의 이유로 서브넷 구성 변경
지원 정책: Microsoft는 수정을 통해 vnetSubnetID
서브넷에서 서브넷 마이그레이션으로 발생하는 문제에 대한 지원을 제공하지 않습니다.
동작 필드
동작 필드는 Karpenter의 동작 방식을 지시하기 위해 NodePool에서 지나치게 아치형 설정으로 처리됩니다. 이러한 필드는 NodeClaim 또는 인스턴스의 설정에 해당하지 않습니다. 사용자는 Karpenter의 프로비전 및 중단 논리를 제어하도록 이러한 필드를 설정합니다. 이러한 필드는 NodeClaims의 원하는 상태에 매핑 되지 않으므로 동작 필드는 Drift에 대해 고려되지 않습니다.
NodePool
분야 |
---|
spec.weight |
spec.limits |
spec.disruption.* |
자세한 내용은 Drift 디자인을 읽어보세요.
NodeClaim이 Drifted
소유 노드 풀에서 표류하는 경우 Karpenter는 NodeClaims에 상태 조건을 추가합니다. 또한 Karpenter는 다음 중 하나일 경우 상태 조건을 제거합니다 Drifted
.
- 기능 게이트는
Drift
사용하도록 설정되지 않았지만 NodeClaim이 드리프트되고 Karpenter는 상태 조건을 제거합니다. - NodeClaim은 표류하지 않지만 상태 조건이 있으며 Karpenter는 이를 제거합니다.
중단 구성
NodePool의 spec.disruption
섹션을 통해 중단을 구성합니다.
spec:
disruption:
# Consolidation policy
consolidationPolicy: WhenEmptyOrUnderutilized | WhenEmpty
# Time to wait after discovering consolidation opportunity
consolidateAfter: 30s
# Node expiration time
expireAfter: Never
# Disruption budgets for rate limiting
budgets:
- nodes: "20%"
- nodes: "5"
schedule: "@daily"
duration: 10m
통합 정책
WhenEmptyOrUnderutilized
NAP는 통합을 위해 모든 노드를 고려하고 사용량이 부족하거나 비어 있는 경우 노드를 제거하거나 바꾸려고 시도합니다.
spec:
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
expireAfter: Never
WhenEmpty
NAP는 워크로드 Pod가 없는 통합 노드만 고려합니다.
spec:
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 30s
종료 유예 기간
Karpenter가 Pod가 정상적으로 종료되기를 기다리는 시간을 구성합니다. 이 설정은 Pod의 terminationGracePeriodSeconds보다 우선하며 PodDisruptionBudgets 및 karpenter.sh/do-not-disrupt 주석을 무시합니다.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
terminationGracePeriod: 30s
중단 예산
NodePool spec.disruption.budgets
을 통해 Karpenter의 중단 제한을 평가할 수 있습니다. 정의되지 않은 경우 Karpenter는 nodes: 10%
기본적으로 . 예산은 어떤 이유로든 삭제되는 노드를 고려합니다. 그들은 만료, 드리프트, 공허함 및 통합을 통해 카르펜터가 자발적인 중단에서만 차단합니다.
노드 예산
예산이 노드 중단을 차단하는지 계산할 때 Karpenter는 NodePool이 소유한 총 노드 수를 계산합니다. 그런 다음 삭제되는 노드와 NotReady인 노드를 뺍니다.
예산이 백분율 값(예: ) 20%
으로 구성된 경우 Karpenter는 허용되는 중단 수를 다음과 같이 allowed_disruptions = roundup(total * percentage) - total_deleting - total_notready
계산합니다.
NodePool에서 여러 예산의 경우 Karpenter는 각 예산의 최소값(가장 제한적)을 사용합니다.
예산 예제
세 가지 예산이 있는 다음 NodePool은 이러한 요구 사항을 정의합니다.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
expireAfter: 720h # 30 * 24h = 720h
budgets:
- nodes: "20%" # Allow 20% of nodes to be disrupted
- nodes: "5" # Cap at maximum 5 nodes
- nodes: "0" # Block all disruptions during maintenance window
schedule: "@daily"
duration: 10m
- 첫 번째 예산을 사용하면 해당 NodePool이 소유한 노드의 20개% 중단될 수 있습니다.
- 두 번째 예산은 한도의 역할을 하며 노드가 25개가 넘는 경우에만 5개의 중단을 허용합니다.
- 마지막 예산은 매일 처음 10분 동안 중단을 차단합니다.
일정 및 기간
일정은 , 등의 @yearly
@daily
@monthly
@weekly
@hourly
특수 매크로와 함께 cron 작업 구문을 사용합니다.
기간은 , 또는 160h
. 같은 10h5m
30m
복합 기간을 허용합니다. 기간과 일정을 함께 정의해야 합니다.
예산 구성 예제
유지 관리 기간 예산
업무 시간 동안 중단 방지:
budgets:
- nodes: "0"
schedule: "0 9 * * 1-5" # 9 AM Monday-Friday
duration: 8h # For 8 hours
주말 전용 중단
주말에만 중단을 허용합니다.
budgets:
- nodes: "50%"
schedule: "0 0 * * 6" # Saturday midnight
duration: 48h # All weekend
- nodes: "0" # Block all other times
점진적 출시 예산
중단률 증가 허용:
budgets:
- nodes: "1"
schedule: "0 2 * * *" # 2 AM daily
duration: 2h
- nodes: "3"
schedule: "0 4 * * *" # 4 AM daily
duration: 4h
수동 노드 중단
노드 삭제
kubectl을 사용하여 노드를 수동으로 제거할 수 있습니다.
# Delete a specific node
kubectl delete node $NODE_NAME
# Delete all NAP-managed nodes
kubectl delete nodes -l karpenter.sh/nodepool
# Delete nodes from a specific nodepool
kubectl delete nodes -l karpenter.sh/nodepool=$NODEPOOL_NAME
NodePool 삭제
NodePool은 소유자 참조를 통해 NodeClaims를 소유합니다. NAP는 소유 노드 풀이 삭제될 때 연속 삭제를 통해 노드를 정상적으로 종료합니다.
중단 컨트롤
Pod 수준 컨트롤
주석을 설정하여 NAP가 특정 Pod를 방해하지 karpenter.sh/do-not-disrupt: "true"
않도록 차단합니다.
apiVersion: apps/v1
kind: Deployment
spec:
template:
metadata:
annotations:
karpenter.sh/do-not-disrupt: "true"
이 주석은 다음 사항에 대한 자발적 중단을 방지합니다.
- 통합
- 드리프트
- 만료
노드 수준 컨트롤
NAP가 특정 노드를 중단하지 못하도록 차단합니다.
apiVersion: v1
kind: Node
metadata:
annotations:
karpenter.sh/do-not-disrupt: "true"
NodePool 수준 컨트롤
NodePool의 모든 노드에 대해 중단을 사용하지 않도록 설정합니다.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
metadata:
annotations:
karpenter.sh/do-not-disrupt: "true"
다음 단계
Azure Kubernetes Service