Введение
Для базовых знаний kubernetes на данный момент есть много материалов, поэтому повторяться не буду, хочу сделать серию подробных пояснений по каждому модулю, включая базовое использование, интерпретацию исходного кода и проблемы, возникающие на практике и т. д., поэтому длина очень длинная.
Во-вторых, модуль HPA
1. Соответствующие инструкции
(1) версия kubernetes: v1.9.2
(2) Подходит для людей, которые имеют определенное представление об основах kubernetes.
2. Основные понятия и использование
(1) Концепция
HPA — это автоматический модуль горизонтального расширения в kubernetes, который масштабирует модули на основе заданных пользователем и полученных метрик (процессор, память, пользовательские метрики) (не напрямую управляя модулями). Контроллер HPA принадлежит контроллеру Controller Manager.
(2) Основное использование
В разделе pkg/apis/autoscaling мы видим, что в настоящее время существует две версии: v1 (поддерживает только метрики ЦП), v2beta1 (поддерживает ЦП и память и пользовательские метрики). Давайте рассмотрим более полный способ написания hpa.
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
metadata:
name: example-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: example-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50
- type: Resource
resource:
name: memory
targetAverageUtilization: 50
- type: Pods
pods:
metricName: receive_bytes_total
targetAverageValue: 100
- type: Object
object:
target:
kind: endpoints
name: example-app
metricName: request_total
targetValue: 500m
3. Анализ исходного кода
Код в kubernetes имеет некую «рутину» (позже будет написана специальная статья, чтобы подробно разобрать эту «рутину»), сначала начинаем с апи, а потом уже к контроллеру
(1) api
Это стандартное написание kubernetes api (которое можно сгенерировать с помощью официальных инструментов), а в register.go добавлено три типа: HorizontalPodAutoscaler/HorizontalPodAutoscalerList/Scale. Затем посмотрите их определения на сайте types.go. Соответствует приведенному выше определению yaml.
// 1,HorizontalPodAutoscaler
type HorizontalPodAutoscaler struct {
......
Spec HorizontalPodAutoscalerSpec
Status HorizontalPodAutoscalerStatus
......
}
// 用户设置的值
type HorizontalPodAutoscalerSpec struct {
MinReplicas *int32 //设置的最小的replicas
MaxReplicas int32 //设置的最大的replicas
Metrics []MetricSpec
}
// hpa的目前的状态
type HorizontalPodAutoscalerStatus struct {
ObservedGeneration *int64 //观察的最近的generaction
LastScaleTime *metav1.Time //上次伸缩的时间
CurrentReplicas int32 //目前的replicas数量
DesiredReplicas int32 //期望的replicas数量
CurrentMetrics []MetricStatus //最近一次观察到的metrics数据
Conditions []HorizontalPodAutoscalerCondition //在某个特定点的hpa状态
}
// Metrics定义
type MetricSpec struct {
Type MetricSourceType //metrics type
Object *ObjectMetricSource // Object类型的metrics定义
Pods *PodsMetricSource // pods类型的metrics定义
Resource *ResourceMetricSource // Resource类型的metrics定义
}
// 2,Scale 是resources的一次scaling请求,最后hpa都是要使用这个来实现
type Scale struct {
Spec ScaleSpec // 期望到达的状态
Status ScaleStatus // 目前的状态
}
(2) controller
После того, как api определен, требуется контроллер, чтобы убедиться, что состояние системы может соответствовать определенным нами требованиям.В это время необходим контроллер hpa.Контроллер hpa получает значения каждого показателя от apiserver и поддерживает значение каждого показателя по определенному алгоритму масштабирования ожидаемое состояние.
Как было сказано выше, контроллер hpa принадлежит диспетчеру контроллеров, поэтому переходим в cmd/kube-controller-manager, и проследив весь путь, видим, что логика запуска контроллера hpa находится в options/autoscaling.go
func startHPAController(ctx ControllerContext) (bool, error) {
// 需要包含v1版本
if !ctx.AvailableResources[schema.GroupVersionResource{Group: "autoscaling", Version: "v1", Resource: "horizontalpodautoscalers"}] {
return false, nil
}
// 如果要使用自定义metrics,需要开启该选项
if ctx.Options.HorizontalPodAutoscalerUseRESTClients {
return startHPAControllerWithRESTClient(ctx)
}
// 从Heapster拉取数据
return startHPAControllerWithLegacyClient(ctx)
}
func startHPAControllerWithMetricsClient(ctx ControllerContext, metricsClient metrics.MetricsClient) (bool, error) {
.......
// 核心参数,根据metrics计算相应的replicas
replicaCalc := podautoscaler.NewReplicaCalculator(
metricsClient,
hpaClient.CoreV1(),
ctx.Options.HorizontalPodAutoscalerTolerance,
)
// 新建HorizontalController
go podautoscaler.NewHorizontalController(
hpaClientGoClient.CoreV1(),
scaleClient, // scale相关客户端,实现最终的pod伸缩
hpaClient.AutoscalingV1(),
restMapper,
replicaCalc, // 副本计算器
ctx.InformerFactory.Autoscaling().V1().HorizontalPodAutoscalers(), //infomer
ctx.Options.HorizontalPodAutoscalerSyncPeriod.Duration, // hpa获取数据的间隔
ctx.Options.HorizontalPodAutoscalerUpscaleForbiddenWindow.Duration, // hpa扩容最低间隔
ctx.Options.HorizontalPodAutoscalerDownscaleForbiddenWindow.Duration, // hpa缩容最低间隔
).Run(ctx.Stop)
return true, nil
}
// 接下来看HorizontalController的定义
type HorizontalController struct {
scaleNamespacer scaleclient.ScalesGetter // 负责scale的get和update
hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter // 负责HorizontalPodAutoscaler的Create, Update, UpdateStatus, Delete, Get, List, Watch等
mapper apimeta.RESTMapper
replicaCalc *ReplicaCalculator // 负责根据指标计算replicas
eventRecorder record.EventRecorder //event记录
upscaleForbiddenWindow time.Duration
downscaleForbiddenWindow time.Duration
// 从informer中list/get数据
hpaLister autoscalinglisters.HorizontalPodAutoscalerLister
hpaListerSynced cache.InformerSynced
queue workqueue.RateLimitingInterface
}
После запуска Run это набор процессов, разрабатываемых контроллером.При оформлении соответствующего информера рабочая очередь не будет расширена.Самое главное это следующее reconcileAutoscaler.По сути он корректирует текущее количество копий, ожидаемое количество копий и границы через серию алгоритмов.Соотношение между (максимальной и минимальной) репликами. (Следующий анализ может быть дольше, перехватываются только некоторые коды клавиш, обратите внимание на комментарии)
func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.HorizontalPodAutoscaler) error {
// 通过namespace和name获取对应的scale
scale, targetGR, err := a.scaleForResourceMappings(hpa.Namespace, hpa.Spec.ScaleTargetRef.Name, mappings)
// 获取当前副本
currentReplicas := scale.Status.Replicas
rescale := true
// 副本为0,则不进行scale操作
if scale.Spec.Replicas == 0 {
desiredReplicas = 0
rescale = false
// 当前副本大于期望的最大副本数量,不进行操作
} else if currentReplicas > hpa.Spec.MaxReplicas {
rescaleReason = "Current number of replicas above Spec.MaxReplicas"
desiredReplicas = hpa.Spec.MaxReplicas
// 当前副本数小于期望的最小值
} else if hpa.Spec.MinReplicas != nil && currentReplicas < *hpa.Spec.MinReplicas {
rescaleReason = "Current number of replicas below Spec.MinReplicas"
desiredReplicas = *hpa.Spec.MinReplicas
}
// 当前副本为0也不进行操作
else if currentReplicas == 0 {
rescaleReason = "Current number of replicas must be greater than 0"
desiredReplicas = 1
}
// 当前副本数量处于设置的Min和Max之间才进行操作
else {
// 根据metrics指标计算对应的副本数
metricDesiredReplicas, metricName, metricStatuses, metricTimestamp, err = a.computeReplicasForMetrics(hpa, scale, hpa.Spec.Metrics)
rescaleMetric := ""
// 这里是防止扩容过快,限制了最大只能扩当前实例的两倍
desiredReplicas = a.normalizeDesiredReplicas(hpa, currentReplicas, desiredReplicas)
// 限制扩容和缩容间隔,默认是两次缩容的间隔不得小于5min,两次扩容的间隔不得小于3min
rescale = a.shouldScale(hpa, currentReplicas, desiredReplicas, timestamp)
}
// 如果上面的限制条件都通过,则进行扩容,扩容注意通过scale实现
if rescale {
scale.Spec.Replicas = desiredReplicas
_, err = a.scaleNamespacer.Scales(hpa.Namespace).Update(targetGR, scale)
} else {
desiredReplicas = currentReplicas
}
}
(3) Весь процесс выглядит следующим образом
4. Практический опыт HPA
Хотя говорят, что hpa может эластично масштабировать стручки в соответствии с показателями и выполнять функцию расширения машины в соответствии с использованием, но в практическом применении я обнаружил следующие проблемы, надеясь вдохновить тех, кто хочет использовать этот модуль.
(1) Подробная информация о проблеме
Мы столкнулись с таким бизнес-сценарием: через определенный период времени трафик резко увеличится в десять раз, в это время из-за низкого состояния трафика до этого реплики были на низком уровне, то расширение в это время связано к ограничению алгоритма расширения (максимум в 2 раза), объем расширения в данный момент недостаточен. Затем, также из-за ограничения алгоритма расширения, два периода расширения по умолчанию составляют не менее трех минут, поэтому он не сможет достичь идеального количества реплик за короткий период времени. На данный момент количество подов, видимых в мониторинге, выглядит следующим образом:
Тогда это вызовет большие проблемы, и своевременно справиться с такими бизнес-сценариями в реальном времени невозможно. В то же время мы также столкнулись с такой бизнес-ситуацией.После масштабного расширения трафик резко упал, а количество подов упало до крайне низкого значения.Однако из-за джиттера бизнес-трафика в следующем за очень короткое время снова появилось большое количество подов, в это время количество подов не может справиться с таким высоким трафиком, что влияет на SLA бизнеса.
(2) Идеи решения проблем
1. Используйте несколько индикаторов Если используется только один индикатор, такой как ЦП, весь hpa будет сильно зависеть от этого индикатора, а точность этого индикатора напрямую влияет на весь hpa. Здесь мы используем CRD для разработки нескольких индикаторов, объединяем их с конкретным сценарием бизнеса, разрабатываем соответствующие индикаторы, а затем используем их вместе с такими индикаторами, как ЦП.
2. Настройте параметры по умолчанию Цикл расширения и сокращения по умолчанию не обязательно является наиболее подходящим для вашего бизнеса, поэтому его можно настроить в соответствии с ситуацией в самом бизнесе.
3. Контроллер hpa собственной разработки Другая идея состоит в том, чтобы модифицировать контроллер HPA, но это будет вредно для будущих обновлений. Таким образом, вы можете разработать контроллер HPA самостоятельно и определить алгоритм расширения и сжатия, который наиболее часто используется в вашем бизнесе. Но эта стоимость разработки немного велика.
Три, вопросы, требующие внимания
(1) Он поддерживает последовательное обновление развертывания, но не поддерживает последовательное обновление RC.
В-четвертых, резюме
(1) Если бы это был я, как бы я это разработал
Выдвинул свою дурацкую идею: Если я ответственный за hpa, то я напишу алгоритм расширения и сжатия как масштабируемый, а пользователь сможет настроить размер шага расширения и сжатия, который можно настроить для каждого hpa. временной интервал расширения и сжатия, который будет очень удобен в использовании.
5. Изучение возможностей новой версии (постоянное обновление)
(1) v1.12.1
Эта версия имеет много изменений в hpa, короче говоря, она добавляет большую гибкость и удобство использования.
1. Установив HorizontalPodAutoscalerDownscaleStabilizationWindow, вы можете предотвратить внезапное уменьшение числа модулей, вызванное дрожанием трафика. Эта версия будет записывать количество модулей, расширяемых каждый раз в течение времени HorizontalPodAutoscalerDownscaleStabilizationWindow, каждый раз брать максимальное значение в течение этого времени, а затем пытаться достичь этого значения в максимально возможной степени.
2. В настоящее время по-прежнему действуют ограничения на расширение, и по-прежнему действует ограничение на удвоенный размер, но ограничение временного интервала на расширение и сжатие отменено.
3. Вы можете самостоятельно установить допустимую погрешность
4. Добавлен учет готовности пода и отсутствующих метрик. Если модуль находится в неготовом состоянии или потерял метрики, модуль будет бездействовать и не обрабатываться. Логика обработки следующая: Если это тип Ресурса и Подов, то при оценке готовности пода сначала startTime пода плюс cpuInitializationPeriod (можно задать) больше текущего времени, а затем Состояние модуля и время сбора метрики оцениваются, чтобы судить о готовности модуля. Если startTime модуля плюс cpuInitializationPeriod меньше текущего времени, определяется, готов ли модуль в соответствии со статусом модуля и временем запуска модуля плюс задержка готовности (можно установить). Для объектов и внешних типов статус модуля оценивается напрямую.