#yyds干货盘点# Kubernetes 你必须掌握的 Pod 抢占式资源调度(20)

随着我们在 Kubernetes 集群中部署越来越多的业务,势必要考虑集群的资源利用率问题。尤其是当集群资源比较紧张的时候,如果此时还要部署一些比较重要的关nginx代理键业务,那么该如何去提前“抢占”集群资源,从而使得关键业务在集群中跑起来优先级调度算法呢?

这里一个最常见的做法就是采用优先级方案。通过给 Pod 设置高优先级,让其比其他 Pod 显得更为重要,通过这种“插队”的方式优先获得调度器的调度nginx反向代理。现在我们就来看看 Kubernetes 是如何定义这种优先k8s部署级的。

Priority优先级最高的运算符Class

Kubernetes 通过对象 PriorityCla高优先级ss 来定义上述优先级,具体怎么定义呢优先级c语言?我们可以通过之前说过的kubec云计算导论tl create命令来创建这个对象:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000" target="_blank">1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only."

这里我们创建了就是一个名为 hik8smgh-priority 的 PriorityClass 定义,使用的 API 版本是 scheduling.k8s.io/v1。这个对象是个集群级别的定义,并不属于任何 name云计算是什么space,可以被全局使用,即各个 namespace 中创dockerhub建的 Pod 都能使用nginx负载均衡 PriorityClass。我们在定义这样一个 Priorityk8s是干嘛的Class 对象的时候,名字不可云计算大数据以包含 systenginx是什么意思m- 这个前缀。

关于这个数值的设置,有优先级调度算法几点要说明。系统自定义了两个优先级值:

// HighestUserDefinablePriority is the highest priority for user defined priority classes. Priority values larger than 1 billion are reserved for Kubernetes system use.
HighestUserDefinablePriority = int32(1000000000)
// SystemCriticalPriority is the beginning of the range of priority values for critical system components.
SystemCriticalPriority = 2 * HighestUserDefinablePriority

那么当你自己创建 PriorityClass 的时候,定义的优先级值是不能高k8s于这里的 HighestUserDefinablePriority 的, 即 1000000000 (10 亿)云计算大数据

Kubernetes 在初始化的时候就自带了两个 Prioridocker常用命令tyClasses,即 system-cluster-critical 和 system-node-critical,优先级值为 2000000000。 你可以通过下面的命令查看到docker安装部署这两个最高优先级的 PriorityClasse:

$ kubectl get priorityclass
NAME                      VALUE        GLOBAL-DEFAULT   AGE
system-cluster-critical   2000000000   false            59d
system-node-critical      2000001000   false            59d

这是两个公共的优先级类,主要用nginx来确保 Kubernetes 系统的关键组件或者关键插件总是能够优先被调度,比如 coredns 等。因为一旦这些关键组件、关键插件被驱逐,或者由于镜像需要升级,新建的nginx反向代理 Pod 无法被调度,始终处于 Pendidockernnginx代理g 的状态,这些都会导致整个集群异常,甚至停止工作。所以对于这些关键的组件,我们务必保证nginx代理其优先级是最高的,这样才会被最先调度。我们可以来参考下 coredns 的做法,以下是截取的一部分配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  ...
  name: coredns
  namespace: kube-system
  ...
spec:
  ...
  template:
    ...
    spec:
      ...
      priorityClassName: system-cluster-critical
      ...
status:
  ...

下面我们来看看如何在 Pod 中使用 PriorityCl云计算是什么ass:通过 spec.priorityClassName 即可指定要使用的 PriorityClass:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  priorityClassName: high-priority

通过kubectl creadockerste创建好该 Pod 后,我们查看详情可以看到 PriorityClass 的名字和优先级数值都被写入了 Pod 中:

$ kubectl describe pod nginx
Name:                 nginx
Namespace:            default
Priority:             1000000
Priority Class Name:  high-priority
...

注意,在使用的时候不允许自己去设置 spec.priority 的数云计算值,我们只能通过 spec.priorityClassName 来设置优先级。现在,我们回过头再来观察下上docker面定义的这个 high-priority 的 PriorityClass 对象,里面有两个可选字段:globalDefault 和 descnginx是什么意思ription。

globalDefault 用来表明是否将该 PriorityClass 的数值作为默认值,并将其应用在所有未设置 prioritynginx安装与配置详解Clasdocker安装部署sName 的 Pod 上。 既然是默认值,那么就意味着整个 Kubernetes 集群中只能存在一个 globalDefak8s全称ult 设为 trudockers什么品牌e 的 PriorityClass 对象。

如果没有任何一个 PriorityCla优先级c的任务特点ss 对象的 globalDefaul云计算的特点t 被设置为 true 的话,就意味着所有未设置 spec.priorityClassName 的 Pod 的优先级为 0。即便你新建了某个 PriorityClass 对象,并将其 globalDefault 设置为 true,那么也不不影响集群中的存量 Pod,只会对新建的 Pod 生效。

你可以在 description 字段中对该 PriorityClass 进行一些使用上的解释说明。

现在我们就来做个优先级抢占的测试,使用一个单节点的集群做演示,该节点的 CPU 为 2 核。先创建一个优先级值更小云计算分为哪些类型的名为 lo云计算是什么w-priority 的 PriorityClass,其 YAML 文件如下:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: low-priority
value: 1000
globalDefault: false

创建好了以后,通过kubectl get可以查看到创建的这两个 PriorityClass:

$ kubectl get priorityclass | grep -v system
NAME                      VALUE        GLOBAL-DEFAULT   AGE
high-priority             1000000      false            30m
low-priority              1000         false            8m35s

现在我们分别使用这两个 PriorityClass 创k8s和docker区别建两个 Pod。先来docker菜鸟教程创建一个使用 low-priority 作为优先级的nginx重启 Pod,下面是其对应的 YAML 文件:

apiVersion: v1
kind: Pod
metadata:
 name: nginx-low-pc
spec:
 containers:
 - name: nginx
   image: nginx
   imagePullPolicy: IfNotPresent
   resources:
    requests:
     memory: "64Mi"
     cpu: "1200m"       #CPU需求设置较大
    limits:
     memory: "128Mi"
     cpu: "1300m"
 priorityClassName: low-priority     #使用低优先级

这里我们指定了一个较大比重的 CPU 资源。我们假定集群中的节点为 2 核,把 Pod 需要的最低 CPU 需求设置为1200m,超过了 2核 CPU 总算力的一半。

同样我们使用 high-priority 作为其优优先级调度算法先级创建一个 Pod,其对应的 YAML 文件如下:

apiVersion: v1
kind: Pod
metadata:
 name: nginx-high-pc
spec:
 containers:
 - name: nginx
   image: nginx
   imagePullPolicy: IfNotPresent
   resources:
    requests:
     memory: "64Mi"
     cpu: "1200m"
    limits:
     memory: "128Mi"
     cpu: "1300m"
 priorityClassName: high-priority        #使用高优先级

如此一来,这两个 Pod 无法被调度到同一个只有 2 核nginx反向代理 CPU 的节点上的,因为 2 个 Pod 加起来的 CPU 请求总量云计算定义超过了 2 核。

我们可以先创建低优先级 Pod 命名为 ngnginxinx-low-pc ,可以看到该 Pod 已经成功运行,并消耗了超过一半的 CPU:

$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
nginx-low-pc   1/1     Running   0          22s
$ kubectl describe pod nginx-low-pc
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests     Limits
--------           --------     ------
  cpu                1220m (61%)  1300m (65%)       #Node的CPU使用率已经过半
  memory             64Mi (1%)    128Mi (3%)
  ephemeral-storage  0 (0%)       0 (0%)

现在我们再创建高优先级 Pod 命名为 nginx-high-pc,可以看到低优先级 Pod nginnginx安装与配置详解x-low-pc 由于高优先级的资源抢占被驱逐,运行状态也从 Runing 状态变为了 Terminating:

$ kubectl get pods
NAME            READY   STATUS        RESTARTS   AGE
nginx-high-pc   0/1     Pending       0          7s
nginx-low-pc    0/1     Terminating   0          87s
$ kubectl get pods
NAME            READY   STATUS    RESTARTS   AGE
nginx-high-pc   1/1     Running   0          12s

最终,高优先级 Podnginx怎么读 成功完成了抢nginx代理占,整个节点上只有它在运行。当新 Pod 被创建优先级c语言后,它们就进入了调度器的队列,优先级越小越优先吗等待被调度。k8s资源调度器会根据 PriorityClass 的优先级来挑选出优先级最高的 Pod,并且尝试把它调度到一个节点上。

如果这个时候没有任何一个节点能够满足这个 Pod的所有要求,包括资源、调度偏好等要求,就会触发抢占逻辑。调度器会尝云计算定义试寻找一个节点,通过移除一个或者多个比该 Pod 的优先级低的 Pok8s和docker区别d, 尝试使目标 Pod 可以被调度。

如果找到dockerhub了这样一个节点,那么运行在该节点上的一个或者多个低优先级的 Pod 就会被驱逐,这样这个高优先级的 Pod 就可以调度到目标节点上了。哈哈,是不是有最高优先级点“鸠占鹊云计算导论巢”的感觉!

当然对于某些场景,如果你并不希望 Pod 被驱逐掉,只是希望可以优先nginx调度,那么你可以使用非抢占式的 PriorityClass。比如这是一个非抢占式的 PriorityClk8smass 的配置:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority-nonpreempting
value: 1000000
preemptionPolicy: Never
globalDefault: false
description: "This priority class will not cause other pods to be preempted."

这个配置跟我们上面的定义基本一致,只不过多了一个字段 preemptionPolicy。这样就可以避免属于该 PriorityClass 的 Pod 抢占其他 Pod。当然你也可以通过给 kube-scheduler 设置参数禁用抢占能力。但是关键组件的 Pod 还是依赖调度器这种抢占机制,以便在集群资源压力较大时可以优先得到调度。因此,不建议你禁用抢占能力。

kube-scheduler 的抢占能力是通过 disablePreemption 这个参数来控制的,该标志默认为 false。如果nginx是什么意思你还是坚持禁用抢占,可以将 disak8s架构原理blePreemption 设置k8s资源为 true,目前这一参数的配置,只能通过 KubeSchedulerConfiguration 来设置,即:

apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
algorithmSource:
  provider: DefaultProvider
...
disablePreemption: true

小结

提高集群nginx反向代理的资源利用率最常见的做法就是采用优先级的方案。在实际使用的时候,要避免恶意用户创建高优先级的 Pod,这样会导致其他 Pod 被驱逐或者无法调度,严重影响集群的稳定性和安全性。集群管理员可以为特定用户创建特定优先级级别,来防止他们恶意使用高优先级的 PriorityClass。

欢迎大家扫码关注,获取更多信息