Memory ReqLim 실제 컨테이너 설정

정의 (Definition)

Kubernetes(cgroup v2)에서 일반적인 구성(특히 MemoryQoS 비활성)에서는 메모리 limit만 memory.max로 강제되며, request에 해당하는 하한(memory.min/memory.low)은 기본적으로 보장되지 않습니다. 문제가 되는 배경 (Problem Context) request는 스케줄링(배치) 기준으로 쓰이지만, 커널 레벨에서 “절대 회수되지 않는 하한”으로 자동 변환되는 것은 아닙니다. 따라서 노드 메모리 압박 상황에서는 request만 믿고 “보호된다”고 가정하면 성능 저하/축출(eviction)로 이어질 수 있습니다.

핵심 메커니즘 (How it Works)

컨테이너가 속한 cgroup에서 다음 파일을 확인하면, kubelet이 어떤 값을 적용했는지 관찰할 수 있습니다.

kubectl exec tempo-ingester-0 -n tempo -- cat /sys/fs/cgroup/memory.min
kubectl exec tempo-ingester-0 -n tempo -- cat /sys/fs/cgroup/memory.low
kubectl exec tempo-ingester-0 -n tempo -- cat /sys/fs/cgroup/memory.high
kubectl exec tempo-ingester-0 -n tempo -- cat /sys/fs/cgroup/memory.max

관찰 예(해당 시점):

  • memory.min = 0
  • memory.low = 0
  • memory.high = max
  • memory.max = 17179869184 (16GiB)

즉, 이 관찰에서는 상한(limit)만 적용 되어 있고, 하한(request 기반 보호)는 적용되지 않았습니다.

불변 조건과 보장 범위 (Invariants & Guarantees)

  • 보장: memory.max는 cgroup v2에서 강제 상한입니다(초과 시 OOM/kill 경로로 이어질 수 있음).
  • 비보장: memory.min/memory.low가 0이 아닌 값으로 설정된다고 보장할 수 없습니다(설정은 kubelet 기능/feature gate/배포판 정책에 의존).

비유 (Analogy)

limit는 “상한선(천장)”이고, request는 “예약(장부상의 몫)”에 가깝습니다. 예약이 곧바로 커널의 “절대 보장(바닥)”으로 변환되는 것은 아닙니다.

실무적 함의 (Operational Implications)

  • request만으로는 노드 압박에서 보호되지 않을 수 있으므로, 축출/성능 저하를 고려해 워크로드 특성에 맞는 request/limit 설계가 필요합니다.
  • request 기반 커널 보호가 필요하다면, K8s MemoryQoS 같은 메커니즘(단, 알파/지원 범위)을 먼저 확인해야 합니다.

주의사항 / 오해 (Pitfalls & Misconceptions)

  • “request를 줬으니 커널이 보호한다”는 가정은 환경에 따라 성립하지 않습니다.
  • cgroup 파일 경로는 컨테이너 런타임/구성에 따라 달라질 수 있으므로, 반드시 해당 컨테이너의 cgroup 을 확인해야 합니다.

References