前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >运维降本增效!大规模k8s集群的潮汐调度

运维降本增效!大规模k8s集群的潮汐调度

作者头像
SRE运维手记
发布2024-09-06 17:56:57
2200
发布2024-09-06 17:56:57
举报
文章被收录于专栏:SRE运维手记

01、背 景

有一个渲染应用场景,单一个工作负载(Deployment)就有数百个副本,为了降低运维成本,选择了某云商的弹性容器实例产品作为载体,其按pod数量以小时计费,相较于准备大量的Node的方式要划算得多。

CPU渲染应用有个特点,在执行任务的时候,CPU会将近满负载运作,有些超清的图片渲染任务甚至需要1-2个小时才能完成渲染,在闲置的时候负载又趋近于0,是一个典型的潮汐应用场景。

那么,如果能够精准回收闲置的Pods,将能够实现极致的运维降本,但同时又是一个难题,我们知道单纯用HPA是无法实现的,所以为了实现该目标,我们研究出了如下方案实现高效的潮汐调度。 02、方 案

据了解,在Kubernetes 1.22版本开始,默认开启了pod-deletion-cost特性,允许用户设置Pod的删除成本,它是一个整数值,可以为正数、零或负数,分值越低在缩容时的优先级越高。

我们在网上翻过很多资料,大多都是通过手动修改,亦或编写脚本定时进行批量修改,都不是很理想。

最后,我们发现了Openkruise这个组件,可以通过自定义探针PodProbeMarker自动给Pods注入pod-deletion-cost的分值,将CPU使用率较低的删除成本设置为5,将CPU使用率较高的设置为10,下面将介绍具体的实现过程,为了方便截图和演示,我们在实验环境进行。

03、实践分享

实验环境

Kubernetes 1.24

Openkruise 1.6

安装

PodProbeMarker能力默认是关闭的, 你可以通过 feature-gate PodProbeMarkerGate

打开,如下:

代码语言:javascript
复制
helm install kruise openkruise/kruise --version 1.6.3 --set featureGates="PodProbeMarkerGate=true"

实践步骤

  • 为简化演示的复杂度,我们使用nginx代替渲染应用进行演示,副本数为2,pod-deletion-cost值为100

nginx.yaml

代码语言:javascript
复制
apiVersion: apps/v1 
kind: Deployment
metadata:
  name: nginx
  namespace: hpa
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx  
  template:
    metadata:
      labels:
        app: nginx
        nginx-idle: 'xxx'   # 默认值设置为xxx,如果是闲置的时候会显示为ture
      annotations:
        controller.kubernetes.io/pod-deletion-cost: '100'  # 初始删除成本我们设置为100
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1
        ports:
        - containerPort: 80
        resources:
          requests:       # 必须设置,否则HPA无法运行
            cpu: 100m     # 设置容器运行时所需CPU资源
            memory: 200Mi # 设置容器运行时所需内存资源
          limits:         # 不是必须设置,但是设置后可以避免压测时占用过多资源
            cpu: 200m      # 限制容器CPU资源为200m,m 是毫核(milli-cores)的缩写,因此200m表示0.2核
            memory: 400Mi   # 限制容器内存资源为400Mi 
---
kind: Service
apiVersion: v1
metadata:
  name: nginx
  namespace: hpa
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

然后执行kubectl apply -f nginx.yaml完成部署

  • 再创建一个HPA控制器,当CPU使用率达到50%,则触发弹性扩缩容,为避免抖动带来的频繁伸缩容,我们把稳定窗口设置为300s,保留最小副本数为2

hpa.yaml

代码语言:javascript
复制
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
  namespace: hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 2  # Deployment可缩容的容器数量下限,需设置为大于等于1的整数
  maxReplicas: 10  # 该Deployment可扩容的容器数量上限,需大于minReplicas
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50 # 目标资源的平均使用率,即资源使用量的平均值与其请求量之间的比例
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
    scaleUp:
      stabilizationWindowSeconds: 300

执行kubectl apply -f hpa.yaml完成部署,创建完成后我们可以通过kubectl get hpa -n hpa查看HPA的状态

  • 接下来是关键环节,创建PodProbeMarker控制器,通过自定义探测脚本idle.sh来判断Pods的CPU是否处于空闲,如果空闲则将删除成本设置为5,繁忙则设置为10,而是否繁忙可以从渲染Pod启动时生成的/data/task.txt文件进行判断,值为0,即空闲,值为1,即繁忙。

idle.sh

代码语言:javascript
复制
#!/bin/bash
# 读取 /data/task.txt 文件的内容
task_status=$(cat /data/task.txt)

# 判断 task_status 的值
if [ "$task_status" -eq 0 ]; then
  # 如果值为 0,表示空闲
  exit 0
elif [ "$task_status" -eq 1 ]; then
  # 如果值为 1,表示繁忙
  exit 1
fi

probe.yaml

代码语言:javascript
复制
apiVersion: apps.kruise.io/v1alpha1
kind: PodProbeMarker
metadata:
  name: nginx-probe
  namespace: hpa
spec:
  selector:
    matchLabels:
      app: nginx
  probes:
  - name: Idle
    containerName: nginx
    probe:
      exec:
        command:
        - /home/nginx/idle.sh
      initialDelaySeconds: 10
      timeoutSeconds: 3
      periodSeconds: 10
      successThreshold: 1
      failureThreshold: 3
    markerPolicy:
    - state: Succeeded
      labels:
        nginx-idle: 'true'
      annotations:
        controller.kubernetes.io/pod-deletion-cost: '5'
    - state: Failed
      labels:
        nginx-idle: 'false'
      annotations:
        controller.kubernetes.io/pod-deletion-cost: '10'
    podConditionType: nginx.io/idle

执行kubectl apply -f probe.yaml完成部署,在完成部署后,我们可以通过如下指令查看当前Pods的删除成本,在繁忙状态下,所有的容器删除成本均从100自动修改为10,自动注入成功,有点小激动。

代码语言:javascript
复制
kubectl get pods -l app=nginx -n hpa -o json | jq '.items[] | {POD_NAME: .metadata.name, POD_DELETION_COST: .metadata.annotations["controller.kubernetes.io/pod-deletion-cost"]}'
  • 别急,我们还要验证下,当Pod空闲的时候是否会将删除成本修改为5呢?好的,我们让其中一个Pod的CPU冷静下,然后再执行上述pod-deletion-cost分值查看指令,果不其然,在CPU下来之后,这个Pod的删除成本变成了5,完美!
  • 最后一个环节,我们执行缩容,看看pod-deletion-cost分值低的Pod是否被优先删除,执行如下指令缩减副本。(正常情况下的工作负载扩缩容应当是HPA自动完成,在这里为了方便演示,我们才通过人为干预)
代码语言:javascript
复制
kubectl scale deployment nginx -n hpa --replicas=1
  • 查看缩容后的情况,分值较小的Pod被删除了,牛逼!!!

04、总结

综上所述,我们借助Openkruise根据Pod的负载情况自动注入pod-deletion-cost分值,从而实现渲染应用的潮汐调度,高效且精准地回收闲置Pods资源,极致节省运维成本,本期分享就到这里,谢谢!

欢迎订阅我的公众号「SRE运维手记」

参考链接

https://openkruise.io/docs/user-manuals/podprobemarker/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SRE运维手记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档