CKA를 준비해보자 10일차 - Resource and Requirements

0

CKA

목록 보기
10/43

Resource Requirements

pod에는 필요로 하는 cpu, memory 자원량이 있는데, 현재 node의 자원 현황을 토대로 이 pod들을 배치시켜주는 것이 kubernetes scheduler의 몫이다.

가령 다음과 같은 예를 보도록 하자.

Pod1: CPU 2, Memory 1
Pod2: CPU 2, Memory 1

Node1: CPU 8, Memory 8
Node2: CPU 8, Memory 8

다음의 상황에서 pod들은 node에 할당될 때, 다음과 같이 할당될 수 있다.

Node1: CPU 4, Memory 6 (Pod1, Pod2)
Node2: CPU 8, Memory 8

이 다음 Pod3이 Node1보다 더 많은 자원량을 필요로 한다면 Node1이 아니라 Node2로 배정될 것이다.

Pod3: CPU: 5, Memory: 7

Node1: CPU 4, Memory 6 (Pod1, Pod2)
Node2: CPU 8, Memory 8

Node1으로는 Pod3가 감당이 되지 못하니 Node2로 배정된다.

Node1: CPU 4, Memory 6 (Pod1, Pod2)
Node2: CPU 3, Memory 1 (Pod3)

그런데, Pod4가 왔는데, 배정될 충분한 자원을 가진 Node가 없다면 어떻게될까?? 그런 경우 Insufficient event가 발생하여 어느 node에도 pod4가 배정되지 않아 Pending상태가 되어버리고 만다.

Pod4: CPU 5, Memory 7

Node1: CPU 4, Memory 6 (Pod1, Pod2)
Node2: CPU 3, Memory 1 (Pod3)

Pod4는 Pending상태에 빠지고 FailedScheduling event가 발생한다.

이렇게 pod에 최소 자원량을 요구하는 것이 바로 Resource Requests이다. pod안에 spec.containers.resources안에 node에 최소로 요구할 자원량을 넣어주면 된다.

  • pod-definition.yaml
apiVersion: v1
kind: Pod
metadata:
  name: simple-webapp-color
  labels:
    name: simple-webapp-color
spec:
  containers:
  - name: simple-webapp-color
    image: simple-webapp-color
    ports:
    - containerPort: 8080
    resources:
      requests:
        memory: "4Gi"
        cpu: 2

스케줄러에 의해 pod가 배정될 node를 찾을 때, 해당 자원량만큼의 여유 공간이 있는 node를 찾아배정해주는 것이다.

그럼 CPU의 숫자값은 무엇을 의미하는 것을까?? 이것은 vCPU 또는 1 CPU core를 말하는 것으로 생각하면 된다.

Memory는 M, Mi와 같이 뒤에 접미사로 i가 붙은 값들이 있는데, 이 경우는 2의 배수로 측정된 값이라고 생각하면 된다.

1G (Gigabyte) = 1,000,000,000 bytes
1M (Megabyte) = 1,000,000 bytes
1K (Kilobyte) = 1,000 bytes

1 Gi(Gibibyte) = 1,073,741,824 bytes
1 Mi(Mebibyte) = 1,048,576 bytes
1 Ki(Kibibyte) = 1,024 bytes

문제는 기본적으로 container에는 자원 제한량이 없기 때문에 실제로 requests보다 더 많은 양의 자원을 사용할 수도 있다. 그래서 사용하는 것이 바로 Resource Limits이다.

  • pod-definition.yaml
apiVersion: v1
kind: Pod
metadata:
  name: simple-webapp-color
  labels:
    name: simple-webapp-color
spec:
  containers:
  - name: simple-webapp-color
    image: simple-webapp-color
    ports:
    - containerPort: 8080
    resources:
      requests:
        memory: "1Gi"
        cpu: 1
      limits:
        memory: "2Gi"
        cpu: 2

다음과 같이 최대 제한량을 limits로 제한 둘 수 있는 것이다. 단, 이는 container단위이기 때문에 pod단위로 생각해서는 안된다.

그런데, 만약 container가 제한된 자원량 이상으로 요구를 하려고 한다면 어떻게 될까?? 가령 memory의 경우 limit보다 더 많은 자원량을 요구하게 되는 경우 OOM(out of memory)가 발생하며 container가 들어가 있는 pod도 함께 terminate된다. 이 동작을 OOMK(out-of-memory kill)이라고 한다.

Default behavior

재밌는 것은 requests만 있을 때, limits만 있을 때의 default동작들이 있다는 것이다.

먼저 CPU측면에서만 보도록 하자.

Pod1
Pod2

Node1: 6 CPU

다음의 상황에서 두 pod가 모두 requests도 없고, limits도 없다고 하자. 그렇다면 다음과 같이 Node1의 자원을 모두 소모할 수도 있게 된다.

  • No Requests, No Limits
Pod2 
Node1: 0 CPU (Pod1: 6 CPU)

만약 Limits를 걸어주면 어떻게 될까? 두 pod에 Limit로 3 CPU를 걸어주면, 아무리 최대로 pod가 자원을 할당해도 3 CPU를 넘지 않는다.

  • No Requests, Limits
Node1: 0 CPU (Pod1: 3 CPU, Pod2: 3 CPU)

다음으로 RequestsLimits를 모두 넣어주면 어떻게될까?? Requests로 두 pod 모두 1 CPU씩 할당해주고 Limits3 CPU를 넣어주면 다음과 같이 된다.

  • Requests, Limits
Node1: 4 (Pod1: 1 CPU, Pod2: 1 CPU)

먼저 pod들이 요청을 적게받아 널널할 때는 다음과 같이 Requests양만큼만 최소로 자원을 잡게 된다.

그런데, pod들이 요청을 받게되어 부하가 커지면 다음과 같이 된다.

  • Requests, Limits
Node1: 0 (Pod1: 3 CPU, Pod2: 3 CPU)

두 pod모두 아무리 많은 요청을 받아도 Limits인 3을 넘지 않는 것이다.

마지막으로 Requests만 설정할 때이다. 두 pod 모두 requests를 1 CPU로 설정하고, 요청이 적은 경우는 다음과 같이 된다.

  • Requests, No Limits
Node1: 4 (Pod1: 1 CPU, Pod2: 1 CPU)

그런데, 갑자기 Pod1에 대한 요청이 많아진다고 하자. limit이 없는데 어떻게될까??

  • Requests, No Limits
Node1: 0 (Pod1: 5 CPU, Pod2: 1 CPU)

다행이도 Pod2Reuqests로 1 CPU가 있다보니 Pod2의 자원까지 소모하진 않게된다. 따라서 Pod1은 자원이 쭉쭉 올라가서 5 CPU까지 넘보게되지만 Node1의 모든 자원이 Pod1에만 한정되는 것이 아니게 되는 것이다.

가장 좋은 방법은 Requests - No Limits 조합이다. 이렇게 하면 유연하 자원 소모율이 변하고, 다른 pod들도 서비스에 크게 영향을 미치지 않게되기 때문이다.

따라서, 모든 pod마다 Requests를 반드시 설정해주는 것이 좋다.

CPU뿐만 아니라 memory측면도 사실 위의 example과 동작이 동일하다.

LimitRange

그런데 사용자가 RequestsLimits가 없는 pod들을 만드는데, 이를 global하게 default RequestsLimits를 제공하고 싶다면 어떻게 해야할까?? 이를 가능하게 해주는 것이 바로 LimitRange이다.

  • limit-range-cpu.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-resource-constraint
spec:
  limits:
  - default:
      cpu: 500m
    defaultRequest:
      cpu: 500m
    max:
      cpu: "1"
    min:
      cpu: 100m
    type: Container

참고로 LimitRange는 namespace 영향을 받으므로 해당 namespace에서 배포되는 pod에만 적용된다고 생각하면 된다.

  1. limits.default.cpu: pod에 limits, requests값이 없다면 자동으로 이 값을 pod의 limits, requests로 설정해준다.
  2. limits.defaultRequest.cpu: pod에 requests가 없다면 해당 값으로 requests를 설정해준다.
  3. limits.max.cpu: 추가된 pod에 설정된 requestslimit의 최대값으로 이 값을 넘지 않도록 해야한다.
  4. limits.min.cpu: 추가된 pod에 설정된 requestslimit의 최소값으로 이 값보다는 커야한다.

메모리 역시도 마찬가지이다. cpu부분만 memory로 바꾸면 된다.

ResourceQuota

LimitRange는 namespace단위로 namespace안에 배포되는 pod에 대한 requests, limits를 설정하고 제한한다면, ResourceQuota는 namespace 자체에 최대 자원량을 제한한다. 따라서 namespace안에 전체 pod의 자원량을 제한하는 기능을 제공하는 것이다.

  • resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
tadata:
  name: my-resource-quota
  namespace: target
spec:
  hard:
    requests.cpu: 4
    requests.memory: 4Gi
    limits.cpu: 10
    limits.memory: 10Gi

위의 ResourceQuotatarget namespace에 대해서 자원량 최대를 제한하는 것이다. 참고로 kubernetes object의 갯수, 특정 object의 자원량을 제한하는 기능들이 있다.

0개의 댓글