[DevOps] k8s Horizontal POD autoscaling

안녕하세요 정리하는 개발자 워니즈입니다. 이번시간에는 쿠버네티스의 Pod의 Autoscaling에 대해서 정리를 해보는 시간을 갖도록 하겠습니다.

HorizontalPodAutoscaler(HPA)는 CPU, 메모리 사용률 또는 일부 사용자 지정 메트릭을 기반으로 포드 수를 확장하는 Kubernetes의 별도 리소스 유형입니다. HPA는 애플리케이션 환경에서 유지 관리해야 하는 복제본 수를 최적화하는 데 도움이 되므로 부하 분산에 도움이 됩니다.

HPA 컨트롤러는 주기적으로 메트릭을 확인합니다. 평균 CPU와 메모리가 너무 높아지면 대상 배포의 복제본 수를 늘리도록 k8에 지시합니다.

1. HPA 알고리즘

replica 계산 알고리즘

desired_replica = ceil(current_replica * (현재 값/목표 값))

위의 알고리즘을 이해하기 위해서 시나리오를 준비했습니다.

시나리오 1

응용 프로그램에 일부 비즈니스 요구 사항이 있고 물리적 제한을 기반으로 이상적인 CPU/메모리 수를 제시한다고 가정합니다. 작업자 노드에 대해 대상 CPU를 60% 미만으로 유지하려고 합니다. 그런 다음 트래픽이 급증하여 현재 사용률이 90%에 도달했습니다. 배포 개체에 3개의 복제본이 정의되어 있고 포드에 과부하가 걸립니다. 알고리즘을 사용하여 원하는 포드 수를 찾을 수 있습니다.

목표 CPU 사용률: 60% 
현재 사용률: 90% 
현재 포드: 3 
원하는 포드 = ceil(current_pods * (현재 값/목표 값)) 
원하는 포드 = ceil(3*(.9/.6)) = 5

이 시나리오에서 HPA 컨트롤러는 배포의 복제본을 5개로 변경하고 스케줄러는 2개의 포드를 더 추가하여 요구 사항을 업데이트합니다.

시나리오 2

일정 기간 후에 트래픽이 감소했고 현재 사용률이 20%로 떨어졌다고 가정해 보겠습니다. 추가 복제본이 자동으로 줄어들기를 바랍니다. HPA 컨트롤러가 어떻게 우리의 소원을 들어주는지 봅시다.

대상 CPU 사용률: 60% 
현재 사용률: 20% 
현재 포드: 5 
원하는 포드 = ceil(5*(.3/.6)) = 2

여기에서는 2개의 복제본만 있으면 충분하다고 판단하고 배포 컨트롤러에 이 수로 줄이도록 지시합니다. 그러나 배포 개체의 최소 복제본 수는 3입니다. 따라서 kubernetes는 이를 존중하고 복제본 수를 5에서 3으로 줄입니다.

2. k8s 에서의 오토스케일링

1) Cluster Autoscaler

Cluster Autoscaler는 resource부족으로 scheduling이 안된 pod(pending상태의 pod)가 존재할때 node를 scale out 합니다.

그리고 Cluster에 장시간동안 utilization이 낮은 node가 있고, 이 node에 있는 pod를 다른 node에 재배치할 수 있을때 node를 scale in 합니다.

CA는 10초에 한번씩 pod를 검사하며 빠르게 scale out, scale in을 합니다. 하지만 한번 node가 scale out 되면 scale in 검사를 하기까지 10분동안 대기를 하기때문에 scale out은 비교적 빠르게, scale in은 비교적 느리게 진행된다고 할 수 있습니다.

  1. 클러스터 자동 확장 처리 알고리즘이 Pending Pod를 확인합니다.
  2. 클러스터 자동 확장 처리에 의해 새로운 Worker Node를 요청합니다.
  3. Kubernetes는 기본 인프라(ex, GCP, AWS, Azur)에 의한 프로비저닝된 새 노드를 감지합니다.
  4. Kubernetes 스케쥴러는 보류 중인 포드를 새 노드에 할당 합니다.

2) VPA (Vertical Pod Autoscaling)

VPA(Vertical Pod Autoscaling)는 컨테이너 리소스가 과소 또는 과도하게 활용되지 않도록 합니다. 최적화된 CPU 및 메모리 요청/제한 값을 권장하고 클러스터 리소스가 효율적으로 사용되도록 자동으로 업데이트할 수도 있습니다.

vpa는 pod의 resource 사용량에 맞게 resource request를 조절해서 pod가 node에 스케쥴링될때 적절한 크기의 resouce를 할당받을 수 있도록 합니다.

vpa는 hpa와 마찬가지로 metric server를 통해 pod들의 resource 사용량을 관찰합니다. 이 resource사용량이 일정기준 이상으로 늘어나면 pod를 scale out하고, 그 반대일때는 scale in합니다.

VPA github

resources:
   requests:
      memory: {{ .Values.minMem }}
      cpu: {{ .Values.minCpu }}
   limits:
      memory: {{ .Values.maxMem }}
      cpu: {{ .Values.maxCpu }}

vpa는 deployment의 yaml 파일에서 request, limit의 값을 비율에 맞춰서 업데이트를 수행합니다.

apiVersion: "autoscaling.k8s.io/v1beta2"
kind: VerticalPodAutoscaler
metadata:
  name: test-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: test
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
      - containerName: '*'
        minAllowed:
          cpu: 100m
          memory: 50Mi
        maxAllowed:
          cpu: 1
          memory: 500Mi
        controlledResources: ["cpu", "memory"]
  • Auto mode : VPA는 Pod의 리소스 사용량을 일정 주기 이상 모니터링 한 후에, 그 Metric을 기반으로, Pod resource의 request값을 변경해주는 방식.
  • Manual mode : VPA가 직접 request 내용을 변경하지 않고, 적절하게 필요한 request양을 추천해줍니다.
# kubectl get vpa [vpa name] -o yaml
recommendation:
    containerRecommendations:
    - containerName: my-rec-container
      lowerBound:
        cpu: 315m
        memory: 262144k
      target:
        cpu: 587m
        memory: 262144k
      Uncapped target:
        cpu: 587m
        memory: 262144k
     upperBound:
        cpu: 1000m
        memory: 500Mi
  • Target: VPA에서 포드에 적용할 컨테이너에 대한 권장 CPU 요청 및 메모리 요청입니다.
  • Uncapped Target: VPA 정의에서 상한/하한을 구성하지 않은 경우 컨테이너에 대한 권장 CPU 요청 및 메모리 요청입니다.
  • lowerBound: 컨테이너에 대해 권장되는 최소 CPU 요청 및 메모리 요청입니다.
  • upperBound: 컨테이너에 대해 권장되는 최대 CPU 요청 및 메모리 요청입니다.

3) HPA (Horizontal Pod Autoscaling)

HPA는 리소스 메트릭 API에서 포드당 리소스 메트릭(예: CPU, 메모리)을 가져오고 모든 대상 포드의 평균 값을 기반으로 현재 메트릭 값을 계산합니다. 현재 메트릭 값을 HPA 사양에 지정된 대상 메트릭 값과 비교하고 원하는 복제본 수를 확장하는 데 사용되는 비율을 생성합니다.

  • metric-server 로부터 생성된 pod의 metric을 기반으로 replica / Deployment / statefulset 과 같은 리소스에 대해 오토 스케일링이 가능하다.
  • HPA는 쿠버네티스 API리소스 및 컨트롤러로 구현됩니다.

HPA Configuration

  • behavior
    behavior:
     scaleDown:
       stabilizationWindowSeconds: 300 ( 기본 5분 )
       policies:
       - type: Percent
         value: 10
         periodSeconds: 30
       - type: Pods
         value: 1
         periodSeconds: 120
       selectPolicy: Min
    
    • stabilizationWindowSeconds : 안정화 윈도우는 메트릭이 계속해서 변할 때 replica의 개수가 너무 자주 변경되지 않도록 제한하기 위해서 사용.
    • 스케일링이 일어난 후, 5분동안 수집된 metric들 중에 가장 큰 수치 변화를 감지.
    • 값이 0이라면, scaling 계산을 바로 하자마자 작업 시작.
    • policy : percent, pods로 scale에 대한 정책 정의
    • percent는 해당 시간동안에 퍼센트만큼을 증가/감소
    • pods는 해당 value만큼 갯수를 증가/감소
    • select policy에 의해 2개 설정중 더 작은(min)값 선택
    • 축소하는 동안 last 동안 가장 안전한(가장 큰) “desiredReplicas” 번호를 선택해야 합니다
    • 확장하는 동안 last 동안 가장 안전한(가장 작은) “desiredReplicas” 번호를 선택해야 합니다
  • metric
    • resource 정의 메트릭 : CPU, MEMORY
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 50
    
    • metric-server에서 제공하는 pod의 resource에 대한 metric이고 주로 사용

    • 사용자 정의 메트릭 : 네트워크 트래픽

    type: Pods
    pods:
      metric:
        name: packets-per-second
      target:
        type: AverageValue
        averageValue: 1k
    
    • metric-server가 아닌 외부의 metric solution 공급업체(prometheus) 에서 제공하는 metric
    • https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api

    • Object 메트릭

    type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      target:
        type: Value
        value: 2k
    

2. HPA custom metric 적용

HPA를 사용하게 되면, CPU, Memory 이외의 Custom Metric을 이용하여 오토스케일링을 구성하고 싶을때가 있습니다. 커스텀 메트릭을 구성하기 위해서는 Prometheus Adapter를 별도로 설치해야 합니다.

  • custom metric을 사용하기 위해서는 prometheus-adapter 리소스를 사용하여 custom.metrics.k8s.io/v1beta1에 사용자 지정 어플리케이션 메트릭을 노출합니다. (kubernetes v1.16 이상)
  • prometheus adapter는 custom metrics를 별도의 API인 Aggregation Layer에 등록한 뒤, 원하는 모니터링 데이터를 Prometheus로부터 PromQL 형식을 통해 가져와 Custom Metrics API에 제공하는 역할을 합니다.
    • Prometheus Adapter가 Prometheus에 쿼리를 요청한 후, Kubernetes API에 해당 데이터를 등록하여 HPA에 사용할 수 있게 하는 방식

설치 방법

Prometheus Adapter github

프로메테우스 공식 헬름 차트를 통하여 설치를 진행합니다. ReadMe를 참고하면 설치를 진행할수 있고,, values.yaml 파일의 수정을 통해서 설치를 진행합니다.

prometheus:
  url: http://prometheus-server
  port: 0
image:
  tag: latest
rules:
  custom:
     - seriesQuery: 'container_network_receive_packets_total{namespace!="",pod!=""}'
       resources:
          overrides:
              namespace: {resource: "namespace"}
              pod: {resource: "pod"}
          name:
                   matches: "container_network_receive_packets_total"
                   as: "network_in"
          metricsQuery: <<.Series>>{<<.LabelMatchers>>}

Custom Metric 조회

  • prometheus-adapter 리소스를 사용하여 등록하면, custom.metrics.k8s.io/v1beta1애 사용자 지정 메트릭을 노출 시킵니다.
$ kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/test-ns/pods/test-admin-74b4578f75-qvd7j/network_in | jq .
{
   "kind": "MetricValueList",
   "apiVersion": "custom.metrics.k8s.io/v1beta1",
   "metadata": {
   "selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/link-me/pods/alpha-lbw-admin-74b4578f75-qvd7j/network_in"
},
"items": [
  {
     "describedObject": {
     "kind": "Pod",
     "namespace": "test-ns",
     "name": "test-admin-74b4578f75-qvd7j",
     "apiVersion": "/v1"
  },
   "metricName": "network_in",
   "timestamp": "2021-10-13T06:34:48Z",
   "value": "5367472m",
   "selector": null
  }
 ]
}

3. 마치며..

쿠버네티스는 확실히 유연한 플랫폼인것 같습니다. 사용자가 지정한대로 resource 효율화를 달성하고 최적화의 개념으로 서비스를 안정적으로 운영할 수 있게 도움을 주는 것 같습니다. HPA를 아직 필자도 실서비스에 도입을 한것은 아니지만, 몇가지 MSA도입을 하게 되면 확실히 효과는 클 것으로 보고 있습니다. 나중에 도입을 하고나서 실제로 운영상에 도움이 되었는지 후기를 작성하도록 하겠습니다.

4. 참고

[K8S] Kubernetes의 HPA를 활용한 오토스케일링(Auto Scaling)
Discussion on Horizontal Pod Autoscaler with a demo on local k8s cluster
https://haereeroo.tistory.com/22?category=1184037
Autoscaling in Kubernetes using HPA and VPA

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다