Привет, Хабр!
Сегодня микросервисы требуют постоянного стремления к автоматизации и оптимизации. В этой статье рассмотрим такой инструмент в Kubernetes, как Horizontal Pod Autoscaler или сокращенно HPA.
Развертывание микросервиса
Развернем простое приложение в Kubernetes. Будем использовать стандартный подход через Deployment и Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-microservice
spec:
replicas: 1 # Начинаем с одного пода
selector:
matchLabels:
app: my-microservice
template:
metadata:
labels:
app: my-microservice
spec:
containers:
- name: my-microservice
image: nginx:latest # Используем NGINX для простоты
resources:
requests:
cpu: 100m # Ресурсы по умолчанию
memory: 256Mi
limits:
cpu: 200m
memory: 512Mi
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: my-microservice-service
spec:
selector:
app: my-microservice
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Манифест описывает простое приложение NGINX, которое будем использовать для тестирования HPA. Создаем Deployment с одним подом и устанавливаем базовые требования к ресурсам.
kubectl apply -f my-microservice.yaml
Теперь есть базовый микросервис, готовый к автоскейлингу.
Теперь настроим HPA. Он автоматически увеличивает или уменьшает количество подов в зависимости от нагрузки на CPU.
kubectl autoscale deployment my-microservice --cpu-percent=50 --min=1 --max=10
Команда создаёт HPA, который будет отслеживать загрузку CPU и масштабировать Deployment в пределах от 1 до 10 подов, пытаясь поддерживать среднюю загрузку CPU на уровне 50%.
Что здесь важно:
--cpu-percent=50: цель автоскейлинга — поддерживать загрузку CPU на уровне 50%.
--min=1 и --max=10: минимум один под, максимум десять. Эти параметры зависят от приложения и ресурсов кластера.
Для более детальной настройки HPA можно использовать YAML-манифест:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-microservice-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-microservice
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # Цель по CPU
Этот манифест можно применить командой:
kubectl apply -f my-microservice-hpa.yaml
После настройки HPA убедимся, что он работает корректно. Для этого можно использовать несколько команд, например:
kubectl get hpa
Можно увидеть что-то вроде:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
my-microservice-hpa Deployment/my-microservice 30%/50% 1 10 2 5m
Этот вывод показывает:
TARGETS: текущая загрузка CPU (в нашем случае 30%) относительно цели (50%).
REPLICAS: Текущее количество подов (в данном примере 2).
Чтобы протестировать, как работает автоскейлер, можно сгенерировать нагрузку на приложение. Один из способов — запустить контейнер, который будет постоянно отправлять запросы на микросервис:
kubectl run -i --tty load-generator --image=busybox --restart=Never -- /bin/sh
while true; do wget -q -O- http://my-microservice-service; done
Через некоторое время, можно снова проверить статус HPA:
kubectl get hpa
Можно увидеть, как количество подов увеличивается по мере роста загрузки CPU.
Для остановки нагрузки, можно нажать Ctrl + C
в терминале, где запущен load-generator.
Кастомные метрики
Для настройки кастомных метрик потребуется интеграция с системой мониторинга, например, Prometheus, которая будет собирать данные метрик и предоставлять их для HPA через API.
Допустим, нужно масштабировать приложение на основе количества HTTP-запросов в секунду. Для этого сначала необходимо экспортировать соответствующие метрики из приложения в Prometheus. Пример метрики:
httpRequestsTotal := prometheus.NewCounter(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests processed.",
},
)
Код на Go экспортирует метрику http_requests_total
, которую можно собрать и использовать для автоскейлинга.
Теперь нужно настроить Prometheus Adapter для работы с этой метрикой. Например, можно добавить следующую конфигурацию в values.yaml для Prometheus Adapter:
rules:
custom:
- seriesQuery: 'http_requests_total{namespace="default"}'
resources:
overrides:
namespace:
resource: namespace
pod:
resource: pod
name:
matches: "^(.*)_total"
as: "${1}_per_second"
metricsQuery: 'rate(http_requests_total{<<.LabelMatchers>>}[2m])'
Этот конфиг преобразует метрику http_requests_total
в http_requests_per_second
, которую можно использовать для автоскейлинга.
Теперь создадим манифест HPA, который будет масштабировать поды на основе количества запросов в секунду:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-microservice-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-microservice
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"
Этот манифест говорит Kubernetes масштабировать микросервис, если среднее количество HTTP-запросов превышает 100 запросов в секунду на под.
Настройка HPA с кастомными метриками — это тонкий процесс. Вот несколько советов, которые помогут вам избежать подводных камней и оптимизировать производительность автоскейлера.
Избегание частого масштабирования
Thrashing — это ситуация, когда автоскейлер часто меняет количество подов из-за слишком агрессивных или неправильно настроенных порогов. Чтобы этого избежать:
Установите адекватные пороговые значения и периоды ожидания. Например, можно настроить задержку между скейлингом с помощью параметра
--horizontal-pod-autoscaler-sync-period
.Еще можно использовать плавные метрики, такие как
rate()
для запросов, которые вычисляют средние значения за определённый интервал времени, чтобы избежать резких изменений.
HPA по умолчанию синхронизируется каждые 15 секунд. Этот интервал можно изменить, чтобы снизить нагрузку на систему или ускорить реакцию на изменения нагрузки:
httpRequestsTotal := prometheus.NewCounter(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests processed.",
},
)
Увеличение периода синхронизации может снизить частоту изменений, но может задерживать реакцию на резкие скачки нагрузки.
Для более точного контроля за автоскейлингом можно использовать комбинацию метрик, например, CPU и кастомные метрики одновременно:
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"
Здесь HPA будет одновременно учитывать загрузку CPU и количество запросов в секунду при масштабировании.
Больше актуальных навыков по инфраструктуре, архитектуре и разработке приложений вы можете получить в рамках практических онлайн-курсов от экспертов отрасли.