https://youtu.be/Y4vnYaqhS74?si=gMsGSJ4ruJawJJPd
Beata Skiba. Software Engineer @ Google, working on Kubernetes Autoscaling
k8s 리소스 배포하는 방법은 아주 쉽다. resource request를 정의하면 됨.
- 그런데 적절한 request 수치는 어느 정도인가?
resource request는 k8s scheduler와 workload 간 일종의 '계약'이다.
- workload는 resource request만큼을 클러스터에서 보장받아야 함.
- 반대로 말하면, 클러스터에 request에 해당하는 여유분이 없다면 not scheduled.
- 물론 priority / preemption 등의 옵션으로 리소스 할당의 우선순위를 구분할 수 있지만, 일단 모든 pod가 동일한 우선순위에 있다고 가정한다.
Request in Action: Case 1
예컨대 위와 같은 상황을 보면
- request가 cpu 200m인 pod, cpu 500m인 pod를 cpu 900m 여유가 있는 노드에 배포한다.
- 이 때, 만약 cpu 200m request였던 pod가 실제로는 500m을 사용하는 workload였다면?
- 지금은 문제되지 않는다. 노드의 총 cpu 여유분이 900m이므로, request 초과한 리소스를 점유할 수 있다.
이제 request가 cpu 600m인 pod를 노드에 배포해야 한다.
- request cpu 200m (실제로는 500m 쓰고 있는)의 경우 scheduler가 보장해야 하는 리소스 양은 200m 뿐이므로, 노드가 할당할 수 있는 cpu 여유분은 700m이다.
- 따라서 scheduler는 request 600m인 pod를 배포할 수 있다.
Request in Action: Case 2
request로 정의한 리소스 대비 실제로 사용하는 리소스가 적은 경우
- 동작엔 아무 문제가 없다. 남은 여유분만큼의 cpu는 Idle 상태.
단, request로 요청한 만큼의 리소스 점유를 보장해야 하기 때문에 cpu 600m이 request인 신규 pod는 노드에 배포될 수 없다.
만약 cluster에 autoscaler가 있어서 신규 node를 추가할 수 있다면 해결됨.
리소스 request가 너무 낮다?
- Workload evicted / pending...
리소스 request가 너무 높다?
- insufficient Usage (Waste)
설령 최적의 resource 양을 측정해서 결정하더라도, 시간이 지나며 resource 요구사항이 바뀔 수 있다.
Vertical Pod Autoscaler
VPA가 하는 일
- Actual Usage of your application 확인
- Recommend what your workloads should actually be using
- Update resources. (발표 시점에서는 Beta)
컴포넌트는 크게 두 가지.
- VPA Spec: What / How should be scaled
- VPA Status: where your recommendations are actually provided.
apiVersion: "autoscaling.k8s.io/v1beta1"
kind: VerticalPodAutoscaler
metadata:
name: worker-vpa
spec:
selector:
matchLabels:
app: worker
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "*"
maxAllowed:
memory: 5Gi
Selector: What to Scale.
- k8s의 label selector 문법을 따른다.
updatePolicy: How to Scale (1). 발표 시점에서 updateMode로 선택 가능한 건 세 가지.
- Off: Dry-Run
- Initial: 리소스의 생성 시점에서만 활용하고, forcefully restart pod 동작은 하지 않는다.
- pod의 경우 eviction, deployment의 rolling updates... 등 pod가 생성 / 변경될 때 활용되지만, 정상적으로 up and running 중인 workload의 설정을 임의로 변경하지는 않는다.
- Auto (발표 시점 Experimental feature): 리소스를 모니터링해서, recommended resource와 큰 차이가 있을 경우 자동으로 적용
resourcePolicy: How to Scale (2). per-container policy를 선택할 수 있다.
- container 단위로 설정할 수 있는 옵션. 예컨대 컨테이너 단위로 부여할 수 있는 리소스 최대 / 최소값 등을 설정할 수 있다.
- sidecar 등 특정한 종류의 workload에는 특정 policy를 지정할 수 있음.
설정했을 때 결과를 받아볼 수 있는 status 필드
- container level recommendation 정보를 확인할 수 있음.
- target value: workload가 사용하고 있는 리소스 상태.
- lower bound
- 리소스를 최소한 이 정도는 줘야 한다
- upper bound
- 리소스가 이 범위를 넘으면 waste
VPA under the hood
크게 세 가지 컴포넌트가 있고, 각 컴포넌트 간 통신은 전부 VPA object를 통해 이루어진다.
- VPA Recommender: 적정 resource 값을 추천하는 컴포넌트
- Admission Plugin: pod creation process에서 request 값을 변경하는 컴포넌트
- VPA Updator: Watch running pod / recommendation 값과 동떨어진 pod를 재시작하는 컴포넌트
분리한 이유는 Extensibility / pluginability.
Recommender
- 리소스 사용량은 metric server를 통해 수집. API server로부터 OOM event나 eviction 이벤트 수집.
- Last 8 Days: collect usages samples history in a histogram, and use very high percentile of that as target recommendation.
- 위 로직은 recommender 로직에 따라 다름. recommender 자체가 pluggable하므로, 만약 특정 workload에 이 방식이 부합하지 않는다면 다른 recommender 로직을 쓰면 됨.
pod가 만들어지는 process 중에 MutatingAdmissionWebhook이 있다. external Webhook을 호출할 수 있는 컴포넌트.
- VPA Admission Plugin을 호출한다. 이 플러그인은 클러스터에 배포된 VPA active Objects를 조회할 수 있다.
- 생성중인 pod에 대응되는 VPA object를 찾아서, request가 VPA 측정치 범위 내에 들어가는지 확인한다.
- 만약 initial 등의 옵션으로 'pod resource request'를 변경할 수 있는 모드라면, pod request를 recommendation target 값으로 수정한다.
running pod의 request를 변경하는 작업. 발표 시점에서 Experimental. 이유는
- k8s의 pod spec이 immutable 상태. -> inplace 변경이 불가능하다.
- pod을 evict -> recreate 방식으로 업데이트하는 식으로 동작해야 하는데, 이 작업은 필연적으로 disruption이 발생함.
- VPA의 recommendation 값이 cluster 상태에 Not fix할 수 있음. (Too big이라던가...)
동작 방식은
- VPA Updater가 pod list를 계속 확인.
- out of sync 상태인 pod가 있다면 (lower / upper bound를 벗어난 상태일 경우) update 수행
- k8s eviction API를 호출.
- recreation 로직은 Depends on Controller. pod creation process에서 VPA가 리소스 조정하도록 한다.