노드의 토폴로지 관리 정책 제어하기

노드의 토폴로지 관리 정책 제어하기 (Control Topology Management Policies on a node)

기능 상태: Kubernetes v1.27부터 Stable.

점점 더 많은 시스템이 대기 시간이 중요한 실행과 고처리량 병렬 계산을 지원하기 위해 CPU와 하드웨어 가속기의 조합을 활용해요. 여기에는 통신, 과학 계산, 머신러닝, 금융 서비스, 데이터 분석 분야의 워크로드가 포함돼요. 이러한 하이브리드 시스템은 고성능 환경을 구성해요.

최고의 성능을 얻으려면 CPU 격리, 메모리, 디바이스 지역성(locality)과 관련된 최적화가 필요해요. 하지만 쿠버네티스에서 이러한 최적화는 서로 분리된 컴포넌트 집합이 처리해요.

Topology Manager는 이러한 최적화를 담당하는 컴포넌트 집합을 조정하는 것을 목표로 하는 kubelet 컴포넌트예요.

출처: 문서

본문

시작하기 전에 (Before you begin)

쿠버네티스 클러스터가 필요하고, kubectl 명령줄 도구가 클러스터와 통신하도록 구성돼 있어야 해요. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 두 개 이상 있는 클러스터에서 실행하는 것을 권장해요. 아직 클러스터가 없다면 minikube로 만들거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있어요.

  • iximiuz Labs
  • Killercoda
  • KodeKloud

쿠버네티스 서버가 최소 v1.18 버전이어야 해요. 버전을 확인하려면 kubectl version을 입력하세요.

토폴로지 매니저는 어떻게 동작하나요? (How topology manager works)

Topology Manager 도입 이전에는 쿠버네티스의 CPU Manager와 Device Manager가 서로 독립적으로 리소스 할당 결정을 내렸어요. 이는 멀티 소켓 시스템에서 바람직하지 않은 할당을 초래할 수 있고, 성능/대기 시간에 민감한 애플리케이션이 이러한 바람직하지 않은 할당으로 인해 피해를 입을 수 있어요. 여기서 바람직하지 않다는 것은 예를 들어 CPU와 디바이스가 다른 NUMA 노드에서 할당되어 추가 대기 시간이 발생하는 경우를 의미해요.

Topology Manager는 kubelet 컴포넌트로, 다른 kubelet 컴포넌트가 토폴로지 정렬된 리소스 할당 선택을 할 수 있도록 진실의 원천(source of truth) 역할을 해요.

Topology Manager는 Hint Provider라고 하는 컴포넌트에 토폴로지 정보를 주고받을 인터페이스를 제공해요. Topology Manager는 아래 설명할 노드 레벨 정책 집합을 가지고 있어요.

Topology Manager는 Hint Provider로부터 사용 가능한 NUMA 노드를 나타내는 비트마스크와 선호 할당 표시로 토폴로지 정보를 받아요. Topology Manager 정책은 제공된 힌트에 대해 일련의 연산을 수행하고, 정책이 결정한 힌트로 수렴해 최적 결과를 제공해요. 바람직하지 않은 힌트가 저장되면 힌트의 preferred 필드가 false로 설정돼요. 현재 정책에서 preferred는 가장 좁은 선호 마스크예요. 선택된 힌트는 Topology Manager의 일부로 저장돼요. 구성된 정책에 따라 선택된 힌트를 기준으로 파드가 노드에서 승인되거나 거부될 수 있어요. 그런 다음 힌트는 Hint Provider가 리소스 할당 결정을 내릴 때 사용하도록 Topology Manager에 저장돼요.

이 흐름은 다음 다이어그램에서 볼 수 있어요.

Windows 지원 (Windows Support)

기능 상태: Kubernetes v1.32부터 Alpha; 기본적으로 비활성화.

이 기능을 사용하려면 WindowsCPUAndMemoryAffinity 기능 게이트를 활성화해야 하고, 컨테이너 런타임의 지원이 필요해요.

토폴로지 매니저 범위와 정책 (Topology manager scopes and policies)

Topology Manager는 현재:

  • 모든 QoS 클래스의 Pod를 정렬해요.
  • Hint Provider가 토폴로지 힌트를 제공하는 요청 리소스를 정렬해요.

이 조건이 충족되면 Topology Manager는 요청된 리소스를 정렬해요.

이 정렬이 수행되는 방식을 사용자 정의하기 위해 Topology Manager는 scopepolicy 두 가지 뚜렷한 옵션을 제공해요.

scope는 리소스 정렬을 수행하려는 세분성을 정의해요. 예를 들어 pod 또는 container 레벨에서요. 그리고 policy는 정렬을 수행하는 데 사용되는 실제 정책을 정의해요. 예를 들어 best-effort, restricted, single-numa-node가 있어요. 오늘 사용 가능한 다양한 scopespolicies에 대한 세부 정보는 아래에서 확인할 수 있어요.

참고: Pod 스펙에서 CPU 리소스를 다른 요청 리소스와 정렬하려면 CPU Manager가 활성화되고 노드에 적절한 CPU Manager 정책이 구성돼 있어야 해요. 노드의 CPU 관리 정책 제어를 참고하세요.

참고: Pod 스펙에서 메모리(및 hugepages) 리소스를 다른 요청 리소스와 정렬하려면 Memory Manager가 활성화되고 노드에 적절한 Memory Manager 정책이 구성돼 있어야 해요. 메모리 매니저 문서를 참고하세요.

토폴로지 매니저 범위 (Topology manager scopes)

Topology Manager는 리소스 정렬을 몇 가지 뚜렷한 범위로 다룰 수 있어요.

  • container (기본값)
  • pod

둘 중 하나를 kubelet 시작 시 kubelet 구성 파일에 topologyManagerScope를 설정해 선택할 수 있어요.

container 범위

container 범위가 기본으로 사용돼요. kubelet 구성 파일에서 topologyManagerScopecontainer로 명시적으로 설정할 수도 있어요. 이 범위 내에서 Topology Manager는 일련의 순차적 리소스 정렬을 수행해요. 즉 각 컨테이너(파드 내에서)별로 별도의 정렬이 계산돼요. 다시 말해 이 특정 범위에서는 컨테이너를 특정 NUMA 노드 집합으로 그룹화하는 개념이 없어요. 결과적으로 Topology Manager는 개별 컨테이너를 NUMA 노드에 임의로 정렬해요.

컨테이너 그룹화 개념은 다음 범위, 예를 들어 pod 범위에서 의도적으로 지지되고 구현됐어요.

pod 범위

pod 범위를 선택하려면 kubelet 구성 파일에서 topologyManagerScopepod로 설정하세요. 이 범위는 파드의 모든 컨테이너를 공통 NUMA 노드 집합으로 그룹화할 수 있게 해 줘요. 즉 Topology Manager는 파드를 하나의 덩어리로 취급하고 전체 파드(모든 컨테이너)를 단일 NUMA 노드나 공통 NUMA 노드 집합에 할당하려고 시도해요.

  • 모든 컨테이너가 단일 NUMA 노드에 할당될 수 있고 할당됨
  • 모든 컨테이너가 공유 NUMA 노드 집합에 할당될 수 있고 할당됨

전체 파드가 요구하는 특정 리소스의 총량은 유효 요청/제한 공식에 따라 계산돼요. 따라서 이 총 값은 리소스에 대해 다음 중 최대값과 같아요.

  • 모든 앱 컨테이너 요청의 합
  • init 컨테이너 요청의 최대값

pod 범위를 single-numa-node Topology Manager 정책과 함께 사용하는 것은 대기 시간에 민감한 워크로드나 IPC를 수행하는 고처리량 애플리케이션에 특히 유용해요. 두 옵션을 결합하면 파드의 모든 컨테이너를 단일 NUMA 노드에 배치할 수 있어, 그 파드의 NUMA 간 통신 오버헤드를 없앨 수 있어요.

single-numa-node 정책의 경우 가능한 할당 중에 적합한 NUMA 노드 집합이 존재할 때만 파드가 승인돼요. 앞선 예시를 다시 생각해 보죠.

  • 단일 NUMA 노드만 포함하는 집합 — 파드 승인으로 이어짐
  • 더 많은 NUMA 노드를 포함하는 집합 — 파드 거부로 이어짐 (하나의 NUMA 노드 대신 둘 이상의 NUMA 노드가 할당 충족을 위해 필요하므로)

요약하면, Topology Manager는 먼저 NUMA 노드 집합을 계산한 뒤 이를 Topology Manager 정책에 대해 테스트하고, 이는 파드의 거부 또는 승인으로 이어져요.

토폴로지 매니저 정책 (Topology manager policies)

Topology Manager는 네 가지 할당 정책을 지원해요. kubelet 플래그인 --topology-manager-policy로 정책을 설정할 수 있어요. 지원되는 정책은 네 가지예요.

  • none (기본값)
  • best-effort
  • restricted
  • single-numa-node

참고: Topology Manager가 pod 범위로 구성되면 정책이 고려하는 컨테이너는 전체 파드의 요구 사항을 반영하므로, 파드의 각 컨테이너는 동일한 토폴로지 정렬 결정을 얻게 돼요.

none 정책

이것은 기본 정책이며 토폴로지 정렬을 수행하지 않아요.

best-effort 정책

Pod의 각 컨테이너에 대해 kubelet은 best-effort 토폴로지 관리 정책으로 각 Hint Provider를 호출해 리소스 가용성을 발견해요. 이 정보를 사용해 Topology Manager는 그 컨테이너의 선호 NUMA 노드 어피니티를 저장해요. 어피니티가 선호되지 않더라도 Topology Manager는 이를 저장하고 파드를 노드에 어쨌든 승인해요.

그러면 Hint Provider가 리소스 할당 결정을 내릴 때 이 정보를 사용할 수 있어요.

restricted 정책

Pod의 각 컨테이너에 대해 kubelet은 restricted 토폴로지 관리 정책으로 각 Hint Provider를 호출해 리소스 가용성을 발견해요. 이 정보를 사용해 Topology Manager는 그 컨테이너의 선호 NUMA 노드 어피니티를 저장해요. 어피니티가 선호되지 않으면 Topology Manager는 이 파드를 노드에서 거부해요. 이는 파드가 파드 승인 실패와 함께 Terminated 상태로 들어가는 결과를 가져와요.

파드가 Terminated 상태가 되면 쿠버네티스 스케줄러는 파드를 재스케줄링하려 하지 않아요. 파드의 재배포를 촉발하려면 ReplicaSet이나 Deployment를 사용하는 것이 권장돼요. Topology Affinity 오류가 있는 파드의 재배포를 촉발하기 위해 외부 제어 루프를 구현할 수도 있어요.

파드가 승인되면 Hint Provider가 리소스 할당 결정을 내릴 때 이 정보를 사용할 수 있어요.

single-numa-node 정책

Pod의 각 컨테이너에 대해 kubelet은 single-numa-node 토폴로지 관리 정책으로 각 Hint Provider를 호출해 리소스 가용성을 발견해요. 이 정보를 사용해 Topology Manager는 단일 NUMA 노드 어피니티가 가능한지 결정해요. 가능하면 Topology Manager가 이를 저장하고 Hint Provider가 리소스 할당 결정을 내릴 때 이 정보를 사용할 수 있어요. 그러나 가능하지 않다면 Topology Manager는 파드를 노드에서 거부해요. 이는 파드가 파드 승인 실패와 함께 Terminated 상태가 되는 결과를 가져와요.

파드가 Terminated 상태가 되면 쿠버네티스 스케줄러는 파드를 재스케줄링하려 하지 않아요. 파드의 재배포를 촉발하려면 replicas가 있는 Deployment를 사용하는 것이 권장돼요. Topology Affinity 오류가 있는 파드의 재배포를 촉발하기 위해 외부 제어 루프를 구현할 수도 있어요.

토폴로지 매니저 정책 옵션 (Topology manager policy options)

Topology Manager 정책 옵션 지원에는 TopologyManagerPolicyOptions 기능 게이트가 활성화돼야 해요(기본적으로 활성화됨). 성숙도 수준에 따라 다음 기능 게이트를 사용해 옵션 그룹을 켜고 끌 수 있어요.

  • TopologyManagerPolicyBetaOptions 기본 활성화. 베타 레벨 옵션을 보여주려면 활성화.
  • TopologyManagerPolicyAlphaOptions 기본 비활성화. 알파 레벨 옵션을 보여주려면 활성화.

여전히 TopologyManagerPolicyOptions kubelet 옵션으로 각 옵션을 활성화해야 해요.

prefer-closest-numa-nodes

prefer-closest-numa-nodes 옵션은 Kubernetes 1.32부터 GA예요. Kubernetes 1.37에서 이 정책 옵션은 TopologyManagerPolicyOptions 기능 게이트가 활성화되면 기본적으로 보여요.

Topology Manager는 기본적으로 NUMA 거리를 인식하지 못하며, 파드 승인 결정을 내릴 때 이를 고려하지 않아요. 이 제한은 멀티 소켓 및 단일 소켓 다중 NUMA 시스템에서 표면화되며, Topology Manager가 인접하지 않은 NUMA 노드에 리소스를 정렬하기로 결정하면 대기 시간이 중요한 실행과 고처리량 애플리케이션에서 심각한 성능 저하를 일으킬 수 있어요.

prefer-closest-numa-nodes 정책 옵션을 지정하면 best-effortrestricted 정책이 승인 결정을 내릴 때 서로 거리가 더 짧은 NUMA 노드 집합을 선호해요.

이 옵션은 Topology Manager 정책 옵션에 prefer-closest-numa-nodes=true를 추가해 활성화할 수 있어요.

기본적으로(이 옵션 없이) Topology Manager는 단일 NUMA 노드에 리소스를 정렬하거나, 둘 이상의 NUMA 노드가 필요한 경우 최소 수의 NUMA 노드를 사용해 정렬해요.

max-allowable-numa-nodes

max-allowable-numa-nodes 옵션은 Kubernetes 1.35부터 GA예요. Kubernetes 1.37에서 이 정책 옵션은 TopologyManagerPolicyOptions 기능 게이트가 활성화되면 기본적으로 보여요.

파드 승인 시간은 물리 머신의 NUMA 노드 수와 연관돼 있어요. 기본적으로 쿠버네티스는 8개 이상의 NUMA 노드가 감지된 (쿠버네티스) 노드에서 Topology Manager를 활성화한 kubelet을 실행하지 않아요.

참고: max-allowable-numa-nodes 정책 옵션을 선택하면 8개 이상의 NUMA 노드가 있는 노드에서도 Topology Manager를 활성화해 실행할 수 있어요. 쿠버네티스 프로젝트는 8개 이상의 NUMA 노드가 있는 (쿠버네티스) 노드에서 Topology Manager를 사용할 때의 영향에 대한 데이터가 제한적이에요. 데이터 부족으로 인해 Kubernetes 1.37에서 이 정책 옵션을 사용하는 것은 권장되지 않으며 자신의 책임 하에 있어요.

이 옵션은 Topology Manager 정책 옵션에 max-allowable-numa-nodes=<integer>를 추가해 활성화할 수 있어요. 여기서 정수 값은 8보다 커야 해요. 기본값은 8이며, 기존 제한을 유지해요.

max-allowable-numa-nodes 값을 설정하는 것 자체로는 파드 승인 대기 시간에 영향을 주지 않지만, NUMA가 많은 (쿠버네티스) 노드에 Pod를 바인딩하는 것은 영향을 줘요. 쿠버네티스에 대한 향후 잠재적 개선으로 파드 승인 성능과 NUMA 노드 수가 증가함에 따라 발생하는 높은 대기 시간을 개선할 수 있어요.

토폴로지 매니저 정책과의 파드 상호작용 (Pod interactions with topology manager policies)

다음 Pod 매니페스트의 컨테이너를 고려해 보죠.

spec:
  containers:
  - name: nginx
    image: nginx

이 파드는 리소스 requestslimits가 지정되지 않았으므로 BestEffort QoS 클래스에서 실행돼요.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

이 파드는 requests가 limits보다 작으므로 Burstable QoS 클래스에서 실행돼요.

선택한 정책이 none이 아닌 경우 Topology Manager는 이러한 Pod 사양을 고려해요. Topology Manager는 Hint Provider를 참조해 토폴로지 힌트를 얻어요. static 정책의 경우, 이 파드들이 CPU 리소스를 명시적으로 요청하지 않으므로 CPU Manager 정책이 기본 토폴로지 힌트를 반환해요.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"
        example.com/device: "1"
      requests:
        memory: "200Mi"
        cpu: "2"
        example.com/device: "1"

정수 CPU 요청을 가진 이 파드는 requestslimits와 같으므로 Guaranteed QoS 클래스에서 실행돼요.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "300m"
        example.com/device: "1"
      requests:
        memory: "200Mi"
        cpu: "300m"
        example.com/device: "1"

CPU를 공유하는 요청을 가진 이 파드는 requestslimits와 같으므로 Guaranteed QoS 클래스에서 실행돼요.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        example.com/deviceA: "1"
        example.com/deviceB: "1"
      requests:
        example.com/deviceA: "1"
        example.com/deviceB: "1"

이 파드는 CPU와 메모리 요청이 없으므로 BestEffort QoS 클래스에서 실행돼요.

Topology Manager는 위 파드들을 고려해요. Topology Manager는 Hint Provider인 CPU Manager와 Device Manager를 참조해 파드에 대한 토폴로지 힌트를 얻어요.

정수 CPU 요청을 가진 Guaranteed 파드의 경우, static CPU Manager 정책은 독점 CPU에 관련된 토폴로지 힌트를 반환하고 Device Manager는 요청된 디바이스에 대한 힌트를 보내줘요.

CPU를 공유하는 요청을 가진 Guaranteed 파드의 경우, static CPU Manager 정책은 독점 CPU 요청이 없으므로 기본 토폴로지 힌트를 반환하고, Device Manager는 요청된 디바이스에 대한 힌트를 보내줘요.

위 두 Guaranteed 파드 경우 모두에서 none CPU Manager 정책은 기본 토폴로지 힌트를 반환해요.

BestEffort 파드의 경우 static CPU Manager 정책은 CPU 요청이 없으므로 기본 토폴로지 힌트를 보내고, Device Manager는 각 요청된 디바이스에 대한 힌트를 보내줘요.

이 정보를 사용해 Topology Manager는 파드에 대한 최적 힌트를 계산하고 이 정보를 저장하는데, 이는 Hint Provider가 리소스 할당을 할 때 사용할 거예요.

알려진 제한 사항 (Known limitations)

  • Topology Manager가 허용하는 최대 NUMA 노드 수는 8이에요. 8개 이상의 NUMA 노드가 있으면 가능한 NUMA 어피니티를 열거하고 그 힌트를 생성할 때 상태 폭발(state explosion)이 발생해요. 더 많은 옵션은 max-allowable-numa-nodes(베타)를 참고하세요.
  • 스케줄러는 토폴로지를 인식하지 못하므로, 노드에 스케줄링된 뒤 Topology Manager로 인해 노드에서 실패할 수 있어요.

다음 단계 (What's next)

  • 파드 레벨 리소스 매니저에 대해 읽기

더 알아보기 (Learn more)