티스토리 뷰

Cloud/Kubernetes

Vertical Pods Autoscaler

Jacob_baek 2023. 2. 16. 15:17

VPA(Vertical Pod Autoscaler)란

안정성과 비용효율성간의 관계로 인해 request 혹은 limits를 낮게 혹은 너무 높게 설정하게 될수 있다.
이러한 상황에서는 OOM(out of memory) 및 불필요한 자원 과소비가 이루어지게 된다.
Pod들의 up/down scale을 지원하는 VPA는 이런 이슈를 대응할 수 있는 방안이 된다.

pod내 container들에 대한 최신 resource limits 과 requests를 설정에서 자유롭게 해준다.
자동으로 requests를 사용량에 기반해 설정하고 이로인해 resource 양에 적절한 노드에 적절한 스케쥴링이 이루어지게 된다.
또한 limits과 requests에 사이에 비율도 관리한다.

현재(2023.03 기준) 다음 제약사항이 있다.

  • 최소 2개이상의 pod가 동작되어야 한다. 1개일 경우 아래와 같은 로그를 vpa-updater가 남기면서 vpa가 동작되지 않는다.
    pods_eviction_restriction.go:219] too few replicas for ReplicaSet default/cpustress-7db8998dd6. Found 1 live pods, needs 2 (glo bal 2)

  • HPA(Horizontal Pod Autoscaler 와 함께 사용될 수 없다.(다만, CPU/Memory가 아닌 다른 metric은 HPA와 함께 사용할 수 있다.)

  • 출처 : https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#known-limitations

How it works

Architecture

VPA를 설치하게 되면 3가지 pods가 동작되어진다.

jacob@laptop:~ $ k get po -n kube-system -l 'app in (vpa-recommender,vpa-admission-controller,vpa-updater)'
NAME                                        READY   STATUS    RESTARTS   AGE
vpa-admission-controller-5596f976dd-mw4xv   1/1     Running   0          128m
vpa-recommender-55f964bd8-42x79             1/1     Running   0          128m
vpa-updater-c4888ff85-tkt68                 1/1     Running   0          128m
  • admission-controller : pod 생성 요청을 수정할 admission webhook을 등록한다. 해당 admission-webhook을 통해 기존 pod가 evicted 된후 새로운 pod가 생성될때 requests/limits가 recommender에 의해 측정된 value로 설정되어 생성된다.

  • recommender : pod에 대한 resource requests의 높고 낮은 limit을 정의한다.

  • updater : 현재 pod의 resource requests가 권장되어진 범위내에 있는지 확인한다. 만약 범위내 없는 경우 해당 pod를 kill 하고 controller에 의해 업데이트된 requests에 맞게 pod가 재생성되도록 한다.

  • 출처 : https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#components-of-vpa

다음 CRD(custom resource definition)를 기반으로 동작되어진다.

jacob@laptop:~ $ k get crds -l helm.toolkit.fluxcd.io/name=overlay-vpa-adapter-helmrelease
NAME                                                  CREATED AT
verticalpodautoscalercheckpoints.autoscaling.k8s.io   2023-03-20T02:05:23Z
verticalpodautoscalers.autoscaling.k8s.io             2023-03-20T02:05:23Z

Deep dive

work on real world

실제 동작을 확인해 보면 배포된 deployment의 requests는 다음과 같이 cpu 100m / memory 50Mi 이며

jacob@laptop:~ $ k get deploy/hamster -o jsonpath='{.spec.template.spec.containers[*].resources}' | jq
{
  "requests": {
    "cpu": "100m",
    "memory": "50Mi"
  }
}

설정된 vpa는 max cpu 가 1(1000m) 이며 min cpu는 100m로 설정된것이 확인되며

jacob@laptop:~ $ k get vpa hamster-vpa -o jsonpath='{.spec}' | jq
{
  "resourcePolicy": {
    "containerPolicies": [
      {
        "containerName": "*",
        "controlledResources": [
          "cpu",
          "memory"
        ],
        "maxAllowed": {
          "cpu": 1,
          "memory": "500Mi"
        },
        "minAllowed": {
          "cpu": "100m",
          "memory": "50Mi"
        }
      }
    ]
  },
  "targetRef": {
    "apiVersion": "apps/v1",
    "kind": "Deployment",
    "name": "hamster"
  },
  "updatePolicy": {
    "updateMode": "Auto"
  }
}

vpa에 의해 계산된 결과인 recommendation이 587m임을 확인 할 수 있다.

jacob@laptop:~ $ k get vpa hamster-vpa -o jsonpath='{.status.recommendation}' | jq
{
  "containerRecommendations": [
    {
      "containerName": "hamster",
      "lowerBound": {
        "cpu": "575m",
        "memory": "262144k"
      },
      "target": {
        "cpu": "587m",
        "memory": "262144k"
      },
      "uncappedTarget": {
        "cpu": "587m",
        "memory": "262144k"
      },
      "upperBound": {
        "cpu": "1",
        "memory": "262144k"
      }
    }
  ]
}

실제 일정시간이 경과된후 아래와 같이 requests CPU가 587m인 pod가 새로 생성되어음을 확인할 수 있다.
(실제 replica count가 2임에도 3개가 확인되는것은 vpa에 의해 하나의 pod는 evicted 되고 새로운 pod가 requests value를 변경하여 생성되었기 때문이다.)

jacob@laptop:~ $ k get pod -l app=hamster -o jsonpath='{.items[*].spec.containers[*].resources}' | jq
{
  "requests": {
    "cpu": "100m",
    "memory": "50Mi"
  }
}
{
  "requests": {
    "cpu": "587m",
    "memory": "262144k"
  }
}
{
  "requests": {
    "cpu": "100m",
    "memory": "50Mi"
  }
}

이와 같은경우 vpa에 의해 evicted되었다는 event를 아래와 같이 확인할 수 있다.

jacob@laptop:~ $ k get events --sort-by="lastTimestamp"
LAST SEEN   TYPE     REASON              OBJECT                          MESSAGE
...
3m20s       Normal   Pulled              pod/hamster-65cd4dd797-tx49r    Container image "registry.k8s.io/ubuntu-slim:0.1" already present on machine
3m20s       Normal   Started             pod/hamster-65cd4dd797-8kpcg    Started container hamster
3m20s       Normal   Created             pod/hamster-65cd4dd797-8kpcg    Created container hamster
3m20s       Normal   Pulled              pod/hamster-65cd4dd797-8kpcg    Container image "registry.k8s.io/ubuntu-slim:0.1" already present on machine
3m19s       Normal   Started             pod/hamster-65cd4dd797-tx49r    Started container hamster
3m19s       Normal   Created             pod/hamster-65cd4dd797-tx49r    Created container hamster
107s        Normal   Killing             pod/hamster-65cd4dd797-tx49r    Stopping container hamster
107s        Normal   EvictedByVPA        pod/hamster-65cd4dd797-tx49r    Pod was evicted by VPA Updater to apply resource recommendation.
107s        Normal   SuccessfulCreate    replicaset/hamster-65cd4dd797   Created pod: hamster-65cd4dd797-9lrr7
106s        Normal   Created             pod/hamster-65cd4dd797-9lrr7    Created container hamster
106s        Normal   Pulled              pod/hamster-65cd4dd797-9lrr7    Container image "registry.k8s.io/ubuntu-slim:0.1" already present on machine
105s        Normal   Started             pod/hamster-65cd4dd797-9lrr7    Started container hamster
47s         Normal   SuccessfulCreate    replicaset/hamster-65cd4dd797   Created pod: hamster-65cd4dd797-nsb8c
47s         Normal   EvictedByVPA        pod/hamster-65cd4dd797-8kpcg    Pod was evicted by VPA Updater to apply resource recommendation.
46s         Normal   Started             pod/hamster-65cd4dd797-nsb8c    Started container hamster
46s         Normal   Created             pod/hamster-65cd4dd797-nsb8c    Created container hamster
46s         Normal   Pulled              pod/hamster-65cd4dd797-nsb8c    Container image "registry.k8s.io/ubuntu-slim:0.1" already present on machine
15s         Normal   Killing             pod/hamster-65cd4dd797-8kpcg    Stopping container hamster

VPA custom resource 정의

spec:
  resourcePolicy:
    containerPolicies:
    - containerName: '*'
      controlledResources:
      - cpu
      - memory
      maxAllowed:
        cpu: 1
        memory: 500Mi
      minAllowed:
        cpu: 100m
        memory: 50Mi
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hamster
  updatePolicy:
    updateMode: Auto

위 example manifest에서 볼수 있듯이 주요 3가지 설정이 필요하다.

  1. resourcePolicy
  2. targetRef
  3. updatePolicy

resourcePolicy는 어떤 자원에 대한 허용 가능한 최대/최소 value를 지정한다.

targetRef는 해당 policy를 적용받은 대상을 지정한다.

updatePolicy는 다음 4가지 옵션으로 동작되어질수 있다.

exception cases

vpa의 max를 넘어서는 경우

새로운 pod의 requests는 max까지만 생성되어진다.

jacob@laptop:~ $ k get vpa hamster-vpa -o jsonpath='{.spec}' | jq
{
  "resourcePolicy": {
    "containerPolicies": [
      {
        "containerName": "*",
        "controlledResources": [
          "cpu",
          "memory"
        ],
        "maxAllowed": {
          "cpu": "400m",
          "memory": "100Mi"
        },
        "minAllowed": {
          "cpu": "100m",
          "memory": "50Mi"
        }
      }
    ]
  },
  "targetRef": {
    "apiVersion": "apps/v1",
    "kind": "Deployment",
    "name": "hamster"
  },
  "updatePolicy": {
    "updateMode": "Auto"
  }
}

실제 vpa도 uncappedTarget는 500m를 넘게 측정되었지만 max가 400m이기에 400m까지만 target이 recommendation이 설정되고

jacob@laptop:~ $  k get vpa hamster-vpa -o jsonpath='{.status.recommendation}' | jq
{
  "containerRecommendations": [
    {
      "containerName": "hamster",
      "lowerBound": {
        "cpu": "400m",
        "memory": "100Mi"
      },
      "target": {
        "cpu": "400m",
        "memory": "100Mi"
      },
      "uncappedTarget": {
        "cpu": "587m",
        "memory": "262144k"
      },
      "upperBound": {
        "cpu": "400m",
        "memory": "100Mi"
      }
    }
  ]
}

400m로 cpu request가 설정되어 새로운 pod가 생성되어진다.

jacob@laptop:~ $ k get pod -l app=hamster -o jsonpath='{.items[*].spec.containers[*].resources}' | jq
{
  "requests": {
    "cpu": "400m",
    "memory": "100Mi"
  }
}
{
  "requests": {
    "cpu": "400m",
    "memory": "100Mi"
  }
}

참고로 새로운 pod에는 annotation이 다음과 같이 붙어진다.

jacob@laptop:~ $ k get pod -l app=hamster -o jsonpath='{.items[*].metadata.annotations}' | jq
{
  "vpaObservedContainers": "hamster",
  "vpaUpdates": "Pod resources updated by hamster-vpa: container 0: memory request, cpu request"
}
{
  "vpaObservedContainers": "hamster",
  "vpaUpdates": "Pod resources updated by hamster-vpa: container 0: cpu request, memory request"
}

limits가 max보다 낮을 경우

다음과 같이 deployment에 limit을 앞서 cpu 500m 이상 측정되던 requests 보다 낮게 잡았다.

jacob@laptop:~ $ k get deploy/hamster -o jsonpath='{.spec.template.spec.containers[*].resources}' | jq
{
  "limits": {
    "cpu": "400m",
    "memory": "100Mi"
  },
  "requests": {
    "cpu": "100m",
    "memory": "50Mi"
  }
}

limit도 늘려서 새로운 pod 생성한다. 아래에 두번째 결과는 vpa에 의해 새로 생성된 pod이며 첫번째 결과는 최초 vpa와 연관없이 배포된 pod 의 requests / limits 이다.

jacob@laptop:~ $ k get pod -l app=hamster -o jsonpath='{.items[*].spec.containers[*].resources}' | jq
{
  "limits": {
    "cpu": "400m",
    "memory": "100Mi"
  },
  "requests": {
    "cpu": "100m",
    "memory": "50Mi"
  }
}
{
  "limits": {
    "cpu": "2348m",
    "memory": "500Mi"
  },
  "requests": {
    "cpu": "587m",
    "memory": "262144k"
  }
}

'Cloud > Kubernetes' 카테고리의 다른 글

Postee  (0) 2023.03.17
kubent(no trouble)  (0) 2023.03.14
Custom Container Registry with containerd runtime on Kubernetes  (0) 2023.02.13
cert-manager with ingress-nginx  (0) 2023.02.13
fluent-bit with azure service  (0) 2023.01.02
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함