인프라

[K8S] 클러스터의 리소스 분배 전략

하루이2222 2025. 6. 15. 19:22

Kubernetes 클러스터의 효율적인 리소스 분배 전략

이 글에서는 Kubernetes 클러스터의 안정성, 성능, 그리고 비용 효율성을 좌우하는 핵심 요소인 리소스 분배 전략에 대해 알아 보고자 하나. 단순히 Pod를 배포하는 것을 넘어, 클러스터의 자원을 어떻게 효율적으로 할당하고 관리할 것인지에 대한 구체적인 방법론을 알아보자.


1. 리소스 단위의 이해: 요청(Request)과 제한(Limit)

Kubernetes에서 리소스 관리의 가장 기본적인 단위는 **요청(Request)**과 **제한(Limit)**이다. 이 두 가지 값을 통해 우리는 Pod가 사용할 컴퓨팅 자원(CPU, 메모리)의 경계를 명확히 정의한다.

  • 요청 (Request): Pod가 정상적으로 실행되기 위해 보장받아야 할 최소한의 리소스 양이다.

    • 스케줄러의 역할: Kubernetes 스케줄러는 Pod를 노드에 배치할 때, 오직 Request 값만을 기준으로 판단한다. 즉, 한 노드에 있는 모든 Pod의 Request 총합은 해당 노드의 전체 용량을 초과할 수 없다.
    • 의미: Request는 Pod에게 할당이 '보장'되는 자원으로, 클러스터의 안정성을 확보하는 데 가장 중요한 역할을 한다.
  • 제한 (Limit): Pod가 최대로 사용할 수 있는 리소스의 상한선이다.

    • Kubelet의 역할: 노드에서 Limit을 초과하는 리소스 사용이 감지되면, Kubelet이 직접 개입하여 제재를 가한다.
    • 제재 방식:
      • CPU: 설정된 Limit을 초과하면 프로세스의 CPU 사용 시간을 강제로 줄인다 (CPU Throttling). 성능 저하의 원인이 될 수 있다.
      • Memory: 설정된 Limit을 초과하면 해당 컨테이너는 즉시 종료된다 (OOMKilled: Out of Memory).

설정 예시:
다음은 Pod에 RequestLimit을 설정하는 예시이다.

resources:
  requests:
    cpu: "500m"      # 0.5 CPU 코어를 보장받는다.
    memory: "256Mi"  # 256 Mebibytes의 메모리를 보장받는다.
  limits:
    cpu: "1"         # 최대 1 CPU 코어까지 사용할 수 있다.
    memory: "512Mi"  # 최대 512 Mebibytes의 메모리까지 사용할 수 있다.

2. Pod 배치를 결정하는 스케줄링 전략

스케줄러는 Request를 기반으로 Pod를 배치하지만, 특정 비즈니스 또는 기술적 요구사항에 따라 Pod가 특정 노드에 배치되거나 배치되지 않도록 제어하는 고급 전략을 사용할 수 있다.

  • NodeSelector: 가장 단순한 노드 선택 방식으로, 노드에 특정 **레이블(Label)**이 있는 경우에만 Pod를 배치하도록 강제한다. 예를 들어, disktype: ssd 레이블이 붙은 노드에만 Pod를 배포할 수 있다.

  • 어피니티와 안티-어피니티 (Affinity and Anti-Affinity): NodeSelector보다 훨씬 더 유연하고 강력한 규칙을 정의한다.

    • 노드 어피니티 (Node Affinity): "이러한 조건을 가진 노드에 배치하고 싶다"는 규칙이다. '반드시 만족해야 하는' hard rule(required)과 '가급적 만족하면 좋은' soft rule(preferred)을 함께 사용할 수 있다.
    • Pod 어피니티/안티-어피니티 (Pod Affinity/Anti-Affinity): "특정 Pod와 함께 혹은 멀리 배치하고 싶다"는 규칙이다. 예를 들어, 웹 서버 Pod와 캐시 Pod를 같은 노드에 배치하여 네트워크 지연 시간을 줄이거나(어피니티), 고가용성을 위해 데이터베이스 레플리카들을 서로 다른 노드에 분산 배치(안티-어피니티)하는 데 사용한다.
  • 테인트와 톨러레이션 (Taints and Tolerations): 특정 노드가 Pod를 밀어내도록 설정하는 방식이다.

    • 테인트 (Taint): 노드에 설정하는 '오염' 표시이다. 이 표시가 있는 노드에는 기본적으로 어떠한 Pod도 스케줄링되지 않는다.
    • 톨러레이션 (Toleration): Pod에 설정하는 '용인' 속성이다. Pod가 특정 Taint를 용인할 수 있다고 명시하면, 해당 Taint가 있는 노드에도 배치가 가능해진다.
    • 주요 용도: GPU가 장착된 노드, 또는 컨트롤 플레인 전용 노드 등 특수한 목적의 노드에 일반적인 워크로드가 배치되지 않도록 격리하는 데 매우 유용하다.

3. 서비스 안정성을 위한 QoS(Quality of Service) 클래스

Kubernetes는 Pod에 설정된 RequestLimit 값을 기반으로 세 가지 QoS 클래스 중 하나를 자동으로 할당한다. 이 클래스는 노드에 리소스가 부족해질 때 어떤 Pod를 먼저 종료시킬지 결정하는 우선순위가 된다.

  1. Guaranteed (최고 우선순위)

    • 조건: 모든 컨테이너의 RequestLimit이 동일하게 설정된 경우이다.
    • 특징: 예측 가능성이 가장 높고 안정적이다. 리소스 부족 상황에서 가장 마지막까지 실행이 보장된다. 중요한 데이터베이스나 핵심 애플리케이션에 적합하다.
  2. Burstable (중간 우선순위)

    • 조건: Request 값이 Limit 값보다 작은 경우이다.
    • 특징: 보장된 최소 리소스(Request)를 사용하다가, 노드에 여유 자원이 있으면 Limit까지 추가로 사용할 수 있다. 대부분의 일반적인 애플리케이션에 적합하며, 리소스 효율성과 안정성 사이의 균형을 제공한다.
  3. BestEffort (최저 우선순위)

    • 조건: RequestLimit이 모두 설정되지 않은 경우이다.
    • 특징: 노드에 남는 자원이 있을 때만 실행된다. 리소스가 부족해지면 가장 먼저 축출(Eviction) 대상이 된다. 중요도가 낮은 개발용 컨테이너나 배치 작업에 적합하다.

4. 리소스 효율성 극대화: 오버커밋과 축출 (Overcommit & Eviction)

  • 오버커밋 (Overcommit): 클러스터의 물리적 리소스보다 더 많은 양의 Pod Limit을 허용하는 전략이다. 이는 Request 기반으로 스케줄링하는 Kubernetes의 특성을 활용한 것이다. 대부분의 애플리케이션이 평소에는 Request만큼의 리소스만 사용한다는 점에 착안하여, 클러스터의 리소스 밀도를 높여 비용 효율성을 극대화한다.

  • 축출 (Eviction): 오버커밋 상태에서 여러 Pod가 동시에 리소스를 많이 사용하게 되면 노드는 리소스 압박(Pressure) 상태에 빠진다. 이때 Kubelet은 노드의 안정성을 위해 우선순위가 낮은 Pod부터 강제로 종료하여 자원을 회수하는데, 이를 **축출(Eviction)**이라 한다. 축출 순서는 QoS 클래스(BestEffortBurstableGuaranteed)와 리소스 사용량에 따라 결정된다.


5. 동적 환경에 대응하는 자동 확장 전략

워크로드의 변화에 따라 리소스를 동적으로 조절하는 자동 확장(Autoscaling) 기능은 Kubernetes의 핵심적인 장점이다.

  • Horizontal Pod Autoscaler (HPA): Pod의 개수를 수평적으로 자동 조절한다. CPU나 메모리 사용량 같은 메트릭을 기준으로, 사용량이 설정된 임계값을 넘으면 Pod의 복제본(Replica) 수를 늘리고, 낮아지면 줄인다. 트래픽 변동이 잦은 웹 서비스에 필수적이다.

  • Vertical Pod Autoscaler (VPA): Pod 자체의 리소스(RequestLimit)를 수직적으로 자동 조절한다. Pod의 과거 리소스 사용 패턴을 분석하여 최적의 Request 값을 추천하거나, 자동으로 적용한다. 수평 확장이 어려운 상태 저장(Stateful) 애플리케이션의 리소스 최적화에 유용하다.

  • Cluster Autoscaler (CA): 노드의 개수 자체를 자동 조절한다. 리소스 부족으로 인해 스케줄링되지 못하는 'Pending' 상태의 Pod가 발생하면, 클러스터에 새로운 노드를 추가한다. 반대로, 오랫동안 사용률이 낮은 노드가 있으면 해당 노드를 클러스터에서 제거하여 비용을 최적화한다.


결론

효과적인 Kubernetes 리소스 분배 전략은 단일 설정이 아닌, 여러 메커니즘의 조합으로 이루어진다. **RequestLimit**으로 개별 Pod의 리소스 경계를 설정하고, 이를 기반으로 QoS 클래스가 서비스의 안정성을 보장한다. 스케줄링 전략을 통해 워크로드를 적재적소에 배치하고, 오버커밋으로 자원 효율성을 높이며, 마지막으로 자동 확장(Autoscaling) 전략을 통해 변화하는 부하에 동적으로 대응하는 것이다. 이러한 요소들이 종합적으로 적용할 될때, 안정적이고 비용 효율 적인 운영이 가능하다.