리소스 매니저
리소스 매니저 (Resource managers)
지연 시간에 민감한(latency-critical) 워크로드와 고처리량(high-throughput) 워크로드를 지원하기 위해, 쿠버네티스는 리소스 매니저(Resource Managers) 세트를 제공해요. 이 매니저들은 CPU, 디바이스, 메모리(hugepages) 리소스에 특정 요구사항이 설정된 Pod를 위해 노드 리소스의 정렬을 조정하고 최적화하는 것을 목표로 합니다.
Topology Manager
이 기능은 Kubernetes 1.27 릴리스부터 안정적(stable)입니다. 더 이상 이 기능을 켜고 끌 수 없어요 (관련 기능 게이트가 제거되었습니다).
Topology Manager는 이러한 최적화를 담당하는 컴포넌트 집합을 조정하는 것을 목표로 하는 kubelet 컴포넌트예요. 자세한 내용은 'Control Topology Management Policies on a Node' 문서를 읽어보세요.
CPU Manager
이 기능은 Kubernetes 1.26 릴리스부터 안정적(stable)입니다. 더 이상 이 기능을 켜고 끌 수 없어요 (관련 기능 게이트가 제거되었습니다).
CPU Manager는 CPU 리소스에 대한 독점 리소스를 할당하는 kubelet 컴포넌트예요. 리소스 할당 결정을 내릴 때 Topology Manager와 상의합니다. 자세한 내용은 'Control CPU Management Policies on the Node' 문서를 읽어보세요.
Pod에 CPU를 할당하는 정책 (Policies for assigning CPUs to Pods)
Pod가 Node에 바인딩되면, 그 노드의 kubelet은 기존 하드웨어를 멀티플렉스하거나(예: 여러 Pod가 CPU를 공유) 일부 리소스를 전용으로 할당해(예: Pod의 독점 사용을 위해 CPU를 하나 이상 지정) 하드웨어를 할당해야 할 수 있어요.
기본적으로 kubelet은 CFS quota를 사용해 Pod CPU 한도를 강제합니다. 노드가 CPU 집약적인 Pod를 많이 실행하면, Pod가 스로틀링되는지와 스케줄링 시점에 어떤 CPU 코어가 사용 가능한지에 따라 워크로드가 다른 CPU 코어로 이동할 수 있어요. 많은 워크로드는 이러한 이동에 민감하지 않으므로 별다른 개입 없이 잘 동작합니다.
하지만 CPU 캐시 affinity와 스케줄링 지연 시간이 워크로드 성능에 크게 영향을 주는 워크로드에서는, kubelet이 대체 CPU 관리 정책을 허용해 노드에서 배치 선호도를 결정하게 할 수 있어요. 이는 CPU Manager와 그 정책을 통해 구현됩니다. 두 가지 정책이 있어요.
none:none정책은 기존 기본 CPU affinity 체계를 명시적으로 활성화하며, OS 스케줄러가 자동으로 제공하는 것 이상의 affinity를 제공하지 않아요. Guaranteed Pod와 Burstable Pod의 CPU 사용 한도는 CFS quota로 강제됩니다.static:static정책은 정수 CPUrequests를 가진GuaranteedPod의 컨테이너가 노드의 독점 CPU에 접근할 수 있게 해요. 이 독점성은 cpuset cgroup 컨트롤러로 강제됩니다.
참고: 컨테이너 런타임이나 kubelet 자체 같은 시스템 서비스는 이러한 독점 CPU에서 계속 실행될 수 있어요. 독점성은 다른 Pod에만 적용됩니다.
CPU Manager는 런타임 중 CPU 오프라인/온라인 전환(offlining and onlining)을 지원하지 않아요.
Static 정책
static 정책은 더 세밀한 CPU 관리와 독점 CPU 할당을 가능하게 해요. 이 정책은 처음에 노드의 모든 CPU를 포함하는 공유 CPU 풀을 관리합니다. 독점 할당 가능한 CPU 수는 노드의 총 CPU 수에서 kubelet 구성이 설정한 CPU 예약량을 뺀 것과 같아요. 이 옵션들이 예약한 CPU는 물리 코어 ID 오름차순으로 초기 공유 풀에서 정수 개수만큼 빠져나가요. 이 공유 풀은 BestEffort 및 Burstable Pod의 컨테이너가 실행되는 CPU 집합이에요. 분수 CPU 요청을 가진 Guaranteed Pod의 컨테이너도 공유 풀의 CPU에서 실행됩니다. 정수 CPU 요청을 가진 Guaranteed Pod의 일부인 컨테이너만 독점 CPU가 할당됩니다.
참고: static 정책이 활성화되면 kubelet은 0보다 큰 CPU 예약을 요구해요. CPU 예약이 0이면 공유 풀이 비워질 수 있기 때문입니다.
static 할당 대상 요건을 충족하는 컨테이너를 가진 Guaranteed Pod가 노드에 스케줄되면, 공유 풀에서 CPU가 제거되어 컨테이너의 cpuset에 배치됩니다. 이 컨테이너들의 CPU 사용은 스케줄링 도메인 자체로 제한되므로 CFS quota로 묶지 않아요. 다시 말하면, 컨테이너 cpuset의 CPU 수는 Pod 스펙에 지정된 정수 CPU 한도와 같습니다. 이 static 할당은 CPU affinity를 높이고 CPU 집약적 워크로드의 스로틀링으로 인한 컨텍스트 스위치를 줄여줍니다.
다음 Pod 스펙의 컨테이너들을 생각해 보세요.
spec:
containers:
- name: nginx
image: nginx
위 Pod는 리소스 requests나 limits가 지정되지 않았으므로 BestEffort QoS 클래스로 실행돼요. 공유 풀에서 실행됩니다.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
위 Pod는 리소스 requests가 limits와 같지 않고 cpu 수량이 지정되지 않았으므로 Burstable QoS 클래스로 실행돼요. 공유 풀에서 실행됩니다.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
requests:
memory: "100Mi"
cpu: "1"
위 Pod는 리소스 requests가 limits와 같지 않으므로 Burstable QoS 클래스로 실행돼요. 공유 풀에서 실행됩니다.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
requests:
memory: "200Mi"
cpu: "2"
위 Pod는 requests가 limits와 같으므로 Guaranteed QoS 클래스로 실행돼요. 그리고 CPU 리소스 한도가 1 이상의 정수입니다. nginx 컨테이너는 독점 CPU 2개를 부여받아요.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "1.5"
requests:
memory: "200Mi"
cpu: "1.5"
위 Pod는 requests가 limits와 같으므로 Guaranteed QoS 클래스로 실행돼요. 하지만 CPU 리소스 한도가 분수입니다. 공유 풀에서 실행됩니다.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
위 Pod는 limits만 지정되고 requests는 명시되지 않으면 limits와 같게 설정되므로 Guaranteed QoS 클래스로 실행돼요. 그리고 CPU 리소스 한도가 1 이상의 정수입니다. nginx 컨테이너는 독점 CPU 2개를 부여받아요.
Static 정책 옵션 (Static policy options)
static CPU 관리 정책에 사용 가능한 옵션들은 다음과 같아요 (알파벳 순).
align-by-socket(alpha, 기본으로 숨김) — 논리적 NUMA 경계 대신 물리 패키지/소켓 경계로 CPU를 정렬해요. (Kubernetes v1.25부터 사용 가능)distribute-cpus-across-cores(alpha, 기본으로 숨김) — 하드웨어 스레드라고도 불리는 가상 코어를 서로 다른 물리 코어에 분배해요. (Kubernetes v1.31부터 사용 가능)distribute-cpus-across-numa(beta, 기본으로 표시) — 선택된 도메인 사이에서 균형을 맞추도록 CPU를 서로 다른 NUMA 도메인에 분산해요. (Kubernetes v1.23부터 사용 가능)full-pcpus-only(GA, 기본으로 표시) — 항상 전체 물리 코어를 할당해요. (Kubernetes v1.22부터 사용 가능, v1.33에서 GA)strict-cpu-reservation(GA, 기본으로 표시) — QoS 클래스와 관계없이 모든 Pod가 예약 CPU에서 실행되지 않게 해요. (Kubernetes v1.32부터 사용 가능, v1.35에서 GA)prefer-align-cpus-by-uncorecache(GA, 기본으로 표시) — best-effort 방식으로 uncore(Last-Level) 캐시 경계로 CPU를 정렬해요. (Kubernetes v1.32부터 사용 가능)
다음 기능 게이트를 사용해 성숙도 수준에 따라 옵션 그룹을 켜고 끌 수 있어요.
CPUManagerPolicyBetaOptions(기본 활성화) — 끄면 beta 수준 옵션을 숨깁니다.CPUManagerPolicyAlphaOptions(기본 비활성) — 켜면 alpha 수준 옵션을 보여줍니다.
각 옵션을 사용하려면 여전히 kubelet 구성 파일의 cpuManagerPolicyOptions 필드로 활성화해야 해요. 각 옵션에 대한 자세한 내용은 아래를 계속 읽어보세요.
full-pcpus-only
full-pcpus-only 정책 옵션을 지정하면 static 정책은 항상 전체 물리 코어를 할당해요. 기본적으로 이 옵션 없이 static 정책은 토폴로지 인식 best-fit 할당으로 CPU를 할당합니다. SMT가 활성화된 시스템에서 이 정책은 하드웨어 스레드에 해당하는 개별 가상 코어를 할당할 수 있어요. 이는 서로 다른 컨테이너가 같은 물리 코어를 공유하게 만들 수 있는데, 이 동작이 noisy neighbours(소음 이웃) 문제의 원인이 됩니다. 이 옵션이 활성화되면, Pod는 모든 컨테이너의 CPU 요청을 전체 물리 코어를 할당해서 충족할 수 있는 경우에만 kubelet이 허용해요. Pod가 admission을 통과하지 못하면 SMTAlignmentError 메시지와 함께 Failed 상태가 됩니다.
distribute-cpus-across-numa
distribute-cpus-across-numa 정책 옵션을 지정하면, 할당을 충족하기 위해 NUMA 노드가 둘 이상 필요한 경우 static 정책은 NUMA 노드에 CPU를 균등하게 분배해요. 기본적으로 CPUManager는 하나의 NUMA 노드가 가득 찰 때까지 CPU를 채우고, 남은 CPU는 다음 NUMA 노드로 넘깁니다. 이는 배리어(barrier)나 이와 유사한 동기화 프리미티브에 의존하는 병렬 코드에서 원치 않는 병목 현상을 일으킬 수 있는데, 이런 코드는 가장 느린 워커만큼만 빠르게 실행되는 경향이 있기 때문이에요 (한 NUMA 노드에서 사용 가능한 CPU가 적어 그 워커가 느려집니다). CPU를 NUMA 노드에 균등하게 분배하면 애플리케이션 개발자는 단일 워커가 다른 워커보다 NUMA 영향을 더 받지 않도록 보장하기 쉬워져, 이런 유형의 애플리케이션 전체 성능이 개선돼요.
align-by-socket
align-by-socket 정책 옵션을 지정하면, 컨테이너에 CPU를 어떻게 할당할지 결정할 때 CPU가 소켓 경계에서 정렬된 것으로 간주됩니다. 기본적으로 CPUManager는 NUMA 경계에서 CPU 할당을 정렬하는데, 할당을 충족하기 위해 둘 이상의 NUMA 노드에서 CPU를 가져와야 한다면 성능 저하가 발생할 수 있어요. 최소 수의 NUMA 노드에서 모든 CPU를 할당하려고는 하지만, 이 NUMA 노드들이 같은 소켓에 있으리라는 보장은 없습니다. NUMA 경계 대신 소켓 경계에서 명시적으로 CPU를 정렬하도록 CPUManager를 지시하면 이런 문제를 피할 수 있어요. 참고로 이 정책 옵션은 TopologyManager의 single-numa-node 정책과 호환되지 않으며, 소켓 수가 NUMA 노드 수보다 많은 하드웨어에는 적용되지 않아요.
distribute-cpus-across-cores
distribute-cpus-across-cores 정책 옵션을 지정하면, static 정책은 가상 코어(하드웨어 스레드)를 서로 다른 물리 코어에 할당하려고 시도해요. 기본적으로 CPUManager는 가능한 한 적은 물리 코어에 CPU를 채우는 경향이 있는데, 이는 같은 물리 코어에서 CPU 간 경쟁을 일으켜 성능 병목 현상을 초래할 수 있어요. 이 정책을 활성화하면 static 정책은 CPU를 가능한 한 많은 물리 코어에 분산시켜 같은 물리 코어의 경쟁을 줄이고 전체 성능을 개선합니다. 다만 이 전략은 시스템이 과부하 상태일 때 효과가 덜할 수 있다는 점에 유의해야 해요. 그런 조건에서는 경쟁 감소의 이점이 줄어듭니다. 반대로 기본 동작은 코어 간 통신 오버헤드를 줄이는 데 도움이 되어 과부하 상태에서 오히려 더 나은 성능을 낼 수 있어요.
strict-cpu-reservation
KubeletConfiguration의 reservedSystemCPUs 파라미터(또는 폐기된 kubelet 커맨드라인 옵션 --reserved-cpus)는 OS 시스템 데몬과 쿠버네티스 시스템 데몬용 명시적 CPU 집합을 정의합니다. 이 파라미터에 대한 자세한 내용은 'Explicitly Reserved CPU List' 페이지에서 확인할 수 있어요. 기본적으로 이 격리는 정수 CPU 요청을 가진 guaranteed Pod에만 구현되며, burstable과 best-effort Pod(그리고 분수 CPU 요청을 가진 guaranteed Pod)에는 적용되지 않습니다. Admission은 CPU 요청을 allocatable CPU와만 비교해요. CPU 한도가 요청보다 높기 때문에, 기본 동작은 burstable과 best-effort Pod가 reservedSystemCPUs의 용량을 사용해 실제 배포에서 호스트 OS 서비스를 굶기는 것을 허용하게 됩니다. strict-cpu-reservation 정책 옵션이 활성화되면, static 정책은 reservedSystemCPUs에 지정된 CPU 코어를 어떤 워크로드도 사용하지 못하게 해요.
prefer-align-cpus-by-uncorecache
prefer-align-cpus-by-uncorecache 정책을 지정하면, static 정책은 컨테이너에 할당된 모든 CPU가 같은 uncore 캐시 블록(Last-Level Cache, LLC라고도 불림)을 공유하도록 개별 컨테이너의 CPU 리소스를 할당해요. 기본적으로 CPUManager는 CPU 할당을 빽빽하게 채워 컨테이너가 여러 uncore 캐시에서 CPU를 할당받게 할 수 있습니다. 이 옵션은 CPUManager가 uncore 캐시를 효율적으로 최대한 활용하도록 CPU를 할당하게 해요. 할당은 best-effort 방식으로 수행되어 같은 uncore 캐시 안에서 가능한 한 많은 CPU를 affine하게 하려고 노력합니다. 컨테이너의 CPU 요구량이 단일 uncore 캐시의 CPU 용량을 초과하면, CPUManager는 최적의 uncore 캐시 정렬을 유지하기 위해 사용되는 uncore 캐시 수를 최소화해요. 특정 워크로드는 캐시 간 지연 시간 감소와 캐시 수준에서의 noisy neighbors 감소로 성능 이점을 얻을 수 있어요. CPUManager가 노드에 충분한 리소스가 있는데도 최적으로 정렬하지 못하면, 컨테이너는 기본 packed 동작으로 여전히 admission됩니다.
Memory Manager
기능 상태: Kubernetes v1.32부터 stable, 기본 활성화
Memory Manager는 메모리 리소스에 대한 독점 리소스를 할당하는 kubelet 컴포넌트예요. 리소스 할당 결정을 내릴 때 Topology Manager와 상의합니다. 자세한 내용은 'Control Memory Management Policies on a Node' 문서를 읽어보세요.
Pod에 메모리를 할당하는 정책 (Policies for assigning memory to Pods)
쿠버네티스 Memory Manager는 Guaranteed QoS 클래스의 Pod를 위해 RAM(메모리, 선택적으로 Linux huge pages) 리소스를 할당해요.
Memory Manager는 힌트 생성 프로토콜(hint generation protocol)을 사용해 Pod에 가장 적합한 NUMA affinity를 산출합니다. Memory Manager는 이 affinity 힌트를 중앙 매니저인 Topology Manager에 공급해요. 힌트와 Topology Manager 정책을 모두 기반으로 Pod는 노드에 거부되거나 admission됩니다.
또한 Memory Manager는 Pod가 요청한 메모리가 최소 수의 NUMA 노드에서 할당되도록 보장합니다.
자세한 내용은 'Control Memory Management Policies on a Node' 문서를 읽어보세요.
Device Manager
기능 상태: Kubernetes v1.26부터 stable
Device Manager는 디바이스 플러그인 API를 사용해 하드웨어 디바이스를 Pod에 할당하는 kubelet 컴포넌트예요. 디바이스 플러그인이 제공하는 토폴로지 정보를 사용해 Topology Manager와 상의하며 리소스 할당 결정을 내립니다. 자세한 내용은 'Device Plugin Integration with the Topology Manager' 문서를 읽어보세요.
Pod 수준 리소스 매니저 (Pod-level resource managers)
기능 상태: Kubernetes v1.37부터 beta, 기본 비활성
kubelet 리소스 매니저(Topology, CPU, Memory)에 대한 Pod 수준 리소스 지원은 리소스 매니저가 NUMA 정렬과 독점 할당 결정에 .spec.resources를 직접 사용할 수 있게 해줘요.
자세한 내용은 전용 'Pod-level resource managers' 개념 페이지를 참고하거나, 실제 사용 방법을 읽어보세요.