본문 바로가기
엑셈 경쟁력/전문가 기술기고

클라우드 A to Z | 쿠버네티스에서 리소스 관리하기

by EXEM 2021. 10. 27.

 

쿠버네티스는 서비스를 수평적으로 확장하고, 가용 리소스를 더 효율적으로 사용할 수 있는 기능을 제공합니다. 각 컨테이너는 파드(Pod) 단위로 배포되는데요, 이때 파드가 위치할 노드는 쿠버네티스의 스케줄러에 의해 결정됩니다. 파드가 노드에 배치된 이후, 컨테이너는 커널에 의해 관리되게 됩니다. 컨테이너는 프로세스이기 때문입니다.

 

리눅스 커널은 프로세스를 핸들링하는 많은 기능이 있습니다. 우리는 컨테이너에 대해 cgroup을 사용하여 CPU, 메모리에 대한 사용률을 설정할 수 있습니다. 도커에서는 다음 명령어로 0.5코어와 128MB 메모리만 사용되도록 제한된 nginx를 배포할 수 있습니다.

 

 

docker run -m 128M -c 0.5 nginx

 

 

세가지 QoS 클래스

쿠버네티스에선 다음과 같은 설정을 통해 CPU, MemoryRequest, Limit를 설정할 수 있습니다.

apiVersion:  v1
kind:  Pod
metadata:
  name:  my-nginx
spec:
  containers:
  - name:  app
    image:  nginx
    resources:
       requests:
         memory:  "64Mi"
         cpu:  "250m"
       limits:
         memory:  "128Mi"
         cpu:  "500m"

 

Request는 노드가 컨테이너에 필수적으로 보장해야 할 자원의 크기(soft limit)입니다. Limit는 초과될 수 없는 hard limit입니다. 이 설정을 어떻게 부여하는가에 따라 세 가지 중 하나의 클래스를 부여받게 되며, 자원이 부족할 시의 처리 로직 또한 달라집니다.

 

Best-effort, Burstable, Guaranteed

  • Guaranteed - 오직 limits만 설정하거나 limits와 requests를 같게 설정할 경우
  • Burstable - 오직 requests만 설정하거나 limits를 requests보다 높게 설정할 경우
  • Best-effort – 아무것도 설정하지 않을 경우 (동시에 네임스페이스에 별도 설정이 없을 경우)

 

 

서버 자원이 부족할 때 어떤 일이 일어나나요?

CPU의 경우, 초과한 컴퓨팅파워는 노드 상에서 동작한 requests.cpu 값에 따라 적절히 분산됩니다. , 두 프로세스가 CPU를 점유하기 위해 다투는 중이라면, 더 높은 request 값을 가진 프로세스가 더 많은 자원을 받는 것입니다. 이때, 아무것도 설정하지 않은 컨테이너는 잉여 자원만을 받게 됩니다.

 

 Memory의 경우 좀 더 치명적일 수 있습니다. 압축 불가능한(incompressible resource) 자원으로 분류되기 때문입니다. 서버의 전체적인 자원이 부족할 때, 컨테이너는 Out of Memory(OOM) killer에 의해 종료될 수 있습니다. 이때 QoS 클래스가 우선순위에 영향을 주게 되는데요. Guaranteed class를 지닌 파드는 가장 후순위로 밀릴 것이고, Best Effort class를 지닌 파드는 먼저 선택될 것입니다. 이 우선순위를 그림으로 나타내면 다음과 같습니다.

 

서버 자원 부족 시 우선순위

다음 명령어를 통해 현재 파드에 배정된 QoS Class를 확인할 수 있습니다.

 

kubectl get po MYPOD -o jsonpath={.status.qosClass}

 

 

기본 Limit, Request 설정하기 – LimitRange

파드 별로 limit, request를 설정하지 않았을 때, 기본적으로 Best-Effort가 설정되게 됩니다. 기본적으로 쿠버네티스는 설정된 Request보다 적은 자원을 가진 노드에는 파드를 배치하지 않는 기능을 제공하는데, request가 설정되지 않은 컨테이너들을 사용하다 보면 쉽게 OOM 등의 문제가 일어나곤 합니다. 쿠버네티스에는 Pod에 일일이 Limit, Request를 설정하고 싶지 않은 이들을 위해 어드미션 컨트롤러를 제공하는데요. 이를 사용하면 아무것도 명세하지 않았을 때 지정된 limit, request를 자동으로 설정하도록 할 수 있습니다.

 

먼저, 개발팀이 사용할 네임스페이스를 만들어 보겠습니다.

 

kubectl create ns dev-team

 

이후, 다음 LimitRange yaml을 작성해줍니다.

 

apiVersion:  v1
kind:  LimitRange
metadata:
  name:  my-limit-range
spec:
   limits:

    - type:  Container
      max:
         cpu2000m
         memory:  1Gi
       min: 
         cpu100m
         memory:  4Mi

       defalut:
         cpu500m
         memory:  200Mi
       defalutRequest:
         cpu:  200m
         memory:  100Mi

 

yaml로 네임스페이스에 대해 다음과 같은 제약조건을 설정할 수 있습니다.

  • 컨테이너는 100 milicore, 4Mi 이상의 request 설정을 가져야 합니다
  • 컨테이너는 200milicore, 이내의 limit를 가져야 합니다.
  • 컨테이너에 아무것도 설정되지 않았을 때, 500 milicore, 200Mi의 limit와 200 milicore, 100Mi의 request값을 가집니다.

해당 yaml을 적용하고, 파드를 만들었을 때 기본 설정이 적용되는지 확인해보겠습니다.

 

kubectl apply -f LimitRange.yaml -n dev-team
kubectl run test-po --image=nginx -n dev-team
kubectl describe po -n dev-team test-po-57bc946dd5-xg

 

이 때, 다음과 같은 결과를 확인할 수 있습니다.

 

Limits:
   cpu:  500m
   memory:  200Mi
Requests:
   cpu:  200m
   memory:  100Mi

 

 

네임스페이스 별 상한 설정하기 - ResourceQuota

여러 팀이 단일 클러스터를 사용한다고 가정해보겠습니다. 팀별로 네임스페이스를 할당할 것인데, 특정 팀이 클러스터를 과점유 하는 것을 막기 위해서는 네임스페이스별로 자원 사용량의 상한을 정해야 할 것입니다. 이때 네임스페이스에 리소스 쿼터를 설정할 수 있습니다. 리소스 쿼터로 설정할 수 있는 일반적인 항목은 다음과 같습니다.

계산 리소스

limits.cpu CPU limit의 합
limits.memory Memory limit의 합
requests.cpu CPU requests의 합
requests.memory Memory requests의 합

스토리지 리소스

requests.storage 스토리지 요청의 합
persistentvolumeclaims 네임스페이스에 존재할 수 있는 퍼시스턴트볼륨클레임의 합
storageclass.request 특정 스토리지클래스와 연관된 볼륨클레임의 request
storageclass.pvc 네임스페이스에 존재하는 퍼시스턴프볼륨클레임의 합

 

위와 같이 네임스페이스별로 리소스쿼터를 지정할 수 있으며, 이외에도 객체 개수의 상한을 지정할 수 있습니다. 실제로 어떻게 적용되는지 살펴보겠습니다.

 

kubectl create ns dev-team2

 

apiVersion:  v1
kind:  ResourceQuota
metadata:
  name:  my-quota
  namespacedev-team2
spec:

   hard:  
      requests.cpu 1000m
      requests.memory 1Gi
      limits.cpu 2000m
      limits.memory 1Gi

 

kubectl apply -f ResourceQuota.yaml

 

이제 리소스쿼터가 실제로 동작하는 방법을 알아보기 위해 어플리케이션을 배포해보겠습니다.

 

kubectl run nginx-test --image=nginx --restart=Never --replicas=1 requests=’cpu=500m,memory=10Gi’ --limits=’cpu=500m,memory=10Gi’ -n dev-team2

 

다음과 같은 에러로그를 내며 배포에 실패하는 것을 확인할 수 있습니다.

 

Error from server (Forbidden): pods "nginx-test" is forbidden: exceeded quota: my-quota, requested: limits.memory=10Gi,requests.memory=10Gi, used: limits.memory=0,requests.memory=0, limited: limits.memory=1Gi,requests.memory=1Gi

 

 

 

 

 

클라우드 네이티브 아키텍처 통합관제 솔루션, CloudMOA
엑셈의 CloudMOA는 쿠버네티스 기반 Service, Application, Database에 대한 모니터링을 고객 환경에 맞추어 서비스형(SaaS) 또는 설치형(On-Premises)으로 제공합니다. 쉽고 편한 쿠버네티스 모니터링을 원하신다면, 👉이곳👈을 방문해주세요!

 

 

 

 

 

 

댓글