本文介绍容器服务ACK弹性伸缩的常见问题及解决办法。
类型 | 问题 |
节点自动伸缩常见问题 | |
容器水平伸缩(HPA)常见问题 | |
基于阿里云组件指标的容器水平伸缩常见问题 |
节点自动伸缩常见问题
如何升级cluster-autoscaler至最新版本?
对于已开启集群自动弹性伸缩的集群,可通过以下方式升级cluster-autoscaler。
登录容器服务管理控制台,在左侧导航栏选择集群。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
单击集群自动弹性伸缩右侧的编辑。
在集群自动弹性伸缩配置页面,单击确定,即可升级cluster-autoscaler至最新版本。
cluster-autoscaler可模拟判断的资源有哪些?
cluster-autoscaler已经支持以下资源的模拟和判断:
cpu
memory
sigma/eni
ephemeral-storage
aliyun.com/gpu-mem (仅共享GPU)
nvidia.com/gpu
如果需要其他资源类型,请参见开启弹性的节点池如何配置自定义资源?。
cluster-autoscaler是否支持自定义资源?
cluster-autoscaler目前仅支持K8s标准对象,暂时不支持K8s自定义资源。
如何指定节点不被cluster-autoscaler缩容?
为目标节点配置Node Annotation "cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"
,使其不被cluster-autoscaler缩容。添加Annotation的命令示例如下。
kubectl annotate node <nodename> cluster-autoscaler.kubernetes.io/scale-down-disabled=true
如何延迟cluster-autoscaler对不可调度Pod的扩容反应时间?
可以通过cluster-autoscaler.kubernetes.io/pod-scale-up-delay
注释为每个Pod设置延迟扩容时间。 如果K8s没有在该延迟结束时调度它们,那么CA可能会考虑对它们进行扩展。注释示例如下:"cluster-autoscaler.kubernetes.io/pod-scale-up-delay": "600s"
。
为什么节点自动伸缩组件无法弹出节点?
请检查是否存在如下几种场景:
配置伸缩组的实例类型无法满足Pod的资源申请(Request)。ECS实例规格给出的资源大小是实例的售卖规格,实际运行时请考虑以下资源预留。
在创建实例的过程中因为虚拟化、OS占用掉一部分。详细信息,请参见购买实例后查看内存大小,为什么和购买时的实例规格定义不一致?。
需要占用一定的节点资源来运行相关组件(例如kubelet、kube-proxy、Terway、Container Runtime等)。详细信息,请参见节点资源预留策略。
默认节点会安装系统组件,Pod的申请资源要小于实例的规格。
对可用区有约束的Pod,无法触发配置了多可用区的节点池扩容。
是否完整按照步骤执行了授权操作。授权操作是集群维度的,需要每个集群操作一次。关于授权,请参见步骤二:授权。
开启自动伸缩的节点池中出现如下异常情况。
实例未加入到集群且超时。
节点未ready且超时。
为保证后续扩缩准确性,弹性组件以阻尼方式处理异常情况,在处理完异常情况节点前,不进行扩缩容。
为什么节点自动伸缩组件无法缩容节点?
请检查是否存在如下几种场景:
节点Pod的资源申请(Request)阈值高于设置的缩容阈值。
节点上运行kube-system命名空间的Pod。
节点上的Pod包含强制的调度策略,导致其他节点无法运行此Pod。
节点上的Pod拥有PodDisruptionBudget,且到达了PodDisruptionBudget的最小值。
您可以在开源社区得到更多关于节点自动伸缩组件的常见问题与解答。
多个伸缩组在弹性伸缩的时候是如何被选择的?
在Pod处在无法调度时,会触发弹性伸缩组件的模拟调度逻辑,会根据伸缩组配置的标签和污点以及实例规格等信息进行判断。当配置的伸缩组可以模拟调度Pod的时候,就会被选择进行节点弹出。当同时有多个伸缩组满足模拟调度条件的时候,默认采用的是最少浪费原则,即根据模拟弹出后节点上剩余的资源最小为原则进行抉择。
什么类型的Pod可以阻止CA移除节点?
cluster-autoscaler使用了哪些调度策略来判断不可调度Pod能否调度到开启自动伸缩节点池?
使用的调度策略如下所示。
PodFitsResources
GeneralPredicates
PodToleratesNodeTaints
MaxGCEPDVolumeCount
NoDiskConflict
CheckNodeCondition
CheckNodeDiskPressure
CheckNodeMemoryPressure
CheckNodePIDPressure
CheckVolumeBinding
MaxAzureDiskVolumeCount
MaxEBSVolumeCount
ready
NoVolumeZoneConflict
开启弹性的节点池如何配置自定义资源?
通过为开启弹性的节点池配置如下固定前缀的ECS标签(Tag),可以让弹性组件识别到已开启弹性的节点池中可供给的自定义资源,或者识别到指定的某些资源的精确值。
k8s.io/cluster-autoscaler/node-template/resource/{资源名}:{资源大小}
示例:
k8s.io/cluster-autoscaler/node-template/resource/hugepages-1Gi:2Gi
为什么Pod无法调度到节点自动伸缩组件弹出节点?
受底层资源占用计算精度约束,自动伸缩组件估算的节点可调度资源可能大于实际节点的可调度资源。关于底层资源占用计算精度约束的更多信息,请参见购买实例后查看内存大小,为什么和购买时的实例规格定义不一致?。当Pod资源申请占用较大时(建议超过节点资源70%时),需要用户使用弹性前Pod确认是否可调度到同实例规格的节点。
弹性组件在判断节点的资源是否满足时,仅考虑Pending Pods和Daemonset Pods的资源,如果节点上有非Daemonset的Static Pods,请您预先为此类Pod预留资源。
如何通过指定Pod控制节点被cluster-autoscaler缩容?
您可以指定Pod阻止或不阻止节点被cluster-autoscaler缩容。
阻止节点被cluster-autoscaler缩容:为Pod添加Annotation
"cluster-autoscaler.kubernetes.io/safe-to-evict": "false"
。不阻止节点被cluster-autoscaler缩容:为Pod添加Annotation
"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"
。
哪些操作会触发cluster-autoscaler自动更新?
为保证cluster-autoscaler配置实时性、版本与集群的兼容性,以下操作会触发cluster-autoscaler自动更新:
更新自动伸缩配置
创建、删除、更新开启弹性节点池
成功升级集群
如何启用或禁用特定DaemonSet的驱逐?
Cluster Autoscaler会根据是否开启daemonset pod排水配置(如下图所示)决定是否逐出DaemonSet Pods,这些配置是集群维度的,对集群中的DaemonSet Pods通用。如果想要对某个DaemonSet Pod指定是否需要被驱逐,可以对这个DaemonSet Pod添加Annotation"cluster-autoscaler.kubernetes.io/enable-ds-eviction":"true"
。
类似的,DaemonSet Pod的Annotation中如果有"cluster-autoscaler.kubernetes.io/enable-ds-eviction":"false"
,则会显示禁止Cluster Autoscaler驱逐这个DaemonSet Pod。
如果未开启DaemonSet Pod排水,此Annotation仅对非空节点的DaemonSet Pods有效。如果想开启空节点DaemonSet Pods,需要先开启DaemonSet Pod排水。
此Annotation需要在DaemonSet Pod上指定,而不是DaemonSet对象本身。
此Annotation对不属于任何DaemonSet的Pod没有影响。
默认情况下,Cluster Autoscaler对DaemonSet Pod驱逐是非阻塞模式的,即不等待DaemonSet Pod驱逐掉,就会执行后续流程。如需要Cluster Autoscaler等待指定DaemonSet Pod驱逐掉后,再执行后续缩容流程,除以上启用配置外,请为相应Pod添加Annotation "cluster-autoscaler.kubernetes.io/wait-until-evicted":"true"。
如果一个伸缩组内配置了多资源类型的实例规格,弹性伸缩时如何计算这个伸缩组的资源呢?
对于配置了多个实例规格的伸缩组,弹性伸缩组件以资源维度在各个实例规格中取最小值,作为资源计算的基准。
例如,如果一个伸缩组内配置了两种实例规格,一个是CPU 4核内存32 GB,另一个是CPU 8核内存16 GB。弹性伸缩组件认为这个伸缩组能保证的扩容出的CPU是4核内存16 GB的实例资源。因此如果状态为pending的Pods的requests资源超出4核或者16 GB,则不会进行扩容。
配置了多实例规格依然需要考虑资源预留,请参见为什么节点自动伸缩组件无法弹出节点?。
容器水平伸缩(HPA)常见问题
HPA的监控数据current字段为何显示为unknown?
当HPA的监控数据的current字段显示为unknown时,表示kube-controller-manager无法访问监控数据源获取对应的监控数据。
Name: kubernetes-tutorial-deployment
Namespace: default
Labels: <none>
Annotations: <none>
CreationTimestamp: Mon, 10 Jun 2019 11:46:48 0530
Reference: Deployment/kubernetes-tutorial-deployment
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): <unknown> / 2%
Min replicas: 1
Max replicas: 4
Deployment pods: 1 current / 0 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: unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API: the server is currently unable to handle the request (get pods.metrics.k8s.io)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedGetResourceMetric 3m3s (x1009 over 4h18m) horizontal-pod-autoscaler unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API: the server is currently unable to handle the request (get pods.metrics.k8s.io)
原因如下:
原因一:resource metrics数据源无法使用。先执行命令
kubectl top pod
检查是否返回数据。如果所有的Pod都无数据,请执行kubectl get apiservice
检查当前提供resource metrics的数据源的情况。返回的示例数据如下。如果v1beta1.metrics.k8s.io所对应的API Service不是kube-system/metrics-server,检查是否由于安装Prometheus Operator覆盖导致。如果是覆盖导致的问题,可以通过部署以下的YAML模板进行恢复。
apiVersion: apiregistration.k8s.io/v1beta1 kind: APIService metadata: name: v1beta1.metrics.k8s.io spec: service: name: metrics-server namespace: kube-system group: metrics.k8s.io version: v1beta1 insecureSkipTLSVerify: true groupPriorityMinimum: 100 versionPriority: 100
如果非上述问题,请确认已在集群的运维管理 > 组件管理页面安装了metrics-server组件。更多信息,参见metrics-server。
原因二:滚动发布或者扩容时无法获取数据。
默认metrics-server的采集周期是1 min。刚扩容或更新完成后,metrics-server会有一段时间无法获取监控数据。请于扩容或更新后2 min左右进行查看。
原因三:缺少request字段设置。
HPA默认是通过实际的利用率/request作为利用率的数值,因此可以检查Pod的Resource字段中是否包含Request字段。
原因四:指标名填写错误。请检查指标名(包括大小写)是否正确。例如,如果将HPA支持的
cpu
指标误写为CPU
,监控数据current
字段会显示为unknown
。
为何HPA在滚动发布时出现扩容多余Pod的现象?
社区Controller Manager在滚动发布时,对于没有监控数据的Pod,进行监控数据的补零操作,从而有一定的概率出现扩容出多余的Pod现象(多弹现象)。您可以通过以下配置防止多弹。
集群维度配置。
您可以通过升级ACK提供的最新版metrics-server,并在metrics-server的启动参数上开启开关防止多弹。
这是全局开关,设置后对集群内所有相关负载生效。
##在metrics-server的启动参数中加入以下选项。 --enable-hpa-rolling-update-skipped=true
工作负载维度配置。如果只想对指定的工作负载开启防止多弹,您可以使用以下两种方法防止多弹。
方法一:通过在指定工作负载的模板中添加以下Annotation,可以在滚动发布时临时暂停HPA的判断生效。
##工作负载的spec.template.metadata.annotations加入Annotation,滚动发布时临时暂停HPA的判断生效。 HPARollingUpdateSkipped: "true"
方法二:通过在指定工作负载的模板中添加以下Annotation,可以在应用发布开始阶段跳过设定的预热时间段。
##工作负载的spec.template.metadata.annotations加入Annotation,在应用发布开始阶段跳过设定的预热的时间段。 HPAScaleUpDelay: 3m # 3m仅为示例,具体时间段请按需设置
HPA到达阈值为何不进行扩缩容?
HPA的扩缩容的触发条件不仅是CPU使用率或内存使用率超过阈值与低于阈值,需要额外考虑的是如果扩容或者缩容后,是否会再次触发缩容或者扩容,减少震荡的场景。
例如当您的扩容阈值设置为80%,如果有两个Pod的CPU目前使用率都是70%,这种情况下就不会缩容。因为缩容后可能单个Pod的CPU使用率高于80%,就会触发扩容,这样就会来回扩缩容出现震荡。
HPA采集周期如何配置?
对版本号大于v0.2.1-b46d98c-aliyun的metric-server,在metric-server的启动参数中设置--metric-resolution
,例如--metric-resolution=15s
即可。
CronHPA是否兼容HPA?
CronHPA可以兼容HPA。阿里云容器服务ACK将CronHPA中的scaleTargetRef设置为HPA对象,然后通过HPA对象来寻找真实的scaleTargetRef,从而让CronHPA感知HPA的当前状态。CronHPA不会直接调整Deployment的副本数目,而是通过HPA来操作Deployment,这样可以避免HPA和CronHPA的冲突问题。关于CronHPA兼容HPA的更多信息,请参见容器定时伸缩(CronHPA)。
如何解决HPA启动时CPU或内存飙高造成扩容出多余Pod的多弹现象?
对于Java等需要预热的语言与框架而言,在容器刚启动的时候,有可能会出现分钟级别的CPU、内存飙高,可能会造成HPA的误触发。您可以通过将ACK提供的metrics-server组件升级至0.3.9.6版本以上,并在Pod的Annotation上增加开关防止误触发,解决此问题。关于如何升级metrics-server组件,请参见升级集群至v1.12版本前升级metrics-server组件。
增加开关防止误触发部署示例YAML如下。
为什么HPA审计日志数值未达阈值但扩缩了?
问题原因
Pod水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例,期望副本数 = ceil(当前副本数 × (当前指标 / 期望指标))。
从这个公式可以看出,期望副本数的准确度,是由当前副本数、当前指标和期望指标的准确度来保证的。以HPA中应用广泛的资源指标为例,HPA获取当前副本数时,是先获取scaleTargetRef所定义的对象的scale子资源(subResources),然后将scale的status的Selector的值转化为labelselector,以此作为条件去匹配获取Pod的。如果某个时刻,用这个条件获取到的Pod并不完全属于scaleTargetRef中定义的对象,那以此计算出的期望副本数就很可能不符合预期(比如实时指标低于阈值却扩容了)。
常见可能导致匹配Pod数目不准确的原因:
滚动发布。
给其他不属于scaleTargetRef中对象的Pod打标了相同Label。执行如下命令,可判断是否有其他Pod。
kubectl get pods -n {命名空间名字} -l {scale子资源的status.Selector的值}
解决方案
针对滚动发布。解决方案,请参见为何HPA在滚动发布时出现扩容多余Pod的现象?。
针对给其他不属于scaleTargetRef中对象的Pod打标了相同Label。定位出这类Pod,如果还需要使用则更换为不同Label,如果不再需要,删除即可。
基于阿里云组件指标的容器水平伸缩常见问题
如果执行kubectl get hpa
后发现target
一栏为unknow
怎么办?
请按照以下操作解决。
执行
kubectl describe hpa <hpa_name>
,确认HPA失效的原因。如果Conditions字段提示AbleToScale为False,请确认Deployment是否正常部署。
如果Conditions字段提示ScalingActive为False,请继续下一步。
执行
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/"
。如果返回为Error from server (NotFound): the server could not find the requested resource,请确认alibaba-cloud-metrics-adapter的启动状态。如果确认alibaba-cloud-metrics-adapter状态正常,请确认HPA指标是否是Ingress相关指标。如果是Ingress相关指标,您需要提前部署日志服务组件。更多信息,请参见Nginx Ingress访问日志分析与监控。
确认HPA指标填写正确。sls.ingress.route的值格式为
<namespace>-<svc>-<port>
。namespace为Ingress所在的命名空间。
svc是Ingress对应的Service名称。
port是Ingress对应Service的端口名称。
如何查找HPA支持的指标名称?
请参见阿里云HPA指标,以下列举为常用指标。
指标名称 | 描述 | 附加参数 |
sls_ingress_qps | 指定的IngressRoute每秒查询率 | sls.ingress.route |
sls_alb_ingress_qps | ALB数据的IngressRoute每秒查询率 | sls.ingress.route |
sls_ingress_latency_avg | 所有请求的延迟 | sls.ingress.route |
sls_ingress_latency_p50 | 50%请求的延迟 | sls.ingress.route |
sls_ingress_latency_p95 | 95%请求的延迟 | sls.ingress.route |
sls_ingress_latency_p99 | 99%请求的延迟 | sls.ingress.route |
sls_ingress_latency_p9999 | 99.99%请求的延迟 | sls.ingress.route |
sls_ingress_inflow | Ingress的流入带宽 | sls.ingress.route |
当用户自定义了Nginx Ingress日志格式,如何进行适配操作?
基于阿里云组件指标的容器水平伸缩介绍了使用SLS Ingress指标进行容器水平伸缩,需要您开启并正确配置集群中Nginx Ingress日志接入阿里云日志服务。
在创建集群时,日志服务是默认开启的。当您保持默认值不变,集群创建成功后,您可以在阿里云日志服务SLS控制台查看Nginx Ingress的访问日志分析报表和监控Nginx Ingress实时状态。
在创建集群时,若您手动关闭了日志服务,集群创建完成后,如果想要使用SLS Ingress指标进行容器水平伸缩,您需要重新开启或配置日志服务。详细信息,请参见Nginx Ingress访问日志分析与监控。
当您需要自定义Nginx Ingress日志格式时,由于集群中初次开启日志服务部署AliyunLogConfig的CRD只针对ACK默认Ingress Controller中的日志格式生效,若您修改过Ingress Controller的访问日志格式,请修改CRD配置中的正则表达式提取
processor_regex
部分。具体操作,请参见通过DaemonSet-CRD方式采集容器日志。