리소스 매니저

리소스 매니저 (Resource Managers)

지연시간에 민감하고 높은 처리량의 워크로드를 지원하기 위해 쿠버네티스는 일련의 Resource Manager를 제공해요. 이 매니저들은 CPU, 장치, 메모리(거대 페이지) 리소스에 대한 특정 요구 사항으로 구성된 파드를 위해 노드 리소스의 정렬을 조정·최적화하는 것을 목표로 합니다.

출처: 문서

본문

토폴로지 매니저

Topology Manager는 이러한 최적화를 담당하는 구성 요소 집합을 조정하는 것을 목표로 하는 kubelet 구성 요소예요. 더 자세히 배우려면 노드의 토폴로지 관리 정책 제어하기를 읽어보세요.

CPU 매니저

CPU Manager는 CPU 리소스에 대한 전용 리소스 할당을 제공하는 kubelet 구성 요소예요. 리소스 할당 결정을 내리기 위해 Topology Manager와 상의합니다. 더 자세히 배우려면 노드에서 CPU 관리 정책 제어하기를 읽어보세요.

파드에 CPU를 할당하는 정책

파드가 노드에 바인딩되면 그 노드의 kubelet은 기존 하드웨어를 멀티플렉싱(예: 여러 파드가 CPU 공유)하거나, 어떤 리소스를 전용해 하드웨어를 할당(예: 한 파드가 전용으로 사용할 CPU 하나 이상 할당)해야 할 수 있어요.

기본적으로 kubelet은 CFS quota를 사용해 파드 CPU limit을 강제합니다. 노드가 많은 CPU 바운드 파드를 실행하면 워크로드는 파드가 스로틀되는지, 스케줄링 시점에 어떤 CPU 코어가 사용 가능한지에 따라 다른 CPU 코어로 이동할 수 있습니다. 많은 워크로드는 이 이동에 민감하지 않아 어떤 개입 없이도 잘 동작합니다.

그러나 CPU 캐시 친화도와 스케줄링 지연시간이 워크로드 성능에 크게 영향을 주는 워크로드에서는, kubelet이 노드에서 몇 가지 배치 선호도를 결정하는 대체 CPU 관리 정책을 허용합니다. 이는 _CPU Manager_와 그 정책으로 구현됩니다. 두 가지 정책이 있습니다:

  • none: none 정책은 기존 기본 CPU 친화도 방식을 명시적으로 활성화하며, OS 스케줄러가 자동으로 하는 것 이상의 친화도를 제공하지 않는다. Guaranteed 파드Burstable 파드의 CPU 사용량 limit은 CFS quota로 강제된다.
  • static: static 정책은 정수 CPU requests를 가진 Guaranteed 파드의 컨테이너가 노드의 전용 CPU에 접근하게 허용한다. 이 독점은 cpuset cgroup 컨트롤러를 사용해 강제된다.

컨테이너 런타임과 kubelet 자체 같은 시스템 서비스는 이 전용 CPU에서 계속 실행될 수 있어요. 독점은 다른 파드에만 적용됩니다.

CPU Manager는 런타임에 CPU의 오프라인·온라인 전환을 지원하지 않아요.

static 정책

static 정책은 더 세분화된 CPU 관리와 전용 CPU 할당을 활성화합니다. 이 정책은 처음에 노드의 모든 CPU를 포함하는 공유 CPU 풀을 관리합니다. 전용 할당 가능한 CPU의 양은 노드의 총 CPU 수에서 kubelet 구성이 설정한 CPU 예약을 뺀 값과 같습니다. 이 옵션들로 예약된 CPU는 정수 수량으로, 초기 공유 풀에서 물리 코어 ID의 오름차순으로 취해집니다. 이 공유 풀은 BestEffortBurstable 파드의 컨테이너가 실행되는 CPU 집합입니다. CPU requests가 분수인 Guaranteed 파드의 컨테이너도 공유 풀의 CPU에서 실행됩니다. Guaranteed 파드의 일부면서 정수 CPU requests를 가진 컨테이너만 전용 CPU를 할당받습니다.

static 정책이 활성화되면 kubelet은 0보다 큰 CPU 예약을 요구해요. CPU 예약이 0이면 공유 풀이 비어질 수 있기 때문입니다.

정적 할당 요건에 맞는 Guaranteed 파드가 노드에 스케줄되면, CPU가 공유 풀에서 제거되어 컨테이너의 cpuset에 놓입니다. 이 컨테이너들의 CPU 사용량은 스케줄링 도메인 자체가 묶으므로 CFS quota를 사용해 제한되지 않습니다. 즉 컨테이너 cpuset의 CPU 수는 파드 스펙에 지정된 정수 CPU limit과 같습니다. 이 정적 할당은 CPU 친화도를 높이고 CPU 바운드 워크로드의 스로틀링으로 인한 컨텍스트 스위치를 줄여줍니다.

다음 파드 스펙의 컨테이너를 고려해보세요:

spec:
  containers:
  - name: nginx
    image: nginx

위 파드는 리소스 requestslimits가 지정되지 않았으므로 BestEffort QoS 클래스로 실행됩니다. 공유 풀에서 실행됩니다.

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

위 파드는 리소스 requestslimits와 같지 않고 cpu 수량이 지정되지 않았으므로 Burstable QoS 클래스로 실행됩니다. 공유 풀에서 실행됩니다.

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

위 파드는 리소스 requestslimits와 같지 않으므로 Burstable QoS 클래스로 실행됩니다. 공유 풀에서 실행됩니다.

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

위 파드는 requestslimits와 같으므로 Guaranteed QoS 클래스로 실행됩니다. 또한 CPU 리소스의 컨테이너 limit은 1보다 크거나 같은 정수입니다. nginx 컨테이너는 2개의 전용 CPU를 부여받습니다.

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

위 파드는 requestslimits와 같으므로 Guaranteed QoS 클래스로 실행됩니다. 하지만 CPU 리소스의 컨테이너 limit은 분수입니다. 공유 풀에서 실행됩니다.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"

위 파드는 limits만 지정되고 requests는 명시적으로 지정하지 않았을 때 limits와 같게 설정되므로 Guaranteed QoS 클래스로 실행됩니다. 또한 CPU 리소스의 컨테이너 limit은 1보다 크거나 같은 정수입니다. nginx 컨테이너는 2개의 전용 CPU를 부여받습니다.

static 정책 옵션

static CPU 관리 정책에 사용할 수 있는 정책 옵션은 알파벳 순서로 다음과 같아요:

align-by-socket (알파, 기본적으로 숨김) : 논리적 NUMA 경계가 아닌 물리적 패키지/소켓 경계로 CPU를 정렬한다 (쿠버네티스 v1.25부터 사용 가능)

distribute-cpus-across-cores (알파, 기본적으로 숨김) : 하드웨어 스레드라고도 하는 가상 코어를 서로 다른 물리 코어에 걸쳐 할당한다 (쿠버네티스 v1.31부터 사용 가능)

distribute-cpus-across-numa (베타, 기본적으로 보임) : 선택된 도메인 사이의 균등한 균형을 목표로 CPU를 서로 다른 NUMA 도메인에 걸쳐 분산한다 (쿠버네티스 v1.23부터 사용 가능)

full-pcpus-only (GA, 기본적으로 보임) : 항상 전체 물리 코어를 할당한다 (쿠버네티스 v1.22부터 사용 가능, v1.33부터 GA)

strict-cpu-reservation (GA, 기본적으로 보임) : Quality of Service 클래스와 관계없이 모든 파드가 예약된 CPU에서 실행되지 못하게 한다 (쿠버네티스 v1.32부터 사용 가능, v1.35부터 GA)

prefer-align-cpus-by-uncorecache (GA, 기본적으로 보임) : 최선 노력 방식으로 uncore(최종 레벨) 캐시 경계로 CPU를 정렬한다 (쿠버네티스 v1.32부터 사용 가능)

다음 피처 게이트로 성숙도 수준에 따라 옵션 그룹을 켜고 끌 수 있어요:

  • CPUManagerPolicyBetaOptions (기본 활성화). 베타 레벨 옵션을 숨기려면 비활성화.
  • CPUManagerPolicyAlphaOptions (기본 비활성화). 알파 레벨 옵션을 보여주려면 활성화.

각 옵션은 kubelet 구성 파일의 cpuManagerPolicyOptions 필드를 사용해 여전히 활성화해야 합니다.

구성할 수 있는 개별 옵션에 대한 더 자세한 내용은 이어서 읽어보세요.

full-pcpus-only

full-pcpus-only 정책 옵션이 지정되면 static 정책은 항상 전체 물리 코어를 할당해요. 기본적으로 이 옵션 없이 static 정책은 토폴로지 인지 최적 적합(topology-aware best-fit) 할당을 사용해 CPU를 할당합니다. SMT가 활성화된 시스템에서 정책은 하드웨어 스레드에 해당하는 개별 가상 코어를 할당할 수 있습니다. 이는 서로 다른 컨테이너가 같은 물리 코어를 공유하게 할 수 있고, 이 동작은 noisy neighbours 문제에 기여합니다. 옵션이 활성화되면 모든 컨테이너의 CPU request를 전체 물리 코어 할당으로 충족할 수 있을 때만 파드가 kubelet에 허용됩니다. 파드가 어드미션을 통과하지 못하면 SMTAlignmentError 메시지와 함께 Failed 상태가 됩니다.

distribute-cpus-across-numa

distribute-cpus-across-numa 정책 옵션이 지정되면, static 정책은 할당을 충족하기 위해 둘 이상의 NUMA 노드가 필요할 때 CPU를 NUMA 노드에 균등하게 분산합니다. 기본적으로 CPUManager는 NUMA 노드 하나가 차기 전까지 CPU를 그 노드에 패킹하고, 남은 CPU는 다음 NUMA 노드로 넘칩니다. 이는 배리어(및 유사한 동기화 프리미티브)에 의존하는 병렬 코드에서 바람직하지 않은 병목을 일으킬 수 있습니다. 이런 코드는 가장 느린 워커만큼만 빠르게 실행되는 경향이 있기 때문입니다(최소 하나의 NUMA 노드에서 사용 가능한 CPU가 더 적어 워커가 느려집니다). CPU를 NUMA 노드에 균등 분산하면 애플리케이션 개발자는 어떤 단일 워커도 다른 워커보다 NUMA 효과를 더 겪지 않도록 더 쉽게 보장할 수 있어, 이런 유형의 애플리케이션 전반적 성능이 향상됩니다.

align-by-socket

align-by-socket 정책 옵션이 지정되면, 컨테이너에 CPU를 할당하는 방법을 결정할 때 CPU가 소켓 경계에서 정렬된 것으로 간주됩니다. 기본적으로 CPUManager는 NUMA 경계에서 CPU 할당을 정렬하는데, 할당을 충족하기 위해 둘 이상의 NUMA 노드에서 CPU를 가져와야 하면 성능 저하가 발생할 수 있습니다. 모든 CPU를 최소 수의 NUMA 노드에서 할당하려고 하더라도, 그 NUMA 노드들이 같은 소켓에 있을 것이라는 보장은 없습니다. CPUManager가 NUMA 경계가 아닌 소켓 경계에서 명시적으로 정렬하도록 지시하면 이런 문제를 피할 수 있습니다. 이 정책 옵션은 TopologyManager single-numa-node 정책과 호환되지 않고, 소켓 수가 NUMA 노드 수보다 많은 하드웨어에는 적용되지 않는다는 점을 유의하세요.

distribute-cpus-across-cores

distribute-cpus-across-cores 정책 옵션이 지정되면, static 정책은 서로 다른 물리 코어에 걸쳐 가상 코어(하드웨어 스레드)를 할당하려 시도합니다. 기본적으로 CPUManager는 가능한 한 적은 수의 물리 코어에 CPU를 패킹하는 경향이 있는데, 이는 같은 물리 코어의 CPU 사이의 경합을 일으키고 성능 병목을 초래할 수 있습니다. distribute-cpus-across-cores 정책을 활성화하면 static 정책이 최대한 많은 물리 코어에 걸쳐 CPU를 분산해, 같은 물리 코어에서의 경합을 줄이고 전반적 성능을 향상시킵니다. 그러나 시스템이 과부하 상태일 때는 이 전략이 덜 효과적일 수 있다는 점을 유의해야 합니다. 그런 조건에서는 경합 감소의 이점이 줄어듭니다. 반대로 기본 동작은 코어 간 통신 오버헤드를 줄이는 데 도움이 되어, 높은 부하 조건에서 더 나은 성능을 제공할 수 있습니다.

strict-cpu-reservation

KubeletConfigurationreservedSystemCPUs 파라미터나, deprecated된 kubelet 명령줄 옵션 --reserved-cpus는 OS 시스템 데몬과 쿠버네티스 시스템 데몬을 위한 명시적 CPU 집합을 정의해요. 이 파라미터에 대한 자세한 내용은 명시적으로 예약된 CPU 목록 페이지에서 찾을 수 있습니다. 기본적으로 이 격리는 정수 CPU request를 가진 guaranteed 파드에 대해서만 구현되며, burstable과 best-effort 파드(및 분수 CPU request를 가진 guaranteed 파드)에는 적용되지 않습니다. 어드미션은 CPU request만 할당 가능한 CPU와 비교합니다. CPU limit이 request보다 높으므로 기본 동작은 burstable과 best-effort 파드가 reservedSystemCPUs의 용량을 사용해 실제 운영에서 호스트 OS 서비스를 굶기게 할 수 있습니다. strict-cpu-reservation 정책 옵션이 활성화되면 static 정책은 어떤 워크로드도 reservedSystemCPUs에 지정된 CPU 코어를 사용하지 못하게 합니다.

prefer-align-cpus-by-uncorecache

prefer-align-cpus-by-uncorecache 정책이 지정되면, static 정책은 컨테이너에 할당된 모든 CPU가 같은 uncore 캐시 블록(최종 레벨 캐시, LLC라고도 함)을 공유하도록 개별 컨테이너의 CPU 리소스를 할당합니다. 기본적으로 CPUManager는 CPU 할당을 밀착 패킹해 컨테이너가 여러 uncore 캐시에서 CPU를 할당받을 수 있습니다. 이 옵션은 CPUManager가 uncore 캐시의 효율적 사용을 극대화하는 방식으로 CPU를 할당하게 합니다. 할당은 최선 노력 기준으로 수행되며, 같은 uncore 캐시 안에서 가능한 한 많은 CPU를 친화시키는 것을 목표로 합니다. 컨테이너의 CPU 요구가 단일 uncore 캐시의 CPU 용량을 초과하면 CPUManager는 최적의 uncore 캐시 정렬을 유지하기 위해 사용되는 uncore 캐시 수를 최소화합니다. 특정 워크로드는 캐시 간 지연시간과 캐시 레벨 noisy neighbours의 감소로 성능 이점을 얻을 수 있습니다. CPUManager가 노드에 충분한 리소스가 있는데도 최적으로 정렬할 수 없으면, 컨테이너는 여전히 기본 패킹 동작으로 허용됩니다.

메모리 매니저

Memory Manager는 메모리 리소스에 대한 전용 리소스 할당을 제공하는 kubelet 구성 요소예요. 리소스 할당 결정을 내리기 위해 Topology Manager와 상의합니다. 더 자세히 배우려면 노드에서 메모리 관리 정책 제어하기를 읽어보세요.

파드에 메모리를 할당하는 정책

쿠버네티스 Memory ManagerGuaranteed QoS 클래스의 파드를 위해 RAM(메모리, 선택적으로 Linux 거대 페이지) 리소스를 할당합니다.

Memory Manager는 파드에 가장 적합한 NUMA 친화도를 산출하는 힌트 생성 프로토콜을 사용합니다. Memory Manager는 이 친화도 힌트를 중앙 매니저(Topology Manager)에 공급합니다. 힌트와 Topology Manager 정책을 기반으로 파드는 노드에 거부되거나 허용됩니다.

또한 Memory Manager는 파드가 요청한 메모리가 최소 수의 NUMA 노드에서 할당되도록 보장합니다.

더 자세히 배우려면 노드에서 메모리 관리 정책 제어하기를 읽어보세요.

디바이스 매니저

Device Manager는 디바이스 플러그인 API를 사용해 하드웨어 장치를 파드에 할당하는 kubelet 구성 요소예요. 디바이스 플러그인이 제공하는 토폴로지 정보를 사용해 Topology Manager와 상의하며 리소스 할당 결정을 내립니다. 더 자세히 배우려면 Topology Manager와의 디바이스 플러그인 통합을 읽어보세요.

파드 레벨 리소스 매니저

kubelet 리소스 매니저(Topology, CPU, Memory)를 위한 파드 레벨 리소스 지원은 리소스 매니저가 NUMA 정렬과 전용 할당 결정에 .spec.resources를 직접 사용하게 해줘요.

더 자세히 배우려면 전용 파드 레벨 리소스 매니저 개념 페이지를 보거나, 파드 레벨 CPU·메모리 리소스 할당하는 방법을 읽어보세요.

더 알아보기 (Learn more)