토폴로지 관리 문제 해결

토폴로지 관리 문제 해결 (Troubleshooting Topology Management)

쿠버네티스는 파드가 노드에서 실행되는 방식의 많은 측면을 사용자로부터 추상화해요. 이는 의도적인 설계예요. 하지만 일부 워크로드는 수용 가능하게 동작하려면 지연 시간 및/또는 성능 측면에서 더 강한 보장을 요구해요. kubelet은 추상화를 명시적 배치 지시로부터 자유롭게 유지하면서 더 복잡한 워크로드 배치 정책을 활성화할 수 있는 방법을 제공해요.

노드 안에서 토폴로지를 관리할 수 있어요. 이는 파드와 컨테이너가 NUMA 도메인 같은 내부 경계의 올바른 쪽에 배치되도록 kubelet이 호스트 운영 체제를 구성하는 데 도움을 주는 것을 의미해요. (NUMA는 non-uniform memory access 의 약어로, 하드웨어 컴포넌트의 물리적 배치와 연결 방식 때문에 CPU가 메모리의 특정 영역에 토폴로지상 더 가까울 수 있다는 아이디어를 가리켜요.)

출처: 문서

본문

문제 해결 정보의 원천

토폴로지 관리 맥락에서 파드가 노드에 배포되지 못했거나 거부된 이유를 해결하기 위해 다음 수단을 사용할 수 있어요:

  • Pod status — 토폴로지 선호도 오류를 나타내요
  • 시스템 로그 — 디버깅에 유용한 정보를 포함해요. 예: 생성된 hints에 대한 정보
  • kubelet 상태 파일 — Memory Manager의 내부 상태 덤프(node mapmemory maps 포함)
  • device plugin resource API를 사용해 컨테이너에 예약된 메모리에 대한 정보를 검색할 수 있어요

TopologyAffinityError 해결하기

이 오류는 일반적으로 다음 상황에서 발생해요:

  • 노드에 파드의 요청을 충족할 충분한 리소스가 없는 경우
  • 특정 Topology Manager 정책 제약 때문에 파드의 요청이 거부된 경우

오류는 파드의 상태에 나타나요:

kubectl get pods
NAME         READY   STATUS                  RESTARTS   AGE
guaranteed   0/1     TopologyAffinityError   0          113s

kubectl describe pod <id> 또는 kubectl events 를 사용해 자세한 오류 메시지를 얻어요:

Warning  TopologyAffinityError  10m   kubelet, dell8  Resources cannot be allocated with Topology locality

시스템 로그 검사하기

특정 파드와 관련해 시스템 로그를 검색해요.

CPU Manager가 생성한 hints 집합이 로그에 있어야 해요. 또한 Memory Manager가 그 파드에 대해 생성한 hints 집합도 로그에서 찾을 수 있어요.

Topology Manager는 이 hints를 병합해 단일 최적 hints를 계산해요. 최적 hints도 로그에 있어야 해요.

최적 hints는 모든 리소스를 어디에 할당할지를 나타내요. Topology Manager는 이 hints를 현재 정책에 대해 테스트하고, 그 판정에 따라 파드를 노드에 허용하거나 거부해요.

또한 Memory Manager와 관련된 로그 발생을 검색해요. 예를 들어 cgroupscpuset.mems 업데이트에 대한 정보를 알아보려고요.

예시

노드의 memory manager 상태 살펴보기

먼저 스펙이 다음과 같은 샘플 Guaranteed 파드를 배포해요:

apiVersion: v1
kind: Pod
metadata:
  name: guaranteed
spec:
  containers:
  - name: guaranteed
    image: consumer
    imagePullPolicy: Never
    resources:
      limits:
        cpu: "2"
        memory: 150Gi
      requests:
        cpu: "2"
        memory: 150Gi
    command: ["sleep","infinity"]

다음으로 배포된 노드에 로그인하고 /var/lib/kubelet/memory_manager_state 의 상태 파일을 살펴봐요:

{
   "policyName":"Static",
   "machineState":{
      "0":{
         "numberOfAssignments":1,
         "memoryMap":{
            "hugepages-1Gi":{
               "total":0,
               "systemReserved":0,
               "allocatable":0,
               "reserved":0,
               "free":0
            },
            "memory":{
               "total":134987354112,
               "systemReserved":3221225472,
               "allocatable":131766128640,
               "reserved":131766128640,
               "free":0
            }
         },
         "nodes":[
            0,
            1
         ]
      },
      "1":{
         "numberOfAssignments":1,
         "memoryMap":{
            "hugepages-1Gi":{
               "total":0,
               "systemReserved":0,
               "allocatable":0,
               "reserved":0,
               "free":0
            },
            "memory":{
               "total":135286722560,
               "systemReserved":2252341248,
               "allocatable":133034381312,
               "reserved":29295144960,
               "free":103739236352
            }
         },
         "nodes":[
            0,
            1
         ]
      }
   },
   "entries":{
      "fa9bdd38-6df9-4cf9-aa67-8c4814da37a8":{
         "guaranteed":[
            {
               "numaAffinity":[
                  0,
                  1
               ],
               "type":"memory",
               "size":161061273600
            }
         ]
      }
   },
   "checksum":4142013182
}

상태 파일에서 파드가 두 NUMA 노드 모두에 고정(pinned)됐음을 추론할 수 있어요:

"numaAffinity":[
   0,
   1
],

고정(pinned)이라는 용어는 파드의 메모리 소비가(cgroups 구성을 통해) 이 NUMA 노드들로 제약된다는 뜻이에요.

이는 자동으로 Memory Manager가 이 두 NUMA 노드, 즉 인덱스 01 NUMA 노드로 구성된 새 그룹을 인스턴스화했다는 것을 의미해요.

그룹에서 사용 가능한 메모리 리소스를 분석하려면 그룹에 속한 NUMA 노드의 해당 항목을 더해야 해요.

예를 들어 그룹의 총 "일반" 메모리 양은 그룹의 각 NUMA 노드에서 사용 가능한 여유 메모리를 더해 계산할 수 있어요. 즉 NUMA 노드 0("free":0)과 NUMA 노드 1("free":103739236352)의 "memory" 섹션을 더하는 것이에요. 따라서 이 그룹의 총 여유 "일반" 메모리 양은 0 + 103739236352 바이트예요.

"systemReserved":3221225472 줄은 이 노드의 관리자가 --reserved-memory 플래그를 사용해 NUMA 노드 0 에서 kubelet과 시스템 프로세스를 제공하기 위해 3221225472 바이트(즉 3Gi)를 예약했음을 나타내요.

device plugin resource API 확인하기

kubelet은 리소스와 관련 메타데이터의 발견을 활성화하는 PodResourceLister gRPC 서비스를 제공해요. List gRPC 엔드포인트를 사용하면 각 컨테이너에 예약된 메모리에 대한 정보를 검색할 수 있어요. 이 정보는 protobuf ContainerMemory 메시지에 포함돼 있어요.

이 정보는 Guaranteed QoS 클래스의 파드에 대해서만 검색할 수 있어요.

더 알아보기 (Learn more)