DRA(동적 리소스 할당) — 클러스터 관리자를 위한 모범 사례
DRA(동적 리소스 할당) — 클러스터 관리자를 위한 모범 사례 (Good practices for Dynamic Resource Allocation as a Cluster Admin)
이 페이지는 동적 리소스 할당(DRA, Dynamic Resource Allocation) 을 활용하는 쿠버네티스 클러스터를 구성할 때 알아두면 좋은 모범 사례를 다룹니다. 내용이 클러스터 관리자 관점에서 쓰여 있다는 점을 먼저 기억해 두세요. DRA는 하드웨어 같은 특수 리소스를 팟에 유연하게 할당할 수 있게 해 주는 기능이에요.
DRA 관련 API에 권한을 분리하세요 (Separate permissions to DRA related APIs)
DRA는 여러 개의 서로 다른 API를 통해 조율됩니다. RBAC(역할 기반 접근 제어) 같은 인가 도구를 사용해서 사용자의 성격(persona)에 맞게 적절한 API에만 접근할 수 있도록 통제하세요.
- 일반적으로
DeviceClass와ResourceSlice는 관리자와 DRA 드라이버만 접근할 수 있게 제한하는 게 좋아요. - 클레임을 가진 팟을 배포할 클러스터 운영자는
ResourceClaim과ResourceClaimTemplateAPI에 접근할 수 있어야 해요. 이 두 API는 모두 네임스페이스 범위(namespace scoped) 입니다.
DRA 드라이버 배포와 유지 관리 (DRA driver deployment and maintenance)
가능하면 무중단 업그레이드가 되는 드라이버를 쓰세요
무중단(seamless) 업그레이드를 지원하는 드라이버를 선택하면 시간과 리스크를 줄일 수 있어요. 다만 이 기능은 kubelet 1.33 이상에서만 사용 가능하고, 이기종(heterogeneous) 클러스터라면 드라이버가 지원하는지 문서를 꼭 확인해야 합니다.
DRA 드라이버가 liveness probe를 노출하는지 확인하고 활용하세요
DRA 드라이버는 보통 상태 확인용 gRPC 소켓을 제공합니다. 이 소켓을 드라이버를 배포하는 DaemonSet의 liveness probe로 설정하면 가장 쉽게 활용할 수 있어요. 만약 드라이버 설정을 직접 만들거나 쿠버네티스 팟으로 실행하지 않는다면, 오케스트레이션 도구가 DRA 드라이버를 재시작하도록 반드시 설정해 두세요.
노드를 드레인할 때 DRA 드라이버는 가능한 한 마지막에 드레인하세요
노드에 대한 커스텀 드레인 로직을 직접 구현한다면, DRA 드라이버 자체를 종료하기 전에 할당되거나 예약된 ResourceClaim/ResourceClaimTemplate이 남아 있지 않은지 확인하는 걸 고려해 보세요.
높은 부하(특히 대규모 환경)에서 컴포넌트를 모니터링하고 튜닝하세요
DRA API에 저장된 메타데이터를 바탕으로 팟을 스케줄링하는 동안, 컨트롤 플레인 컴포넌트인 kube-scheduler와 kube-controller-manager에 의해 조율되는 내부 ResourceClaim 컨트롤러가 가장 많은 일을 처리해요.
- DRA 클레임을 사용하는 팟은 그렇지 않은 팟에 비해 API 서버 호출 수, 메모리, CPU 사용량이 더 필요합니다.
- 노드 로컬 컴포넌트인 DRA 드라이버와 kubelet도 팟 샌드박스 생성 시 DRA API를 통해 하드웨어 요청을 할당해요.
- 특별히 노드가 많은 대규모 환경이나 DRA 리소스 클레임을 많이 쓰는 워크로드가 많은 환경에서는, 관련 컴포넌트를 늘어난 부하에 대비하도록 설정해야 합니다.
잘못 튜닝된 컴포넌트는 팟 라이프사이클 동안 직간접적으로 다양한 증상을 일으킬 수 있어요. 예를 들어 kube-scheduler의 QPS와 burst 설정이 너무 낮으면, 스케줄러가 팟에 적합한 노드는 빠르게 찾지만 팟을 그 노드에 바인딩하는 데는 오래 걸릴 수 있습니다. DRA 스케줄링 중에는 kube-controller-manager 내 client-go 설정의 QPS와 Burst 파라미터가 특히 중요해요.
구체적인 튜닝 값은 노드/팟 수, 팟 생성 속도, 변경 주기(churn) 등 여러 요소에 따라 달라집니다. 스케일러빌리티 관련 기준은 SIG Scalability의 쿠버네티스 스케일링 임계값 문서를 참고하세요. DRA가 활성화된 100개 노드 클러스터에서 720개의 장수명 팟(90% 포화도)과 80개의 churn 팟(10% churn, 10회), 잡 생성 QPS 10으로 스케일 테스트를 수행했을 때, kube-controller-manager의 QPS를 75, Burst를 150까지 낮춰도 동등한 지표를 충족할 수 있었습니다.
kube-controller-manager 메트릭
kube-controller-manager가 관리하는 내부 ResourceClaim 컨트롤러를 관찰할 수 있는 메트릭이에요.
- Workqueue Add Rate:
sum(rate(workqueue_adds_total{name="resource_claim"}[5m]))—ResourceClaim컨트롤러에 항목이 얼마나 빨리 추가되는지 가늠할 수 있어요. - Workqueue Depth:
sum(workqueue_depth{endpoint="kube-controller-manager", name="resource_claim"})—ResourceClaim컨트롤러의 백로그(밀린 작업)를 파악해요. - Workqueue Work Duration:
histogram_quantile(0.99, sum(rate(workqueue_work_duration_seconds_bucket{name="resource_claim"}[5m])) by (le))— 컨트롤러가 작업을 처리하는 속도를 이해하는 데 도움이 돼요.
만약 낮은 Workqueue Add Rate + 높은 Workqueue Depth + 높은 Workqueue Work Duration이 보인다면 컨트롤러가 최적으로 동작하지 않는다는 뜻이에요. QPS, burst, CPU/메모리 설정 같은 파라미터 튜닝을 고려해 보세요.
반대로 높은 Add Rate + 높은 Depth인데 Work Duration은 적정하다면, 컨트롤러가 작업을 처리하고는 있지만 동시성(concurrency)이 부족하다는 신호예요. 동시성은 컨트롤러에 하드코딩되어 있으므로, 클러스터 관리자는 팟 생성 QPS를 낮춰서 리소스 클레임 workqueue의 추가 속도를 감당 가능한 수준으로 조정할 수 있습니다.
kube-scheduler 메트릭
다음 스케줄러 메트릭은 DRA만이 아니라 스케줄된 모든 팟의 성능을 집계한 상위 수준 메트릭이에요. ResourceClaimTemplate을 많이 쓰는 배포에서는 종단 간(end-to-end) 메트릭이 결국 kube-controller-manager가 ResourceClaimTemplate으로부터 ResourceClaim을 만드는 성능에 영향을 받는다는 점을 알아 두세요.
- Scheduler End-to-End Duration:
histogram_quantile(0.99, sum(increase(scheduler_pod_scheduling_sli_duration_seconds_bucket[5m])) by (le)) - Scheduler Algorithm Latency:
histogram_quantile(0.99, sum(increase(scheduler_scheduling_algorithm_duration_seconds_bucket[5m])) by (le))
kubelet 메트릭
노드에 바인딩된 팟이 ResourceClaim을 충족해야 할 때, kubelet은 DRA 드라이버의 NodePrepareResources와 NodeUnprepareResources 메서드를 호출해요. 이 동작은 kubelet 관점에서 다음 메트릭으로 관찰할 수 있습니다.
DRA kubeletplugin 동작
DRA 드라이버는 kubeletplugin 패키지 인터페이스를 구현하며, 이는 하부 gRPC 연산인 NodePrepareResources와 NodeUnprepareResources에 대한 자체 메트릭을 노출합니다. 예를 들어 다음과 같이 관찰할 수 있어요.
- DRA kubeletplugin gRPC NodeUnprepareResources 연산:
histogram_quantile(0.99, sum(rate(dra_grpc_operations_duration_seconds_bucket{method_name=~".*NodeUnprepareResources"}[5m])) by (le))