[Kubernetes] 파드의 컴퓨팅 리소스 관리

Dev·2022년 12월 29일
0

파드의 예상 소비량과 최대 소비량을 설정하는 것은 파드 정의에서 매우 중요하다. 이는 리소스를 공평하게 공유하고, 클러스터 전체에서 파드가 스케줄링되는 방식에도 영향을 미친다.

1. Request와 Limit

  • 파드를 생성할 때 컨테이너가 필요로하는 cpu, memory에 엄격한 제한을 지정할 수 있다.
  • 컨테이너에 개별적으로 지정되며 파드 전체에 지정되지 않는다. 이때 파드는 모든 컨테이너의 요청과 제한의 합으로 계산된다.
  • cpu 요청을 지정하지 않으면 컨테이너에 실행중인 프로세스에 할당되는 cpu 시간에 신경쓰지 않는다는 것과 같다. 하지만 최악의 경우 cpu 시간을 전혀 할당받지 못할수도 있다. 이는 다른 프로세스가 cpu 요청을 많이 한 상황에서 발생할 수 있다. 이러한 이유로 배치같은 경우 cpu를 지정하지 않을 수도 있으나, 웹 애플리케이션에서는 필수적으로 지정하는 것이 좋다.
apiVersion: v1
kind: Pod
metadata:
  name: requests-pod
spec:
  containers:
  - image: busybox
    command: ["dd", "if=/dev/zero", "of=/dev/null"]
    name: main
    resources:
      requests:              # 컨테이너 리소스 요청
        cpu: 200m         # cpu 200밀리코어 (1 core : 1000m 또는 1, 200밀리코어는 1/5 core 시간을 의미)
        memory: 10Mi   # 10Mi 메모리를 요청

2. Request

[1] 특징

  • 파드에 필요한 리소스의 최소량을 지정할 수 있다.
  • 스케줄러는 파드를 스제줄링할 때 먼저 파드의 리소스 요청 사항을 만족하는 충분한 리소스를 가진 노드만을 고려한다.
  • 스케줄러는 스케줄링하는 시점에 각 개별 리소스가 얼마나 사용되는지 보지 않고, 노드에 배포된 파드들의 리소스 요청량의 전체 합만을 기준으로 처리한다. 이는 실제 리소스 사용량에 기반해 다른 파드를 스케줄링한다는 것은 이미 배포된 파드에 대한 리소스 요청 보장을 깨뜨릴 수 있기 때문이다.

[2] CPU 시간 공유

  • CPU 요청은 단지 스케줄링에만 영향을 미칠 뿐만 아니라 남은 CPU 시간을 파드에 분배하는 방식도 결정한다. 미사용된 CPU는 두 파드 사이에 요청 비율에 맞게 나눠진다.
  • 이외에도 한 컨테이너가 CPU를 최대로 사용하려는 순간 나머지 파드가 유휴상태에 있다면 전체 CPU를 사용할 수도 있다. (아무도 사용하지 않는다면 사용 가능한 모든 CPU를 사용 가능하다.)

3. Limit

[1] 특징

  • 특정 컨테이너가 지정한 CPU 양보다 많은 cpu를 사용하는 것을 막고 싶을 수 있다.
  • cpu는 압축 가능한 리소스이므로 프로세스에 악영향을 주지 않으면서 컨테이너가 사용하는 cpu 양을 조절할 수 있다.
  • 반면 메모리는 프로세스에 주어지면 프로세스가 메모리를 해제하지 않는 한 다른 프로세스에서 사용할 수 없다. 그래서 컨테이너에 할당되는 메모리의 최대량을 제한해야한다.
  • 메모리를 제한하지 않으면 워커노드에 실행 중인 컨테이너는 사용 가능한 모든 메모리를 사용해서 노드에 있는 다른 모든 파드와 노드에 스케줄링되는 새 파드에 영향을 미칠 수 있다.
  • 쿠버네티스는 모든 컨테이너의 리소스에 제한을 지정할 수 있으며, 리소스 요청을 지정하지 않고 제한만 지정한 경우 자동적으로 요청과 제한이 동일한 값으로 설정된다.
  • 리소스 요청과 달리, 리소스 제한은 노드의 할당 가능한 리소스 양으로 제한하지 않고 오버커밋될 수 있다.(노드 용량 100%를 초과할 수 있다.)
  • 여기서 노드 리소스의 100%가 다 소진되면 특정 컨테이너는 제거가 되어야한다. 쿠버네티스에서는 리소스 제한을 초과해 사용하려고 하거나 초과하는 경우 컨테이너를 제거한다.

[2] 리소스 제한 초과

  • CPU 제한이 설정돼 있으면 프로세스는 설정된 제한보다 많은 cpu 시간을 할당받을 수 없다.
  • 메모리의 경우는 cpu와 달리 제한보다 많은 메모리를 할당받으려 시도하면 프로세스는 강제 종료된다. (컨테이너 OOMKilled)
  • 파드의 재시작 정책(restart policy)이 Always 또는 Onfailure로 설정된 경우 프로세스는 즉시 다시 지작하므로 이를 알아차리지 못할 수도 있다.
  • 메모리 제한 초과가 지속적으로 반복하면 쿠버네티스는 재시작 사이의 지연 시간을 증가시키면서 재시작한다. 이런 재시작의 경우 CrashLoopBackOff STATUS를 갖는다.

[3] CrashLookBackOff

  • 이 상태는 크래시 후 kubelet이 컨테이너를 다시 시작하기 전에 간격을 늘리는 상태를 의미한다.
  • 첫번째 크래시 후에 kubelet은 컨테이너를 즉시 다시 시작하고, 다시 크래시가 발생하면 10초를 기다리고, 그이후에는 20초 40초 80초 지수 단위로 증가하다가 마지막 300초로 제한한다.
  • 크래시된 이유는 로그를 보면되는데 대표적으로 OOMKilled가 있다.
  • 컨테이너가 종료되는 것을 원하지 않는답면 메모리 제한을 너무 낮게 설정하지 않는 것이 중요하다. 하지만 컨테이너가 제한을 넘어서지 않아도 OOMKilled되는 경우도 있다.

[4] 컨테이너의 애플리케이션이 제한을 바라보는 방법

컨테이너는 항상 컨테이너 메모리가 아닌 노드의 메모리를 바라본다.

  • 컨테이너 내부에서 top 명령을 수행해보면 컨테이너가 실행중인 전체 노드의 메모리양을 표시한다. (컨테이너 레벨에서 인식할 수 없다.)
  • JVM은 컨테이너에 사용 가능한 메모리 대신 호스트(노드)의 총 메모리를 기준으로 힙 크기를 설정하여 컨테이너 레벨에서 OOMKilled 위험이 있다. (최대 힙 크기를 지정하지 않은 경우 JVM GC가 돌기 전에 메모리 제한을 넘어서 OOMKilled 될 수 있음)
    컨테이너는 노드의 모든 CPU 코어를 본다.

메모리와 마찬가지로 컨테이너에 설정된 CPU 제한과 관계없이 노드의 모든 CPU를 본다.

  • CPU 제한이 하는 일은 컨테이너가 사용할 수 있는 CPU 시간의 양을 제한하는것 뿐이다.
  • CPU 제한이 1코어로 설정되더라도 컨테이너의 프로세스는 한 개 코어에서만 실행되는 것이 아니다.
    쿠버네티스 클러스터에서 애플리케이션을 개발할때 주의할 점은 시스템의 CPU 코어수를 기준으로 작업 스레드를 결정하는 경우에 문제가 될 수 있다.

4. 네임스페이스별 파드에 대한 기본 요청과 제한 설정

컨테이너 리소스 요청과 제한을 설정하지 않으면 컨테이너는 이를 설정한 다른 컨테이너에 의해 좌지우지된다. 그래서 모든 컨테이에 리소스 요청과 제한을 설정하는 것이 좋다.

[1] LimitRange 리소스

  • 모든 컨테이너에 리소스 요청과 제한을 설정하는 대신 LimitRage 리소스를 생성해 이를 수행할 수 있다.
  • 컨테이너의 각 리소스(네임스페이스별) 최소/최대 제한을 지정할 수 있고, 리소스 요청을 명시적으로 지정하지 않은 컨테이너의 기본 리소스 요청을 지정할 수 있다.

[2] LimitRange 오브젝트

  • 컨테이너 레벨에서 보면 최소값, 최대값 뿐만 아니라 리소스 요청과 제한을 명시적으로 지정하지 않은 각 컨테이너에 적용될 기본 요청(defaultRequest)와 기본 제한(default)을 설정할 수 있다.
  • 또한 maxLimitREquestRatio을 통해 제한 대 요청 비율을 설정할 수 있다.(cpu 4의 의미는 cpu limit은 cpu request보다 4배 이상 큰 값이 될 수 없다.)
  • 단일 PVC에서 요청 가능한 스토리지 양을 제한 할수도 있다.
  • 하나의 LimitRange 리소스로 관리할수도 있고, 각 type별로 쪼개서 관리할수도 있다.
  • 다른 쿠버네티스 매커니즘과 마찬가지로 나중에 수정된 사항은 기존 파드 및 PVC 등에 영향을 미치지 않는다.

[3] ResourceQuota 리소스

  • 리소트쿼터는 LimitRange와 마찬가지로 네임스페이스 기준으로 동작한다.
  • 파드가 사용할 수 있는 컴퓨팅 리소스 양과 퍼시스턴트볼륨클레임이 사용할 수 있는 스토리지 양 등을 제한할 수 있다.
  • 네임스페이스 내에서 모든 파드들의 할 수 있는 요청과 제한의 최대값을 지정한다.
  • 각 개별 파드나 컨테이너에 개별적으로 적용하지 않고 모든 파드의 리소스 요청과 제한의 총합에 적용된다.
  • 리소스쿼터를 생성할 때 주의할 점은 LimitRange 오브젝트와 함꼐 생성해야 한다는 것이다.
  • LimitRange에 default가 없는 경우, 리소스 요청이나 제한도 명시하지 않은 파드는 아예 생성할 수 없게 된다.
  • 또한, 퍼시스턴트 스토리지에 관한 쿼터 지정할 수도 있다.

쿠버네티스 클러스터를 최대한 활용하기 위해 리소스 요청과 제한을 적절하게 설정하는 것은 매우 중요한 일이다. 하지만 적정 값을 찾으려면 모니터링이 필요하다. 예상되는 부하 수준에서 컨테이너의 실제 리소스 사용량을 모니터링하고, 필요한 경우 리소스 요청과 제한을 조정해야 한다.

profile
성장하는 개발자가 되고싶어요

0개의 댓글