FinOps 之 Crane 成本优化(二)
  zNxK8cIqmu7p 2023年12月12日 15 0

一、应用资源优化

资源优化是 FinOps 中常见的优化手段,基于 Kubernetes 应用的特点总结出云原生应用的资源优化模型:

FinOps 之 Crane 成本优化(二)_crane

图中五条线从上到下分别是:

  1. 节点容量:集群中所有节点的资源总量,对应集群的 Capacity
  2. 已分配:应用申请的资源总量,对应 Pod Request
  3. 周峰值:应用在过去一段时间内资源用量的峰值。周峰值可以预测未来一段时间内的资源使用,通过周峰值配置资源规格的安全性较高,普适性更强
  4. 日均峰值:应用在近一天内资源用量的峰值
  5. 均值:应用的平均资源用量,对应 Usage

其中资源的闲置分两类:

  1. Resource Slack:Capacity 和 Request 之间的差值
  2. Usage Slack:Request 和 Usage 之间的差值

Total Slack = Resource Slack + Usage Slack

资源优化的目标是 减少 Resource Slack 和 Usage Slack。模型中针对如何一步步减少浪费提供了四个步骤,从上到下分别是:

  1. 提升装箱率:提升装箱率能够让 Capacity 和 Request 更加接近。手段有很多,例如:动态调度器、腾讯云的云原生节点的节点放大功能等
  2. 业务规格调整减少资源锁定:根据周峰值资源用量调整业务规格使的 Request 可以减少到周峰值线。资源推荐副本推荐可以帮助应用实现此目标。
  3. 业务规格调整+扩缩容兜底流量突发:在规格优化的基础上再通过 HPA 兜底突发流量使的 Request 可以减少到日均峰值线。此时 HPA 的目标利用率偏低,仅为应对突发流量,绝大多数时间内不发生自动弹性。弹性推荐可以扫描出适合做弹性的应用并提供HPA配置。
  4. 业务规格调整+扩缩容应对日常流量变化:在规格优化的基础上再通过 HPA 应用日常流量使的 Request 可以减少到均值。此时 HPA 的目标利用率等于应用的平均利用率。EHPA实现了基于预测的水平弹性,帮助更多应用实现智能弹性。



推荐规则

添加集群之后勾选了安装推荐规则之后,会在推荐规则里面创建4个推荐规则。

FinOps 之 Crane 成本优化(二)_crane_02

通过查看 Recommendationrules CRD可以查看到这四个资源。

FinOps 之 Crane 成本优化(二)_crane_03

目前 Crane 支持了以下 Recommender:

  • 资源推荐: 通过 VPA 算法分析应用的真实用量推荐更合适的资源配置
  • 副本数推荐: 通过 HPA 算法分析应用的真实用量推荐更合适的副本数量
  • HPA 推荐: 扫描集群中的 Workload,针对适合适合水平弹性的 Workload 推荐 HPA 配置
  • 闲置节点推荐: 扫描集群中的闲置节点



查看 workloads-rule 规则的yaml文件

apiVersion: analysis.crane.io/v1alpha1
kind: RecommendationRule
metadata:
  labels:
    analysis.crane.io/recommendation-rule-preinstall: "true"
  name: workloads-rule
spec:
  namespaceSelector:					# 所有的namespace
    any: true
  recommenders:								# 资源推荐器
  - name: Replicas
  - name: Resource
  resourceSelectors:					# 资源信息
  - apiVersion: apps/v1
    kind: Deployment
  - apiVersion: apps/v1
    kind: StatefulSet
  runInterval: 24h						# 24小时运行一次

在该示例中:

  • 每隔24小时运行一次分析推荐,runInterval格式为时间间隔,比如: 1h,1m,设置为空表示只运行一次。
  • 待分析的资源通过配置 resourceSelectors 数组设置,每个 resourceSelector 通过 kind,apiVersion,name 选择 k8s 中的资源,当不指定 name 时表示在 namespaceSelector 基础上的所有资源
  • namespaceSelector 定义了待分析资源的 namespace,any: true 表示选择所有 namespace
  • recommenders 定义了待分析的资源需要通过哪些 Recommender 进行分析。目前支持的类型:recommenders
  • 资源类型和 recommenders 需要可以匹配,比如 Resource 推荐默认只支持 Deployments 和 StatefulSets,每种 Recommender 支持哪些资源类型请参考 recommender 的文档


资源推荐

查看资源推荐

FinOps 之 Crane 成本优化(二)_crane_04

查看yaml,得知 kind:Recommendation CRD 资源 。

FinOps 之 Crane 成本优化(二)_crane_05

根据现有规则,根据每一个命名空间下的服务会生成对应的副本数、资源、service的推荐规则的资源。



采纳命令

点击查看采纳命令,可以获取一个服务的

FinOps 之 Crane 成本优化(二)_crane_06

patchData=`kubectl get recommend workloads-rule-resource-4w5hg -n testing-mingzhu-1 -o jsonpath='{.status.recommendedInfo}'`;
kubectl patch Deployment iov-parking-mqtt -n testing-mingzhu-1 --patch "${patchData}"


查看 workloads-rule-resource-4w5hg 的 yaml

...
spec:
  adoptionType: StatusAndAnnotation
  completionStrategy:
    completionStrategyType: Once
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: iov-parking-mqtt
    namespace: testing-mingzhu-1
  type: Resource
status:
  action: Patch
  conditions:
  - lastTransitionTime: "2023-12-03T08:20:48Z"
    message: Recommendation is ready
    reason: RecommendationReady
    status: "True"
    type: Ready
  currentInfo: '{"spec":{"template":{"spec":{"containers":[{"name":"iov-parking-mqtt","resources":{"requests":{"cpu":"300m","memory":"500Mi"}}}]}}}}'
  lastUpdateTime: "2023-12-10T08:49:49Z"
  recommendedInfo: '{"spec":{"template":{"spec":{"containers":[{"name":"iov-parking-mqtt","resources":{"requests":{"cpu":"114m","memory":"120586239"}}}]}}}}'
  recommendedValue: |
    resourceRequest:
      containers:
      - containerName: iov-parking-mqtt
        target:
          cpu: 114m
          memory: "120586239"
  targetRef: {}

命令的意思是获取 recommendedInfo 的推荐,通过kubectl的命令 patch Deployment 的信息。



资源优化

Kubernetes 用户在创建应用资源时常常是基于经验值来设置 request 和 limit。通过资源推荐的算法分析应用的真实用量推荐更合适的资源配置,您可以参考并采纳它提升集群的资源利用率。

优化前:

FinOps 之 Crane 成本优化(二)_crane_07

优化后:

FinOps 之 Crane 成本优化(二)_crane_08



命名空间成本分布:

优化前:

FinOps 之 Crane 成本优化(二)_crane_09


优化后(金额差距太多,可能和数据少了几天有关):

FinOps 之 Crane 成本优化(二)_crane_10


使用24小时颗粒度的图表来看,cpu,内存都有降低,资源分配的也更合理。

FinOps 之 Crane 成本优化(二)_crane_11



实现原理

资源推荐按以下步骤完成一次推荐过程:

  1. 通过监控数据,获取 Workload 过去一周的 CPU 和 Memory 历史用量。
  2. 基于历史用量通过 VPA Histogram 取 P99 百分位后再乘以放大系数
  3. OOM 保护:如果容器存在历史的 OOM 事件,则考虑 OOM 时的内存适量增大内存推荐结果
  4. 资源规格规整:按指定的容器规格对推荐结果向上取整

基本原理是基于历史的资源用量,将 Request 配置成略高于历史用量的最大值并且考虑 OOM,Pod 规格等因素。


VPA 算法

资源推荐的核心思想是基于历史资源用量推荐合理的资源配置,我们采用了社区 VPA Histogram 算法来实现。VPA 算法将历史的资源用量放到直方图中,找到资源用量的 P99 百分数,将百分数乘以放大系数作为推荐值。

VPA 算法的 output 是 cpu、内存指标的 P99 用量。为了给应用预留 buffer,推荐结果还会乘以放大系数。资源推荐支持两种方式配置放大系数:

  1. 扩大比例:推荐结果=P99用量 * (1 + 放大系数),对应配置:cpu-request-margin-fraction 和 mem-request-margin-fraction
  2. 目标峰值利用率:推荐结果=P99用量/目标峰值利用率,对应配置:cpu-target-utilization 和 mem-target-utilization

在您有应用的目标峰值利用率目标时,推荐使用目标峰值利用率方式放大推荐结果。


OOM 保护

Craned 运行了单独的组件 OOMRecorder ,它记录了集群中 container OOM 的事件,资源推荐会读取 OOM 事件获取 OOM 时刻的内存使用,将内存使用乘以放大系数后与 VPA 的内存推荐结果比较,取较大值


资源规格规整

在 Kubernetes Serverless 中,Pod 的 cpu、内存规格是预设的,资源推荐支持对推荐结果按预设的资源规格向上取整,例如,基于历史用量的 cpu 推荐值为0.125核,资源规格规整后向上取整后为 0.25核。用户也可以通过修改规格配置来满足自己环境的规格需求。


通过 Prometheus Metric 监控推荐结果

推荐资源的推荐结果会记录到 Metric:crane_analysis_resource_recommendation



如何验证推荐结果的准确性

用户可以通过以下 Prom query 得到 Workload Container 的资源用量,推荐值会略高于历史用量的最大值并且考虑 OOM,Pod 规格等因素。

以 crane-system 的 Deployment Craned 为例,用户可以将 container, namespace, pod 换成希望验证的推荐 TargetRef。

irate(container_cpu_usage_seconds_total{container!="POD",namespace="crane-system",pod=~"^craned.*$",cnotallow="craned"}[3m])   # cpu usage
container_memory_working_set_bytes{container!="POD",namespace="crane-system",pod=~"^craned.*$",cnotallow="craned"}  # memory usage




二、动态调度器

kubernetes 的原生调度器只能通过资源请求来调度 pod,这很容易造成一系列负载不均的问题:

  • 对于某些节点,实际负载与资源请求相差不大,这会导致很大概率出现稳定性问题。
  • 对于其他节点来说,实际负载远小于资源请求,这将导致资源的巨大浪费。

为了解决这些问题,动态调度器根据实际的节点利用率构建了一个简单但高效的模型,并过滤掉那些负载高的节点来平衡集群。


架构

FinOps 之 Crane 成本优化(二)_crane_12

如上图,动态调度器依赖于PrometheusNode-exporter收集和汇总指标数据,它由两个组件组成:

 Node-annotator 目前是 Crane-scheduler-controller的一个模块.

  • Node-annotator定期从 Prometheus 拉取数据,并以注释的形式在节点上用时间戳标记它们。
  • Dynamic plugin直接从节点的注释中读取负载数据,过滤并基于简单的算法对候选节点进行评分。


安装 Crane-Schedule

Crane-scheduler 是一组基于scheduler framework的调度插件。


配置 Prometheus 规则

如果根据 FinOps 之 Crane 成本优化(一) 进行安装的,已经配置过了。

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: example-record
spec:
  groups:
  - name: cpu_mem_usage_active
    interval: 30s
    rules:
    - record: cpu_usage_active
      expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[30s])) * 100)
    - record: mem_usage_active
      expr: 100*(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes)
  - name: cpu-usage-5m
    interval: 5m
    rules:
    - record: cpu_usage_max_avg_1h
      expr: max_over_time(cpu_usage_avg_5m[1h])
    - record: cpu_usage_max_avg_1d
      expr: max_over_time(cpu_usage_avg_5m[1d])
  - name: cpu-usage-1m
    interval: 1m
    rules:
    - record: cpu_usage_avg_5m
      expr: avg_over_time(cpu_usage_active[5m])
  - name: mem-usage-5m
    interval: 5m
    rules:
    - record: mem_usage_max_avg_1h
      expr: max_over_time(mem_usage_avg_5m[1h])
    - record: mem_usage_max_avg_1d
      expr: max_over_time(mem_usage_avg_5m[1d])
  - name: mem-usage-1m
    interval: 1m
    rules:
    - record: mem_usage_avg_5m
      expr: avg_over_time(mem_usage_active[5m])

Prometheus 的采样间隔必须小于30秒,不然可能会导致规则无法正常生效。如:cpu_usage_active


安装 Crane-schedule 作为第二个调度器

有两种选择:

  • 安装 Crane-scheduler 作为第二个调度器
  • 用 Crane-scheduler 替换原生 Kube-scheduler


这里使用第一种方法。替换原生调度器需要经过谨慎测试,安装方法参考官网:用 Crane-scheduler 替换原生 Kube-scheduler


将下面的 global.prometheusAddr 替换成自己的 prometheus 的 地址,要加 http:// 协议。

helm repo add crane https://finops-helm.pkg.coding.net/gocrane/gocrane
helm install scheduler -n crane-system --create-namespace --set global.prometheusAddr="http://prometheus-k8s.monitoring:9090" crane/scheduler


检查是否安装成功

查看 crane-scheduler-controller Pod 的日志。

FinOps 之 Crane 成本优化(二)_crane_13


查看node节点的 annotations 

FinOps 之 Crane 成本优化(二)_crane_14



默认调度策略文件

Crane-Schedule 默认的调度策略,配置文件如下:

# dynamic-scheduler-policy
# policy.yaml
    apiVersion: scheduler.policy.crane.io/v1alpha1
    kind: DynamicSchedulerPolicy
    spec:
      syncPolicy:
        ##cpu usage
        - name: cpu_usage_avg_5m
          period: 3m
        - name: cpu_usage_max_avg_1h
          period: 15m
        - name: cpu_usage_max_avg_1d
          period: 3h
        ##memory usage
        - name: mem_usage_avg_5m
          period: 3m
        - name: mem_usage_max_avg_1h
          period: 15m
        - name: mem_usage_max_avg_1d
          period: 3h

      predicate:
        ##cpu usage
        - name: cpu_usage_avg_5m
          maxLimitPecent: 0.65
        - name: cpu_usage_max_avg_1h
          maxLimitPecent: 0.75
        ##memory usage
        - name: mem_usage_avg_5m
          maxLimitPecent: 0.65
        - name: mem_usage_max_avg_1h
          maxLimitPecent: 0.75

      priority:
        ###score = sum(() * weight) / len,  0 <= score <= 10
        ##cpu usage
        - name: cpu_usage_avg_5m
          weight: 0.2
        - name: cpu_usage_max_avg_1h
          weight: 0.3
        - name: cpu_usage_max_avg_1d
          weight: 0.5
        ##memory usage
        - name: mem_usage_avg_5m
          weight: 0.2
        - name: mem_usage_max_avg_1h
          weight: 0.3
        - name: mem_usage_max_avg_1d
          weight: 0.5

      hotValue:
        - timeRange: 5m
          count: 5
        - timeRange: 1m
          count: 2


动态调度器提供了一个默认值调度策略并支持用户自定义策略。默认策略依赖于以下指标:

  • cpu_usage_avg_5m
  • cpu_usage_max_avg_1h
  • cpu_usage_max_avg_1d
  • mem_usage_avg_5m
  • mem_usage_max_avg_1h
  • mem_usage_max_avg_1d

在调度的Filter阶段,如果该节点的实际使用率大于上述任一指标的阈值,则该节点将被过滤。而在Score阶段,最终得分是这些指标值的加权和。


默认调度文件

里面包含的就是调度器的配置文件,我们会在配置中启用 Dynamic 动态调度插件。

# scheduler-config
# scheduler-config.yaml
    apiVersion: kubescheduler.config.k8s.io/v1beta2
    kind: KubeSchedulerConfiguration
    leaderElection:
      leaderElect: true
    profiles:
    - schedulerName: crane-scheduler		# 调度器名字
      plugins:
        filter:
          enabled:
          - name: Dynamic								# 开启插件名字
        score:
          enabled:
          - name: Dynamic								# 调度器打分
            weight: 3
      pluginConfig:
      - name: Dynamic
        args:							# 配置文件为上面的默认调度策略文件
          policyConfigPath: /etc/kubernetes/policy.yaml


使用 Crane-Schedule 调度器

使用 schedulerName: crane-scheduler 指定调度器。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cpu-stress
spec:
  selector:
    matchLabels:
      app: cpu-stress
  replicas: 1
  template:
    metadata:
      labels:
        app: cpu-stress
    spec:
      schedulerName: crane-scheduler
      hostNetwork: true
      tolerations:
      - key: node.kubernetes.io/network-unavailable
        operator: Exists
        effect: NoSchedule
      containers:
      - name: stress
        image: docker.io/gocrane/stress:latest
        command: ["stress", "-c", "1"]
        resources:
          requests:
            memory: "1Gi"
            cpu: "1"
          limits:
            memory: "1Gi"
            cpu: "1"


部署到k8s集群

$ kubectl apply -f test-crane-schedule.yaml -n crane-system
deployment.apps/cpu-stress created


查看describe,使用了期望的调度器。

FinOps 之 Crane 成本优化(二)_crane_15


卸载测试deployment

$ kubectl delete -f test-crane-schedule.yaml -n crane-system
deployment.apps "cpu-stress" deleted



三、精细化调度器

以后用到以下功能再继续更新。

https://gocrane.io/zh-cn/docs/tutorials/node-resource-tpolology-scheduler-plugins/

四、EHPA

https://gocrane.io/zh-cn/docs/tutorials/using-effective-hpa-to-scaling-with-effectiveness/

五、时序预测

https://gocrane.io/zh-cn/docs/tutorials/using-time-series-prediction/

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月12日 0

暂无评论

推荐阅读