如何在业务低峰期优先删除利用率低的 Kubernetes Pod 实例

公众号关注 「奇妙的 Linux 世界」

设为「星标」,每天带你玩转 Linux !

45aeac64a6d591a9fbc74a9d521136ac.png

需求场景

同一应用的不同 Pod 可能其利用率是不同的。

对应用执行缩容操作时, 可能希望移除利用率较低的 Pod

为了避免频繁更新 Pod,应用应该在执行缩容操作之前更新一次 controller.kubernetes.io/pod-deletion-cost 注解值 (将注解值设置为一个与其 Pod 利用率对应的值)。如果应用自身控制器缩容操作时(例如 Spark 部署的驱动 Pod),这种机制是可以起作用的。

controller.kubernetes.io/pod-deletion-cost

通过使用 controller.kubernetes.io/pod-deletion-cost 注解,用户可以对 ReplicaSet 缩容时要先删除哪些 Pod 设置偏好。

  • • 类别:注解

  • • 特性状态: Kubernetes v1.22 [beta]

  • • 例子:controller.kubernetes.io/pod-deletion-cost: "10"

  • • 用于:Pod

  • • 该注解用于设置 Pod 删除成本允许用户影响 ReplicaSet 缩减顺序。注解解析为 int32 类型。

此注解要设置到 Pod 上,取值范围为 [-2147483647, 2147483647]。所代表的是删除同一 ReplicaSet 中其他 Pod 相比较而言的开销。删除开销较小的 Pod 比删除开销较高的 Pod 更容易被删除。

Pod 如果未设置此注解,则隐含的设置值为 0。负值也是可接受的。如果注解值非法,API 服务器会拒绝对应的 Pod。

此功能特性处于 Beta 阶段,默认被启用。你可以通过为 kube-apiserver 和 kube-controller-manager 设置特性门控 PodDeletionCost 来禁用此功能。

说明:

  • • 此机制实施时仅是尽力而为,并不能对 Pod 的删除顺序作出任何保证;

  • • 用户应避免频繁更新注解值,例如根据某观测度量值来更新此注解值是应该避免的。这样做会在 API 服务器上产生大量的 Pod 更新操作。

实操演练

编写一个副本数为3的nginx-deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  # tells deployment to run 3 pods matching the template
  replicas: 3 
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

部署后,效果如下:

$ kubectl apply -f nginx-deployment.yaml 
deployment.apps/nginx-deployment created

$  kubectl get pod -owide
NAME                                READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
nginx-deployment-66b6c48dd5-97rjj   1/1     Running   0          11s   10.244.219.78   master   <none>           <none>
nginx-deployment-66b6c48dd5-fcckz   1/1     Running   0          11s   10.244.219.77   master   <none>           <none>
nginx-deployment-66b6c48dd5-rsq8j   1/1     Running   0          11s   10.244.219.79   master   <none>           <none>

修改pod注解,使用 controller.kubernetes.io/pod-deletion-cost 注解

nginx-deployment-66b6c48dd5-97rjj 删除成本设置为100

nginx-deployment-66b6c48dd5-fcckz删除成本设置为60

nginx-deployment-66b6c48dd5-rsq8j删除成本设置为20

# `nginx-deployment-66b6c48dd5-97rjj `删除成本设置为100
kubectl annotate pod nginx-deployment-66b6c48dd5-97rjj controller.kubernetes.io/pod-deletion-cost=100 --overwrite

# `nginx-deployment-66b6c48dd5-fcckz`删除成本设置为60
kubectl annotate pod nginx-deployment-66b6c48dd5-fcckz controller.kubernetes.io/pod-deletion-cost=60 --overwrite

# `nginx-deployment-66b6c48dd5-rsq8j`删除成本设置为20
kubectl annotate pod nginx-deployment-66b6c48dd5-rsq8j controller.kubernetes.io/pod-deletion-cost=20 --overwrite

查看所有pod的controller.kubernetes.io/pod-deletion-cost注解,发现 controller.kubernetes.io/pod-deletion-cost 注解已经被添加

$ kubectl get pods -l app=nginx -o custom-columns=POD_NAME:.metadata.name,POD_DELETION_COST:.metadata.annotations.'controller\.kubernetes\.io/pod-deletion-cost'
POD_NAME                            POD_DELETION_COST
nginx-deployment-66b6c48dd5-97rjj   100
nginx-deployment-66b6c48dd5-fcckz   60
nginx-deployment-66b6c48dd5-rsq8j   20

使用kubectl scale命令缩容nginx-deployment,发现controller.kubernetes.io/pod-deletion-cost数值低的pod优先被删除

$ kubectl scale deployment nginx-deployment --replicas=2
deployment.apps/nginx-deployment scaled

# 发现`controller.kubernetes.io/pod-deletion-cost`数值低的pod优先被删除
$  kubectl get pod -owide
NAME                                READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
nginx-deployment-66b6c48dd5-97rjj   1/1     Running   0          12m   10.244.219.78   master   <none>           <none>
nginx-deployment-66b6c48dd5-fcckz   1/1     Running   0          12m   10.244.219.77   master   <none>           <none>

上面我们的nginx-deployment-66b6c48dd5-rsq8j删除成本设置为20,数值最低,所以优先被删除。

拓展:kubectl scale缩容时删除pod的规则

缩容时默认删除pod的逻辑代码如下,有兴趣的同学可以看一下:

https://github.com/kubernetes/kubernetes/blob/release-1.11/pkg/controller/controller_utils.go#L737

func (s ActivePods) Less(i, j int) bool {
    // 1. Unassigned < assigned
    // If only one of the pods is unassigned, the unassigned one is smaller
    if s[i].Spec.NodeName != s[j].Spec.NodeName && (len(s[i].Spec.NodeName) == 0 || len(s[j].Spec.NodeName) == 0) {
        return len(s[i].Spec.NodeName) == 0
    }
    // 2. PodPending < PodUnknown < PodRunning
    m := map[v1.PodPhase]int{v1.PodPending: 0, v1.PodUnknown: 1, v1.PodRunning: 2}
    if m[s[i].Status.Phase] != m[s[j].Status.Phase] {
        return m[s[i].Status.Phase] < m[s[j].Status.Phase]
    }
    // 3. Not ready < ready
    // If only one of the pods is not ready, the not ready one is smaller
    if podutil.IsPodReady(s[i]) != podutil.IsPodReady(s[j]) {
        return !podutil.IsPodReady(s[i])
    }
    // TODO: take availability into account when we push minReadySeconds information from deployment into pods,
    //       see https://github.com/kubernetes/kubernetes/issues/22065
    // 4. Been ready for empty time < less time < more time
    // If both pods are ready, the latest ready one is smaller
    if podutil.IsPodReady(s[i]) && podutil.IsPodReady(s[j]) && !podReadyTime(s[i]).Equal(podReadyTime(s[j])) {
        return afterOrZero(podReadyTime(s[i]), podReadyTime(s[j]))
    }
    // 5. Pods with containers with higher restart counts < lower restart counts
    if maxContainerRestarts(s[i]) != maxContainerRestarts(s[j]) {
        return maxContainerRestarts(s[i]) > maxContainerRestarts(s[j])
    }
    // 6. Empty creation time pods < newer pods < older pods
    if !s[i].CreationTimestamp.Equal(&s[j].CreationTimestamp) {
        return afterOrZero(&s[i].CreationTimestamp, &s[j].CreationTimestamp)
    }
    return false
}

总结一下:

  1. 1. 如果pod没分配到节点,先被删除

  2. 2. 如果pod的状态是 Pending>PodUnknown>PodRunning,则Pending优先被删除,PodUnknown次之,PodRunning最后被删除。

  3. 3. 不是Ready状态的Pod先被删除。

  4. 4. 如果Pod都是Ready状态,则最后一个变成Ready状态的Pod先被删除(Ready时间最短的)。

  5. 5. 重启次数大的Pod先被删除。

  6. 6. 创建时间最新的Pod先被删除。

总结

controller.kubernetes.io/pod-deletion-cost 是一个用于 Kubernetes Pod 的注解(Annotation)。这个注解通常用于管理控制器(Controller)对于 Pod 删除的优先级和策略。以下是有关如何使用 controller.kubernetes.io/pod-deletion-cost 注解的一些信息:

  1. 1. 控制器中的 Pod 删除顺序:Kubernetes 控制器(如 Deployment、StatefulSet 等)通常会维护一组 Pod,它们共同形成一个应用程序或服务的一部分。在某些情况下,你可能希望定义哪些 Pod 比其他 Pod 更容易删除。这可以通过 controller.kubernetes.io/pod-deletion-cost 注解来实现。

  2. 2. 定义 Pod 删除的相对优先级:通过为 Pod 添加 controller.kubernetes.io/pod-deletion-cost 注解,你可以为每个 Pod 指定一个数字值,表示其删除的成本。较低成本的 Pod 将被控制器优先删除,以便在需要缩容时释放资源。这可以有助于控制器在缩容时选择删除哪些 Pod。例如,你可以设置:controller.kubernetes.io/pod-deletion-cost: "50"对于一个 Pod,而对于另一个 Pod,你可以设置:controller.kubernetes.io/pod-deletion-cost: "100"在这种情况下,具有成本为 50 的 Pod 会在成本为 100 的 Pod 之前被删除,以便控制器更倾向于删除成本较低的 Pod。

  3. 3. 控制器的自定义删除策略:一些自定义控制器可能会使用这个注解来实现自定义的 Pod 删除策略。这取决于控制器的设计和需求。

请注意,controller.kubernetes.io/pod-deletion-cost 注解的实际效果取决于控制器的实现和支持。并非所有控制器都支持这个注解,而且它的行为可能因控制器而异。如果你使用的是自定义控制器,可能需要查看相关文档或代码以了解如何正确配置和使用这个注解。

本文转载自:「云原生百宝箱」,原文:https://url.hi-linux.com/vpCoh,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。

e4afa2b4eca25fed68ee518a7ec3cd92.gif

最近,我们建立了一个技术交流微信群。目前群里已加入了不少行业内的大神,有兴趣的同学可以加入和我们一起交流技术,在 「奇妙的 Linux 世界」 公众号直接回复 「加群」 邀请你入群。

3c949d956768b00795e45f2d83aec725.png

你可能还喜欢

点击下方图片即可阅读

e3c53006d7209f2a647b8bd5cc29d3b8.png

图解几种常见 Kubernetes Pod 驱逐场景

7f850088dd85df4fefd709965e4cfff1.png
点击上方图片,『美团|饿了么』外卖红包天天免费领

a6400c909cccab7118e919dc4f7a7d8f.png

更多有趣的互联网新鲜事,关注「奇妙的互联网」视频号全了解!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值