【问题标题】:Is there a way to downscale pods only when message is processed (the pod finished its task) with the HorizontalPodAutoscaler in Kubernetes?有没有办法仅在使用 Kubernetes 中的 Horizo​​ntalPodAutoscaler 处理消息(pod 完成其任务)时缩小 pod?
【发布时间】:2019-10-26 09:01:40
【问题描述】:

我使用 prometheus 适配器 https://github.com/DirectXMan12/k8s-prometheus-adapter 设置了带有自定义指标的 Kubernetes Horizo​​ntal Pod Autoscaler。 Prometheus 正在监控 rabbitmq,我正在关注 rabbitmq_queue_messages 指标。队列中的消息被 Pod 拾取,然后进行一些处理,这可能会持续几个小时。

放大和缩小是根据队列中的消息数量进行的。

问题: 当 pod 完成处理并确认消息时,这将降低 num。队列中的消息,这将触发 Autoscaler 终止 pod。如果我有多个 Pod 进行处理并且其中一个完成,如果我没记错的话,Kubernetes 可以终止仍在处理自己的消息的 Pod。这是不可取的,因为 pod 正在执行的所有处理都会丢失。

有没有办法克服这个问题,或者有其他方法可以解决这个问题?

这里是 Autoscaler 配置:

kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
metadata:
  name: sample-app-rabbitmq
  namespace: monitoring
spec:
  scaleTargetRef:
    # you created above
    apiVersion: apps/v1
    kind: Deployment
    name: sample-app
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Object
    object:
      target:
        kind: Service
        name: rabbitmq-cluster
      metricName: rabbitmq_queue_messages_ready
      targetValue: 5

【问题讨论】:

    标签: kubernetes rabbitmq autoscaling


    【解决方案1】:

    您可以考虑使用 preStop hook

    根据文档Container StatesDefine postStart and preStop handlers

    在容器进入 Terminated 之前,会执行 preStop hook(如果有的话)。

    所以你可以在你的部署中使用:

    lifecycle:
          preStop:
            exec:
              command: ["your script"]
    

    ###更新

    1. 由于一些研究,我想提供更多信息: 有一个有趣的project

      KEDA 允许对事件驱动的 Kubernetes 工作负载进行细粒度的自动缩放(包括从零到零)。 KEDA 作为 Kubernetes Metrics Server,允许用户使用专用的 Kubernetes 自定义资源定义来定义自动缩放规则。 KEDA 可以在云端和边缘运行,与 Horizo​​ntal Pod Autoscaler 等 Kubernetes 组件原生集成,没有外部依赖。

    2. 对于主要问题“Kubernetes 可以终止仍在处理自己的消息的 pod”。

      根据文档:

      “部署是一个更高级别的概念,它管理 ReplicaSet 并为 Pod 提供声明式更新以及许多其他有用的功能”

    部署由 Replicaset 支持。根据此控制器代码,存在函数“getPodsToDelete”。结合“filteredPods”,它给出的结果是:“这确保我们尽可能删除早期阶段的 pod。

    所以作为概念证明:

    您可以使用 init 容器 创建部署。初始化容器应检查队列中是否有消息,并在至少出现一条消息时退出。这将允许主容器启动、获取和处理该消息。在这种情况下,我们将有 两种 pod - 一种是 处理消息 并消耗 CPU,另一种是处于 启动状态,空闲并等待下一条消息。在这种情况下,当 HPA 决定减少部署中的副本数量时,将首先删除启动容器

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      labels:
        app: complete
      name: complete
    spec:
      replicas: 5
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: complete
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: complete
        spec:
          hostname: c1
          containers:
          - name: complete
            command: 
            - "bash"
            args:
            - "-c"
            - "wa=$(shuf -i 15-30 -n 1)&& echo $wa && sleep $wa"
            image: ubuntu
            imagePullPolicy: IfNotPresent
            resources: {}
          initContainers:
          - name: wait-for
            image: ubuntu
            command: ['bash', '-c', 'sleep 30']
    
    
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
    

    希望对您有所帮助。

    【讨论】:

    • 谢谢,但我不确定这是否会解决问题,因为容器在获取消息后运行很长时间。现在我正在考虑按照link 使用作业和 crontask
    • @Zarko 请查看答案中的其他信息。
    【解决方案2】:

    Horizo​​ntal Pod Autoscaler 不是为长时间运行的任务而设计的,也不适合。如果您需要为每条消息生成一个长时间运行的处理任务,我会采用以下两种方法之一:

    • 使用任务队列,例如Celery。它旨在解决您的确切问题:拥有需要分发给工作人员的任务队列,并确保任务运行完成。 Kubernetes 甚至提供了这个设置的official example
    • 如果您不想引入其他组件,例如 Celery,您可以自己为每条传入消息生成一个 Kubernetes job。 Kubernetes 将确保作业至少运行一次完成 - 如果 Pod 死亡,则重新安排它等。在这种情况下,您需要编写一个脚本来读取 RabbitMQ 消息并自己为它们创建作业。

    在这两种情况下,请确保您还启用了Cluster Autoscaler,以便在您当前的节点不足以处理负载时自动配置新节点。

    【讨论】:

      猜你喜欢
      • 2021-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      • 2018-10-09
      • 2023-02-11
      相关资源
      最近更新 更多