弹性伸缩FAQ

本文介绍容器服务ACK弹性伸缩的常见问题及解决办法。

类型

问题

水平伸缩(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的数据源的情况。返回的示例数据如下。

    NAME                                   SERVICE                      AVAILABLE   AGE
    v1.                                    Local                        True        29h
    v1.admissionregistration.k8s.io        Local                        True        29h
    v1.apiextensions.k8s.io                Local                        True        29h
    v1.apps                                Local                        True        29h
    v1.authentication.k8s.io               Local                        True        29h
    v1.authorization.k8s.io                Local                        True        29h
    v1.autoscaling                         Local                        True        29h
    v1.batch                               Local                        True        29h
    v1.coordination.k8s.io                 Local                        True        29h
    v1.monitoring.coreos.com               Local                        True        29h
    v1.networking.k8s.io                   Local                        True        29h
    v1.rbac.authorization.k8s.io           Local                        True        29h
    v1.scheduling.k8s.io                   Local                        True        29h
    v1.storage.k8s.io                      Local                        True        29h
    v1alpha1.argoproj.io                   Local                        True        29h
    v1alpha1.fedlearner.k8s.io             Local                        True        5h11m
    v1beta1.admissionregistration.k8s.io   Local                        True        29h
    v1beta1.alicloud.com                   Local                        True        29h
    v1beta1.apiextensions.k8s.io           Local                        True        29h
    v1beta1.apps                           Local                        True        29h
    v1beta1.authentication.k8s.io          Local                        True        29h
    v1beta1.authorization.k8s.io           Local                        True        29h
    v1beta1.batch                          Local                        True        29h
    v1beta1.certificates.k8s.io            Local                        True        29h
    v1beta1.coordination.k8s.io            Local                        True        29h
    v1beta1.events.k8s.io                  Local                        True        29h
    v1beta1.extensions                     Local                        True        29h
    ...
    [v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        29h]
    ...
    v1beta1.networking.k8s.io              Local                        True        29h
    v1beta1.node.k8s.io                    Local                        True        29h
    v1beta1.policy                         Local                        True        29h
    v1beta1.rbac.authorization.k8s.io      Local                        True        29h
    v1beta1.scheduling.k8s.io              Local                        True        29h
    v1beta1.storage.k8s.io                 Local                        True        29h
    v1beta2.apps                           Local                        True        29h
    v2beta1.autoscaling                    Local                        True        29h
    v2beta2.autoscaling                    Local                        True        29h

    如果v1beta1.metrics.k8s.io所对应的apiservice不是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在滚动发布时出现扩容多余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"

      示例如下。

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nginx-deployment-basic
        labels:
          app: nginx
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: nginx
          template:
              metadata:
                labels:
                  app: nginx
                annotations:
                  HPARollingUpdateSkipped: "true"  # 跳过滚动发布时的HPA的效果。
              spec:
                containers:
                - name: nginx
                  image: nginx:1.7.9
                  ports:
                  - containerPort: 80

    • 方法二:通过在指定工作负载的模板中添加以下Annotation,可以在应用发布开始阶段跳过设定的预热时间段。

      ##工作负载的spec.template.metadata.annotations加入Annotation,在应用发布开始阶段跳过设定的预热的时间段。
      HPAScaleUpDelay: 3m # 3m仅为示例,具体时间段请按需设置

      示例如下。

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nginx-deployment-basic
        labels:
          app: nginx
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: nginx
          template:
              metadata:
                labels:
                  app: nginx
                annotations:
                  HPAScaleUpDelay: 3m  # m代表分钟,表示HPA在Pod创建3分钟后开始生效,可选单位为[s(秒),m(分)]。
              spec:
                containers:
                - name: nginx
                  image: nginx:1.7.9
                  ports:
                  - containerPort: 80

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组件,并在Pod的Annotation上增加开关防止误触发。关于如何升级metrics-server组件,请参见升级Kubernetes集群的metrics-server组件

增加开关防止误触发部署示例YAML如下。

## 以Deployment为例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-basic
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
      annotations:
        HPAScaleUpDelay: 3m # m代表分钟,表示HPA在Pod创建3分钟后开始生效,可选单位为[s(秒),m(分)]。
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9 # Replace it with your exactly <image_name:tags>.
        ports:
        - containerPort: 80 

常见问题

为什么节点自动伸缩组件无法弹出节点?

请检查是否存在如下几种场景:

  • 配置伸缩组的实例类型无法满足Pod的资源申请(Request)。ECS实例规格给出的资源大小是实例的售卖规格,实际运行时请考虑以下资源预留。

  • 对可用区有约束的Pod,无法触发配置了多可用区的节点池扩容。

  • 是否完整按照步骤执行了授权操作。授权操作是集群维度的,需要每个集群操作一次。关于授权,请参见弹性伸缩FAQ

  • 开启自动伸缩的节点池中出现如下异常情况。

    • 实例未加入到集群且超时。

    • 节点未ready且超时。

    为保证后续扩缩准确性,弹性组件以阻尼方式处理异常情况,在处理完异常情况节点前,不进行扩缩容。

为什么节点自动伸缩组件无法缩容节点?

请检查是否存在如下几种场景:

  • 节点Pod的资源申请(Request)阈值高于设置的缩容阈值。

  • 节点上运行kube-system命名空间的Pod。

  • 节点上的Pod包含强制的调度策略,导致其他节点无法运行此Pod。

  • 节点上的Pod拥有PodDisruptionBudget,且到达了PodDisruptionBudget的最小值。

您可以在开源社区得到更多关于节点自动伸缩组件的常见问题与解答。

多个伸缩组在弹性伸缩的时候是如何被选择的?

在Pod处在无法调度时,会触发弹性伸缩组件的模拟调度逻辑,会根据伸缩组配置的标签和污点以及实例规格等信息进行判断。当配置的伸缩组可以模拟调度Pod的时候,就会被选择进行节点弹出。当同时有多个伸缩组满足模拟调度条件的时候,默认采用的是最少浪费原则,即根据模拟弹出后节点上剩余的资源最小为原则进行抉择。

什么类型的Pod可以阻止CA移除节点?

cluster-autoscaler使用了哪些调度策略来判断不可调度Pod能否调度到开启自动伸缩节点池?

使用的调度策略如下所示。

说明

如果您的业务场景中有自动伸缩需求的Pod依赖的调度策略超出以下策略,请通过聆听平台提需求,待支持后再使用,否则可能导致误弹。

  • PodFitsResources

  • GeneralPredicates

  • PodToleratesNodeTaints

  • MaxGCEPDVolumeCount

  • NoDiskConflict

  • CheckNodeCondition

  • CheckNodeDiskPressure

  • CheckNodeMemoryPressure

  • CheckNodePIDPressure

  • CheckVolumeBinding

  • MaxAzureDiskVolumeCount

  • MaxEBSVolumeCount

  • ready

  • MatchInterPodAffinity

  • NoVolumeZoneConflict

基于阿里云组件指标的容器水平伸缩常见问题

  • 问:如果执行kubectl get hpa后发现target一栏为<unknow>怎么办?

    答:请按照以下操作解决。

    1. 执行kubectl describe hpa <hpa_name>,确认HPA失效的原因。

      • 如果Conditions字段提示AbleToScaleFalse,请确认Deployment是否正常部署。

      • 如果Conditions字段提示ScalingActiveFalse,请继续下一步。

    2. 执行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访问日志分析与监控

    3. 确认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方式采集容器日志

为什么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"

如何启用或禁用特定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。daemonsetpod排水..png

说明
  • 如果未开启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"

为什么HPA审计日志数值未达阈值但扩缩了?

问题原因

Pod水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例,期望副本数 = ceil(当前副本数 × (当前指标 / 期望指标))。

从这个公式可以看出,期望副本数的准确度,是由当前副本数、当前指标和期望指标的准确度来保证的。以HPA中应用广泛的资源指标为例,HPA获取当前副本数时,是先获取scaleTargetRef所定义的对象的scale子资源(subResources),然后将scale的status的Selector的值转化为labelselecor,以此作为条件去匹配获取Pod的。如果某个时刻,用这个条件获取到的Pod并不完全属于scaleTargetRef中定义的对象,那以此计算出的期望副本数就很可能不符合预期(比如实时指标低于阈值却扩容了)。

常见可能导致匹配Pod数目不准确的原因:

  • 滚动发布。

  • 给其他不属于scaleTargetRef中对象的Pod打标了相同Label。

解决方案

  • 针对滚动发布。解决方案,请参见为何HPA在滚动发布时出现扩容多余Pod?

  • 针对给其他不属于scaleTargetRef中对象的Pod打标了相同Label。定位出这类Pod,如果还需要使用则更换为不同Label,如果不再需要,执行如下命令删除即可。

    kubectl get pods -n {命名空间名字} -l {scale子资源的status.Selector的值}

如何指定节点不被cluster-autoscaler缩容?

为目标节点配置Node Annotation "cluster-autoscaler.kubernetes.io/scale-down-disabled": "true",使其不被cluster-autoscaler缩容。添加Annotation的命令示例如下。

kubectlannotatenode<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”

开启弹性的节点池如何配置自定义资源?

通过为开启弹性的节点池配置如下固定前缀的ECS标签(Tag),可以让弹性组件识别到已开启弹性的节点池中可供给的自定义资源,或者识别到指定的某些资源的精确值。

k8s.io/cluster-autoscaler/node-template/resource/{资源名}:{资源大小}

示例

k8s.io/cluster-autoscaler/node-template/resource/hugepages-1Gi:2Gi

哪些操作会触发Cluster Autoscaler自动更新?

为保证Cluster Autoscaler配置实时性、版本与集群的兼容性,以下操作会触发Cluster Autoscaler自动更新:

  • 更新自动伸缩配置

  • 创建、删除、更新开启弹性节点池

  • 成功升级集群

如果一个伸缩组内配置了多资源类型的实例规格,弹性伸缩时如何计算这个伸缩组的资源呢?

对于配置了多个实例规格的伸缩组,弹性伸缩组件以资源维度在各个实例规格中取最小值,作为资源计算的基准。

例如,如果一个伸缩组内配置了两种实例规格,一个是CPU 4核内存32 GB,另一个是CPU 8核内存16 GB。弹性伸缩组件认为这个伸缩组能保证的扩容出的CPU是4核内存16 GB的实例资源。因此如果状态为pending的Pods的requests资源超出4核或者16 GB,则不会进行扩容。

配置了多实例规格依然需要考虑资源预留,详见为什么节点自动伸缩组件无法弹出节点?