[kubernetes] AutoScaling

728x90

Auto Sacling

Resource Request & Limit

공식 문서: https://kubernetes.io/ko/docs/concepts/configuration/manage-resources-containers/

요청: request

제한: limit

요청 ≤ 제한

QoS(서비스 품질) Class:

  1. BestEffort: 품질이 가장 안좋음, 리소스를 아예 할당받지 못할 수도 있다. 리소스가 없는 상태에서 파드가 생성되야 하는 경우 BestEffort Pod 가 먼저 삭제된다.
  2. Burstable: 중간
  3. Guranteed: 품질이 가장 좋음, 가장 베스트
  • 요청/제한이 설정되어 있지 않으면: QoS
  • 요청 < 제한: Burstable
  • 요청 == 제한: Guranteed

pod.spec.containers.resources

  • requests
    • cpu
    • memory
  • limits
    • cpu
    • memory

CPU 요청 & 제한: milicore 단위를 사용

ex) 1500m → CPU 코어 1.5개, 1000m → CPU 코어 1개

ex) 1.5, 0.5

메모리 요청 & 제한: M, G, T, Mi, Gi, Ti

파드를 지정할 때, 컨테이너에 필요한 각 리소스의 양을 선택적으로 지정할 수 있다. 지정할 가장 일반적인 리소스는 CPU와 메모리(RAM) 그리고 다른 것들이 있다.

파드에서 컨테이너에 대한 리소스 요청(request) 을 지정하면, kube-scheduler는 이 정보를 사용하여 파드가 배치될 노드를 결정한다. 컨테이너에 대한 리소스 제한(limit) 을 지정하면, kubelet은 실행 중인 컨테이너가 설정한 제한보다 많은 리소스를 사용할 수 없도록 해당 제한을 적용한다. 또한 kubelet은 컨테이너가 사용할 수 있도록 해당 시스템 리소스의 최소 요청 량을 예약한다.

파드가 실행 중인 노드에 사용 가능한 리소스가 충분하면, 컨테이너가 해당 리소스에 지정한 request 보다 더 많은 리소스를 사용할 수 있도록 허용된다. 그러나, 컨테이너는 리소스 limit 보다 더 많은 리소스를 사용할 수는 없다.

예를 들어, 컨테이너에 대해 256MiB의 memory 요청을 설정하고, 해당 컨테이너가 8GiB의 메모리를 가진 노드로 스케줄된 파드에 있고 다른 파드는 없는 경우, 컨테이너는 더 많은 RAM을 사용할 수 있다.

해당 컨테이너에 대해 4GiB의 memory 제한을 설정하면, kubelet(그리고 컨테이너 런타임)이 제한을 적용한다. 런타임은 컨테이너가 구성된 리소스 제한을 초과하여 사용하지 못하게 한다. 예를 들어, 컨테이너의 프로세스가 허용된 양보다 많은 메모리를 사용하려고 하면, 시스템 커널은 메모리 부족(out of memory, OOM) 오류와 함께 할당을 시도한 프로세스를 종료한다.

제한은 반응적(시스템이 위반을 감지한 후에 개입)으로 또는 강제적(시스템이 컨테이너가 제한을 초과하지 않도록 방지)으로 구현할 수 있다. 런타임마다 다른 방식으로 동일한 제약을 구현할 수 있다.

로컬 임시(ephemeral) 스토리지

노드에는 로컬에 연결된 쓰기 가능 장치 또는, 때로는 RAM에 의해 지원되는 로컬 임시 스토리지가 있다. "임시"는 내구성에 대한 장기간의 보증이 없음을 의미한다.

파드는 스크래치 공간, 캐싱 및 로그에 대해 임시 로컬 스토리지를 사용한다. kubelet은 로컬 임시 스토리지를 사용하여 컨테이너에 emptyDir 볼륨을 마운트하기 위해 파드에 스크래치 공간을 제공할 수 있다.

kubelet은 이러한 종류의 스토리지를 사용하여 노드-레벨 컨테이너 로그, 컨테이너 이미지 및 실행 중인 컨테이너의 쓰기 가능 계층을 보유한다.

myweb-reqlim.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-reqlim
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb
      resources:
        requests:
          cpu: 200m
          memory: 200M
        limits:
          cpu: 200m
          memory: 200M
kubectl craete -f .
apiVersion: v1
kind: Pod
metadata:
  name: myweb-reqlim
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb
      resources:
        requests:
          cpu: 200m
          memory: 200M
        limits:
          cpu: 300m
          memory: 300M
kubectl replace -f myweb-reqlim.yml --force

노드별 CPU & Memory 사용량 확인

kubectl top node

노드 요청/제한 확인

kubectl describe nodes <노드_이름>

파드별 CPU & Memory 사용량 확인

kubectl top pods
kubectl top pods -A

리소스 모니터링

Heapster 프로젝트(retire)

metric-server: 실시간 CPU/Memory 모니터링

prometheus: 실시간/이전 CPU/Memory/Network/Disk 모니터링

HPA: Horisontal Pod AutoScaler

공식 문서: https://kubernetes.io/ko/docs/tasks/run-application/horizontal-pod-autoscale/

AutoScaling

  • Pod
    • HPA: Scale OUT
    • VPA(Vertical Pod AutoScaler): Scale UP
  • Node
    • ClusterScaler

HPA: Deployment, ReplicaSet, StatefulSet 의 복제본 개수를 조정

쿠버네티스에서, HorizontalPodAutoscaler 는 워크로드 리소스(예: 디플로이먼트 또는 스테이트풀셋)를 자동으로 업데이트하며, 워크로드의 크기를 수요에 맞게 자동으로 스케일링하는 것을 목표로 한다.

수평 스케일링은 부하 증가에 대해 파드를 더 배치하는 것을 뜻한다. 이는 수직 스케일링(쿠버네티스에서는, 해당 워크로드를 위해 이미 실행 중인 파드에 더 많은 자원(예: 메모리 또는 CPU)를 할당하는 것)과는 다르다.

부하량이 줄어들고, 파드의 수가 최소 설정값 이상인 경우, HorizontalPodAutoscaler는 워크로드 리소스(디플로이먼트, 스테이트풀셋, 또는 다른 비슷한 리소스)에게 스케일 다운을 지시한다.

Horizontal Pod Autoscaling은 크기 조절이 불가능한 오브젝트(예: 데몬셋)에는 적용할 수 없다.

HorizontalPodAutoscaler는 쿠버네티스 API 자원 및 컨트롤러 형태로 구현되어 있다. HorizontalPodAutoscaler API 자원은 컨트롤러의 행동을 결정한다. 쿠버네티스 컨트롤 플레인 내에서 실행되는 HPA 컨트롤러는 평균 CPU 사용률, 평균 메모리 사용률, 또는 다른 커스텀 메트릭 등의 관측된 메트릭을 목표에 맞추기 위해 목표물(예: 디플로이먼트)의 적정 크기를 주기적으로 조정한다.

HorizontalPodAutoscaler는 디플로이먼트 및 디플로이먼트의 레플리카셋의 크기를 조정한다.

알고리즘 세부 정보

가장 기본적인 관점에서, HorizontalPodAutoscaler 컨트롤러는 원하는(desired) 메트릭 값과 현재(current) 메트릭 값 사이의 비율로 작동한다.

원하는 레플리카 수 = ceil[현재 레플리카 수 * ( 현재 메트릭 값 / 원하는 메트릭 값 )]

예를 들어 현재 메트릭 값이 200m이고 원하는 값이 100m인 경우 200.0 / 100.0 == 2.0이므로 복제본 수가 두 배가 된다. 만약 현재 값이 50m 이면, 50.0 / 100.0 == 0.5 이므로 복제본 수를 반으로 줄일 것이다. 컨트롤 플레인은 비율이 1.0(기본값이 0.1인 -horizontal-pod-autoscaler-tolerance 플래그를 사용하여 전역적으로 구성 가능한 허용 오차 내)에 충분히 가깝다면 스케일링을 건너 뛸 것이다.

targetAverageValue 또는 targetAverageUtilization가 지정되면, currentMetricValue는 HorizontalPodAutoscaler의 스케일 목표 안에 있는 모든 파드에서 주어진 메트릭의 평균을 취하여 계산된다.

허용치를 확인하고 최종 값을 결정하기 전에, 컨트롤 플레인은 누락된 메트릭이 있는지, 그리고 몇 개의 파드가 Ready인지도 고려한다. 삭제 타임스탬프가 설정된 모든 파드(파드에 삭제 타임스탬프가 있으면 셧다운/삭제 중임을 뜻한다)는 무시되며, 모든 실패한 파드는 버려진다.

워크로드 스케일링의 안정성

HorizontalPodAutoscaler를 사용하여 레플리카 그룹의 크기를 관리할 때, 측정하는 메트릭의 동적 특성 때문에 레플리카 수가 계속 자주 요동칠 수 있다. 이는 종종 thrashing 또는 flapping이라고 불린다. 이는 사이버네틱스 분야의 이력 현상(hysteresis) 개념과 비슷하다.

즉, 자주 스케일 인, 스케일 아웃이 계속해서 발생할 경우 성능이 더 떨어지기 때문에 metric monitoring 이 필요하다.

안정화 윈도우

안정화 윈도우는 스케일링에 사용되는 메트릭이 계속 변동할 때 레플리카 수의 흔들림을 제한하기 위해 사용된다. 오토스케일링 알고리즘은 이전의 목표 상태를 추론하고 워크로드 수의 원치 않는 변화를 방지하기 위해 이 안정화 윈도우를 활용한다.

예를 들어, 다음 예제 스니펫에서, scaleDown에 대해 안정화 윈도우가 설정되었다.

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300

메트릭 관측 결과 스케일링 목적물이 스케일 다운 되어야 하는 경우, 알고리즘은 이전에 계산된 목표 상태를 확인하고, 해당 구간에서 계산된 값 중 가장 높은 값을 사용한다. 위의 예시에서, 이전 5분 동안의 모든 목표 상태가 고려 대상이 된다.

이를 통해 동적 최대값(rolling maximum)을 근사화하여, 스케일링 알고리즘이 빠른 시간 간격으로 파드를 제거하고 바로 다시 동일한 파드를 재생성하는 현상을 방지할 수 있다.

즉, 5분 동안 스케일링을 하지 않고 기다린 후에 스케일링이 이뤄진다.

예제

반드시 requests, limits 를 설정해줘야 HPA 가 가능하다.

myweb-deploy.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myweb-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: myweb
          image: ghcr.io/c1t1d0s7/go-myweb
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 200m
            limits:
              cpu: 200m

myweb-hpa.yml

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: myweb-hpa
spec:
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myweb-deploy

부하 걸기

kubectl exec <POD> -- sha256sum /dev/zero

v2beta2 로 HPA 구성

myweb-hpa-v2beta2.yml

$ cat myweb-hpa-v2beta2.yml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: myweb-hpa
spec:
  minReplicas: 1
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 40
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myweb-deploy
728x90