В этой статье рассмотрим использование HorizontalPodAutoscaler
— объектов, предназначенных для автоматического масштабирования количества подов (Pods
) в Replication Controller
, Replica Set
или Deployment
, основываясь на использовании CPU (или, при поддержке custom metrics, на других метриках приложения). Давайте разберемся!
Сразу стоит отметить, что HorizontalPodAutoscaler
не может быть применен к объектам, которые не предназначены для масштабирования, например DaemonSets
. Horizontal Pod Autoscaler состоит из Kubernetes
ресурса (объекта) и контроллера, поведение которого описывается ресурсом.
C периодичностью 15 секунд (можно изменить с помощью параметра --horizontal-pod-autoscaler-sync-period
), контроллер собирает данные по использованию метрик, определенных в манифесте ресурса HorizontalPodAutoscaler
. Метрики собираются или с resource metrics API (метрики использования ресурсов подами) или с custom metrics API (остальные метрики, например, метрики приложения).
Для каждого подконтрольного пода, контроллер собирает метрики (например, использования CPU) с resource metrics API (metrics.k8s.io
, предоставляется metrics-server). Далее, происходит вычисление текущего значения использования CPU в процентах от запрошенных ресурсов (resource request) контейнерами каждого пода, после чего это значение сравнивается с “целевым” (target) значением — порогом, после которого количество подов должно быть увеличено.
Рассмотрим конкретный пример. Создадим файл test-hpa.yaml
с описанием ресурса HorizontalPodAutoscaler
такого содержания:
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: test-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: test-api-deploy
minReplicas: 10
maxReplicas: 29
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 80
Создадим данный объект в кластере Kubernetes
:
kubectl create -f test-hpa.yaml
Проверим наличие объекта:
kubectl get horizontalpodautoscaler
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
test-hpa Deployment/test-api-deploy <unknown>/80% 10 29 0 7s
Спустя некоторое время, вместо <unknown>
, мы должны увидеть текущее использование CPU подами в деплойменте test-api-deploy, однако в моем случае этого не произошло. Начинаем разбираться — для начала, убедимся, что metrics.k8s.io
доступно:
kubectl get --raw "/apis/metrics.k8s.io/" | jq
{
"kind": "APIGroup",
"apiVersion": "v1",
"name": "metrics.k8s.io",
"versions": [
{
"groupVersion": "metrics.k8s.io/v1beta1",
"version": "v1beta1"
}
],
"preferredVersion": {
"groupVersion": "metrics.k8s.io/v1beta1",
"version": "v1beta1"
}
}
Проверим, что метрики использования CPU доступны. Первый вариант:
kubectl top pod | grep test-api-deploy
test-api-deploy-5f77b79896-2t9x9 738m 43931Mi
test-api-deploy-5f77b79896-fhr7b 643m 43999Mi
test-api-deploy-5f77b79896-gcrlc 700m 44028Mi
test-api-deploy-5f77b79896-lx24k 666m 44201Mi
test-api-deploy-5f77b79896-mzlzb 660m 44048Mi
test-api-deploy-5f77b79896-ndjwx 651m 44136Mi
test-api-deploy-5f77b79896-q2nvw 654m 44177Mi
test-api-deploy-5f77b79896-qmw4t 692m 44051Mi
test-api-deploy-5f77b79896-rl4bb 650m 43979Mi
test-api-deploy-5f77b79896-xhpbx 752m 44116Mi
Второй вариант (метрики только одного конкретного пода):
kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods/test-api-deploy-5f77b79896-xhpbx | jq
{
"kind": "PodMetrics",
"apiVersion": "metrics.k8s.io/v1beta1",
"metadata": {
"name": "test-api-deploy-5f77b79896-xhpbx",
"namespace": "default",
"selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/default/pods/test-api-deploy-5f77b79896-xhpbx",
"creationTimestamp": "2019-06-11T13:50:00Z"
},
"timestamp": "2019-06-11T13:49:41Z",
"window": "30s",
"containers": [
{
"name": "envoy",
"usage": {
"cpu": "489151208n",
"memory": "45692Ki"
}
},
{
"name": "test",
"usage": {
"cpu": "7125240328n",
"memory": "45515856Ki"
}
}
]
}
Как видим, метрики доступны. Получим детальное описание нашего HorizontalPodAutoscaler
:
kubectl describe hpa test-hpa
Name: test-hpa
Namespace: default
Labels: app.kubernetes.io/managed-by=spinnaker
app.kubernetes.io/name=test
Annotations: artifact.spinnaker.io/location: default
artifact.spinnaker.io/name: test-hpa
artifact.spinnaker.io/type: kubernetes/horizontalpodautoscaler
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"autoscaling/v2beta1","kind":"HorizontalPodAutoscaler","metadata":{"annotations":{"artifact.spinnaker.io/location":"default"...
moniker.spinnaker.io/application: test
moniker.spinnaker.io/cluster: horizontalpodautoscaler test-hpa
CreationTimestamp: Tue, 11 Jun 2019 11:21:03 +0300
Reference: Deployment/test-api-deploy
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): <unknown> / 80%
Min replicas: 10
Max replicas: 29
Deployment pods: 10 current / 10 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True SucceededGetScale the HPA controller was able to get the target's current scale
ScalingActive False FailedGetResourceMetric the HPA was unable to compute the replica count: missing request for cpu
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 7m17s horizontal-pod-autoscaler New size: 10; reason: Current number of replicas below Spec.MinReplicas
Warning FailedComputeMetricsReplicas 4m15s (x12 over 7m2s) horizontal-pod-autoscaler failed to get cpu utilization: missing request for cpu
Warning FailedGetResourceMetric 2m15s (x20 over 7m2s) horizontal-pod-autoscaler missing request for cpu
Здесь самое важное — сообщение the HPA was unable to compute the replica count: missing request for cpu
. И действительно, в манифесте развертывания (Deployment
) не указаны resource requests для одного из контейнеров (с именем envoy):
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# From https://www.spinnaker.io/reference/providers/kubernetes-v2/#strategy
strategy.spinnaker.io/use-source-capacity: "true"
name: test-api-deploy
spec:
# replicas: 15
selector:
matchLabels:
deployment: test-api-deploy
strategy:
rollingUpdate:
maxSurge: 0
type: RollingUpdate
template:
metadata:
labels:
deployment: test-api-deploy
spec:
containers:
- image: envoyproxy/envoy:v1.10.0
name: envoy
ports:
- containerPort: 8080
name: http
volumeMounts:
- mountPath: /etc/envoy
name: envoy-config
- env:
- name: JAVA_OPTS
value: -Xms40g -Xmx40g
image: index.docker.io/ealebed/test:v1
name: test
resources:
limits:
memory: 55Gi
requests:
cpu: "10"
memory: 55Gi
volumes:
- configMap:
name: envoy-config
name: envoy-config
Важно! Если не указаны resource request хотя бы для одного из контейнеров в Replication Controller
, Replica Set
или Deployment
, то текущее значение использование CPU подами не может быть корректно определено, и, в результате, HorizontalPodAutoscaler
не будет предпринимать никаких действий по масштабированию.
После исправления этой досадной ошибки, HorizontalPodAutoscaler
, базируясь на полученных метриках, начинает масштабировать поды в развертывании:
kubectl get horizontalpodautoscaler
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
test-hpa Deployment/test-api-deploy 86%/80% 10 29 29 9m10
Формула, по которой HorizontalPodAutoscaler
вычисляет требуемое количество реплик выглядит так:
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
Например, если текущее значение метрики (currentMetricValue) равно 200m
, а ожидаемое (desiredMetricValue) установлено в 100m
, то количество реплик будет удвоено (200.0 / 100.0 == 2.0
). Если же текущее значение метрики равно всего лишь 50m
, то количество реплик должно быть уменьшено вдвое (50.0 / 100.0 == 0.5
). Если соотношение текущего значения метрики к ожидаемому значению достаточно близко к 1, то никаких действий не будет предпринято.
Так как мы указали targetAverageUtilization
при описании ресурса HorizontalPodAutoscaler
, то текущее значение метрики (currentMetricValue) использования CPU рассчитывается как среднее значение этой метрики для всех подов, контролируемых данным автоскейлером.
После того, как текущее значение использования CPU снизилось и оставалось низким в течении 5 минут (устанавливается с помощью параметра --horizontal-pod-autoscaler-downscale-stabilization
), количество реплик было автоматически уменьшено:
kubectl get horizontalpodautoscaler
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
test-hpa Deployment/test-api-deploy 70%/80% 20 29 23 1h
На этом все, в одной из следующих статей рассмотрим более сложный вариант автоскейлинга, базирующийся на метриках приложения.
Источник: https://ealebed.github.io/posts/2019/знакомство-с-kubernetes-часть-19-horizontalpodautoscaler/