클라우드 컴퓨팅 & NoSQL/도커 & 쿠버네티스

쿠버네티스 #25 - Pod 스케쥴링 #3 리소스 부족 관리

Terry Cho 2019. 8. 15. 16:15

쿠버네티스 고급 스케쥴링

#3 리소스 부족 (Resource starving) 관리


조대협 (http://bcho.tistory.com)


request와 limit의 개념이 있기 때문에 생기는 문제인데, request 된 양에 따라서 컨테이너를 만들었다고 하더라도, 컨테이너가 운영이되다가 자원이 모자르면 limit 에 정의된 양까지 계속해서 리소스를 요청하게 된다.

 컨테이너의 총 Limit의 양이 실제 시스템이 가용한 resource의 양보다 많을 수 있는 경우가 발생한다. 처음 CPU resource가 1 CPU 였는데, limit이 4이면,Pod 가 배포된 후에, 동작하다가 limit 양까지 증가되서 4 CPU가 되어 버릴 수 있다. 이때 node의 물리 CPU가 4 이면, CPU 리소스 부족이 발생할 수 있다. 이렇게 limit의 총량이 물리 resource의 총량 보다 많은 상황을 over committed 상태라고 한다.


Node에서 리소스 부족이 발생하면 쿠버네티스 클러스터는 이 상태를 해결하기 위해서 부족한 리소스를 회수하기 시작한다. 

리소스에 종류에 따라서 다른 동작을 하는데, 크게 Compressible 리소스와 Un-compressible 리소스에 따라 동작 방식이 다르다.

Compressible resource

Compressible resource는 CPU와 같이 할당된 리소스 양을 줄일 수 있는 리소스이다. 리소스 부족이 발생하면, node에 배포된 Pod의 CPU를 현재 사용하고 있는 양에서 초반 생성할때 할당된 request 크기까지 강제적으로 줄여서 리소스 부족을 해결한다. 이를 throttling 이라고 한다

이 경우 문제는 CPU 사용량일 request 이상으로 증가한 것은 그만큼 그 Pod가 애플리케이션을 동작시키기 위해서 CPU가 필요하였기 때문에 추가 할당되었던 것이다. Request 크기 까지 줄이면 할당된 CPU양을 강제적으로 줄이는 것이기 때문에, 성능 저하가 발생할 수 있다.

이런 문제를 예방하려면, Pod를 배포할때 request와 limit 값을 같이 주면, throttling은 발생하지 않지만 정확히 얼마의 CPU를 할당해야 하는지가 중요하다. 그래서 Pod 별로 적정한 CPU양을 계산하기 위해서는 개발/테스트 환경에서 request/limit 값을 서로 다르게 준 상태에서 부하 테스트를 통해서 적정 CPU 양을 찾아낸 후에 그 값을 적용하는 것이 좋다. 

Un-compressible resource

메모리나 로컬 디스크 공간은 compressible resource에 해당하지 않기 때문에, 강제적으로 Throttle을 할 수 없다. 그래서 쿠버네티스 클러스터는 리소스를 수거하기 위해서 리소스 사용량이 많은 Pod를 강제로 종료 시킨다. 

로컬 디스크의 경우에는 Pod를 강제 종료 시키기전에, 사용되지 않은 컨테이너 이미지등 사용되지 않은 공간을 삭제 해서 먼저 공간 확보를 시도하고, 그래도 공간이 모자르면 우선 순위에 따라서 Pod를 하나 삭제 한다. 삭제된 Pod는 컨트롤러 (ReplicaSet 등)에 의해서 관리가 되고 있으면 자동으로 다른 Node에서 생성된다. 

메모리의 경우에는 캐슁되는 이미지공간등이 없기 때문에, 바로 Pod를 우선순위에 따라서 삭제한다. 이를 Eviction이라고 한다.

우선 순위를 결정하는 로직은 복합적인 값들이 관여되는데, PodPriority 등, Pod 의 우선 순위등이 관련되는데, 대체적으로 Pod의 리소스 사용량이 request에 비해서 오버된 양이 가장 큰 Pod를 우선적으로 삭제 한다. 

예를 들어서 request가 3G, 4G 인 Pod가 각각 있고, 사용량이 5G, 4G 이면, request가 3G인 Pod가 사용량이 2G가 초과했고, 4G인 Pod는 초과하지 않았기 때문에, request가 3G인 Pod를 삭제(Evict)하게 된다. 

Vertical Pod Auto-scaler (VPA)

Pod의 Resource(CPU,Memory)  적절 request를 결정하는 다른 방법으로는 Vertical Pod Auto-scaler(VPA)를 사용하는 방법이 있다. 현재 beta 기능인데, 쿠버네티스 1.11 버전 이상에 별도로 추가 설치해야 한다. 

참고 : https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler

VPA는 리소스로 설정해서 Deployment에 적용할 수 있다.


apiVersion: autoscaling.k8s.io/v1beta2

kind: VerticalPodAutoscaler

metadata:

  name: my-app-vpa

spec:

  targetRef:

    apiVersion: "extensions/v1beta1"

    kind:       Deployment

    name:       my-app

  updatePolicy:

    updateMode: "Auto"

출처 : https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler


위의 예제는 my-app 이라는 Deployment에 VPA를 적용한 예제인데, VPA는 Auto 모드와 Manual 모드가 있다. 설정은 updatePolicy.updateMode에서 지정하면 된다. 

Auto 모드로 하면, VPA가 적절한 CPU와 Memory을 측정한 후에, Pod 내의 컨테이너 resource의 request 값을 적절한 값으로 변경해준다. 대신 주의해야할 점은 resource의 request를 변경하는 유일한 방법은 Pod를 리스타트 하는 방법이기 때문에 VPA를 Auto 모드로 적용한 경우 원하지 않은 Pod 리스타트가 발생할 수 있다.


만약에 Manual 모드로 설정하고, Pod를 운영하면, VPA가 직접 request 내용을 변경하지 않고, 적절하게 필요한 request 양을 추천 해준다. VPA를 만들어서 Deployment에 적용한 후 수분 정도 운영하다가 kubetctl get vpa 명령으로 내용을 보면 추천되는 request 양을 알려준다. 

% kubectl get vpa [VPA 이름]  --output yaml

다음은 위의 명령을 실행한 결과 예제이다. 

....

  recommendation:

    containerRecommendations:

    - containerName: my-rec-container

      lowerBound:

        cpu: 25m

        memory: 262144k

      target:

        cpu: 25m

        memory: 262144k

     upperBound:

        cpu: 7931m

        memory: 8291500k


위의 결과에서 출력된 target 값이 추천 resource 양이다. CPU 25m, 메모리 262144k 가 추천되는 값이다.

그리드형