持续集成部署-k8s-高级调度-污点和容忍

持续集成部署-k8s-高级调度-污点和容忍

  • 1. 基本概念
  • 2. 使用场景
  • 3. 污点的基本操作
    • 1. 添加污点
    • 2. 查看污点
    • 3. 删除污点
    • 4. 污点的影响:
    • 5. 配置容忍
    • 6. 删除容忍
    • 7. 测试添加污点
  • 4. 容忍的配置

1. 基本概念

Kubernetes中,污点是一种属性,它可以被赋予Node(节点),用于标记该节点上的Pod应该避免调度的特定条件,例如特定的硬件限制、安全策略等。而容忍则是Pod的一个属性,它允许Pod在特定的污点条件下仍然被调度到对应的节点上。

k8s 集群中可能管理着非常庞大的服务器,这些服务器可能是各种各样不同类型的,比如机房、地理位置、配置等,有些是计算型节点,有些是存储型节点,此时我们希望能更好的将 pod 调度到与之需求更匹配的节点上。

此时就需要用到污点(Taint)和容忍(Toleration),这些配置都是 key: value 类型的。

比如我们拿一个三节点的 K8s 集群来说:

Master 节点一般是用来调度从节点实现对应的任务,是更重要的角色,而从节点是用来执行对应的任务的。当创建一个新的任务,无论是 Pod 还是 Deployment 都会先找没有存在污点的节点上执行。

污点还可以理解为,为了将未分配的任务排挤到没有污点的节点上运行。

容忍,就是反过来的概念,你有污点,我这个任务配置了容忍,也就是可以容忍你有污点,这时候我这个任务还是可以调度到这个节点上的。

2. 使用场景

  • 硬件特性限制:当某些节点具有特定的硬件特性(如GPU、TPU等)时,可以给这些节点打上对应的污点,然后只有带有对应容忍标记的Pod才会被调度到这些节点上,从而保证Pod能够充分利用这些硬件资源。

  • 避免节点负载过高:当节点负载过高时,可以给这些节点打上污点,防止新的Pod被调度到这些节点上,以避免进一步加重节点负载。

  • 安全策略:通过污点和容忍,可以实现对部分节点进行安全隔离,例如将某些特殊的安全策略应用到特定的节点上,以满足安全合规性要求。

  • 节点维护:在节点需要维护时,可以先将节点打上污点,然后逐步驱逐上面的Pod,以确保维护操作不会影响到正在运行的应用程序。

总之,污点和容忍功能为Kubernetes集群的高级调度提供了灵活性和精细化的控制,可以根据实际需求对Pod的调度行为进行定制,使得整个集群能够更好地适应复杂的业务场景和运维需求。

3. 污点的基本操作

1. 添加污点

要向节点添加污点,可以使用kubectl命令行工具执行以下命令:

kubectl taint nodes <node-name> key=value:taint-effect

其中:

  • 是要添加污点的节点名称。
  • key=value 是污点的键值对,可以根据实际情况定义不同的键值对,例如gpu=true。
  • taint-effect 指定了污点的效果,包括:
    • NoSchedule:表示新的Pod将不会被调度到带有此污点的节点上。
    • NoExecute:表示已经存在的Pod如果不满足对应的容忍条件,则将被驱逐出该节点。

例如,要向名为node1的节点添加一个gpu=true:NoSchedule的污点,可以执行以下命令:

kubectl taint nodes node1 gpu=true:NoSchedule

2. 查看污点

kubectl describe no k8s-master

3. 删除污点

要删除节点上的污点,可以使用kubectl命令行工具执行以下命令:

kubectl taint nodes <node-name> key-

这里最后的这个 - 号,就是删除这个污点的意思。这跟操作 Label 是一样的。

例如,要删除名为node1的节点上的gpu=true:NoSchedule污点,可以执行以下命令:

kubectl taint nodes node1 gpu-

4. 污点的影响:

  • NoSchedule:不能容忍的 pod 不能被调度到该节点,但是已经存在的节点不会被驱逐
  • NoExecute:不能容忍的节点会被立即清除,能容忍且没有配置- tolerationSeconds 属性,则可以一直运行,设置了 tolerationSeconds: 3600 属性,则该 pod 还能继续在该节点运行 3600 秒

5. 配置容忍

# pod 的 spec 下面配置容忍
tolerations:
- key: "污点的 key"
  value: "污点的 value"
  offect: "NoSchedule" # 污点产生的影响
  operator: "Equal" # 表是 value 与污点的 value 要相等,也可以设置为 Exists 表示存在 key 即可,此时可以不用配置 value

其中:

  • Equal: 比较操作类型为 Equal,则意味着必须与污点值做匹配,key/value都必须相同,才表示能够容忍该污点;
  • Exists:容忍与污点的比较只比较 key,不比较 value,不关心 value 是什么东西,只要 key 存在,就表示可以容忍。

6. 删除容忍

要删除Pod的容忍规则,可以通过编辑Pod的配置文件,将tolerations字段移除或者修改为其他的容忍规则。

7. 测试添加污点

看下当前集群中 Pod 的调度情况:

[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS      RESTARTS        AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-ptqc6   1/1     Running     318 (42m ago)   13d     10.244.2.96    docker-56   <none>           <none>
nginx-deploy-bcc5c945c-vwbrd   1/1     Running     140 (42m ago)   5d20h   10.244.1.61    docker-55   <none>           <none>
[root@docker-54 ~]# 

可以看到,当前集群中在没有配置任何污点时的调度,docker-55、docker-56 两个节点的调度情况基本一致;

现在给 docker-56 节点添加一个内存低的污点:memory=low:NoSchedule

kubectl tain no docker-56 memory=low:NoSchedule

在执行前可以先看下节点的污点情况:kubectl describe no docker-56
其中污点信息Taints如下:

CreationTimestamp:  Sun, 14 May 2023 23:05:48 +0800
Taints:             <none>
Unschedulable:      false

看下 Master 节点的污点情况:

[root@docker-54 ~]# kubectl describe no docker-54
CreationTimestamp:  Sun, 14 May 2023 22:57:50 +0800
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false

可以看到这里设置了污点的内容是:node-role.kubernetes.io/master:NoSchedule ,也就是如果没有配置容忍为 node-role.kubernetes.io/master 则不会调度到 Master 节点上。

然后对节点 docker-56 添加完污点信息,则变为:

CreationTimestamp:  Sun, 14 May 2023 23:05:48 +0800
Taints:             memory=low:NoSchedule
Unschedulable:      false

接着看下 Pod 的执行情况:

[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS      RESTARTS        AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-ptqc6   1/1     Running     318 (51m ago)   13d     10.244.2.96    docker-56   <none>           <none>
nginx-deploy-bcc5c945c-vwbrd   1/1     Running     140 (51m ago)   5d20h   10.244.1.61    docker-55   <none>           <none>
[root@docker-54 ~]# 

可以看到这时候,是没什么区别的,因为我们上面配置的污点是 NoSchedule,只是不再往上面调度任务了,对于已经存在的Pod 则不会有影响。

对于 Master 节点的污点,如果删除了该污点,则新创建的 Pod 任务是允许调度到 Master 节点上的。

我们来测试下看看效果:

先删除 Master 节点上的污点

[root@docker-54 ~]# kubectl taint no docker-54 node-role.kubernetes.io/master-
node/docker-54 untainted
[root@docker-54 ~]# 

然后手动删除之前部署的 nginx-deploy,由于之前是使用 deploy 创建的 Pod,在手动删除后,k8s 会自动再启动两个 Pod;

[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS              RESTARTS          AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-blsgx   1/1     Running             0                 28s     10.244.1.72    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-ptqc6   1/1     Terminating         319 (5m15s ago)   13d     10.244.2.96    docker-56   <none>           <none>
nginx-deploy-bcc5c945c-rf6gl   0/1     ContainerCreating   0                 28s     <none>         docker-54   <none>           <none>
nginx-deploy-bcc5c945c-vwbrd   1/1     Terminating         141 (4m21s ago)   5d21h   10.244.1.61    docker-55   <none>           <none>
[root@docker-54 ~]# 
[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS              RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-blsgx   1/1     Running             0             51s     10.244.1.72    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-rf6gl   0/1     ContainerCreating   0             51s     <none>         docker-54   <none>           <none>
[root@docker-54 ~]# 

可以看到,上面在删除了之后,两个新的 nginx-deploy 的 Pod 又重新启动,并且一个已经被调度到 Master 节点 docker-54 上。

然后调整 Master 节点的污点,新增一个 NoExecute 污点:

[root@docker-54 ~]# kubectl taint no docker-54 node-role.kubernetes.io/master:NoExecute
node/docker-54 tainted
[root@docker-54 ~]# 
[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS        RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-9mcs5   1/1     Running       0             22s     10.244.1.75    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-blsgx   1/1     Running       0             4m13s   10.244.1.72    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-rf6gl   1/1     Terminating   0             4m13s   10.244.0.10    docker-54   <none>           <none>
[root@docker-54 ~]# 
[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS      RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-9mcs5   1/1     Running     0             52s     10.244.1.75    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-blsgx   1/1     Running     0             4m43s   10.244.1.72    docker-55   <none>           <none>
[root@docker-54 ~]# 

可以看到,在新增 NoExecute 污点后,docker-54 节点上的 Pod 被驱离,这时候两个 nginx-deploy 的Pod 都被调度到 docker-55 节点上了。而没有调度到 docker-56 节点,这是因为 docker-56 节点上有个 NoSchedule 的污点。

测试完毕,恢复 Master 节点上的污点:

[root@docker-54 ~]# kubectl taint no docker-54 node-role.kubernetes.io/master-
node/docker-54 untainted
[root@docker-54 ~]# 
[root@docker-54 ~]# kubectl taint no docker-54 node-role.kubernetes.io/master:NoSchedule
node/docker-54 tainted
[root@docker-54 ~]# 
[root@docker-54 ~]# 
[root@docker-54 ~]# 
[root@docker-54 ~]# kubectl taint no docker-56 memory-
node/docker-56 untainted
[root@docker-54 ~]#

4. 容忍的配置

由于我的 docker-56 节点的污点设置值为memory=low:NoSchedule

[root@docker-54 ~]# kubectl describe no docker-56 |grep Taints
Taints:             memory=low:NoSchedule
[root@docker-54 ~]# 

所以接下来测试下设置容忍这个污点。

添加容忍前,Pod 调度情况:

[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS      RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-9mcs5   1/1     Running     2 (31m ago)   151m    10.244.1.75    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-blsgx   1/1     Running     2 (35m ago)   155m    10.244.1.72    docker-55   <none>           <none>
[root@docker-54 ~]# 

由于我这里之前运行过 nginx-deploy 这里就直接修改deploy 新增容忍的配置:

[root@docker-54 jobs]# kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   2/2     2            2           46d
[root@docker-54 jobs]# 

然后编辑:kubectl edit deploy nginx-deploy

  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      tolerations:
      - effect: "NoSchedule"
        key: "memory"
        operator: "Equal"
        value: "low"
      containers:
        image: nginx:1.7.9
        imagePullPolicy: IfNotPresent
        name: nginx

新增 tolerations相关的内容,这里需要注意,需要配置在 模板template下的 spec里面,跟 containers 并齐。

这里为了测试上面的污点,所以配置了 Equal。修改完毕保存,看下 Pod 的变化情况;

[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS      RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-bcc5c945c-9mcs5   1/1     Running     2 (31m ago)   151m    10.244.1.75    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-blsgx   1/1     Running     2 (35m ago)   155m    10.244.1.72    docker-55   <none>           <none>
[root@docker-54 ~]# 
[root@docker-54 ~]# 
[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS              RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-b8886d997-46sm4   1/1     Running             0             4s      10.244.2.118   docker-56   <none>           <none>
nginx-deploy-b8886d997-d92xh   0/1     ContainerCreating   0             2s      <none>         docker-55   <none>           <none>
nginx-deploy-bcc5c945c-9mcs5   1/1     Terminating         2 (33m ago)   153m    10.244.1.75    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-blsgx   1/1     Running             2 (37m ago)   157m    10.244.1.72    docker-55   <none>           <none>
[root@docker-54 ~]# kubectl get po -o wide
NAME                           READY   STATUS        RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deploy-b8886d997-46sm4   1/1     Running       0             14s     10.244.2.118   docker-56   <none>           <none>
nginx-deploy-b8886d997-d92xh   1/1     Running       0             12s     10.244.1.76    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-9mcs5   1/1     Terminating   2 (33m ago)   153m    10.244.1.75    docker-55   <none>           <none>
nginx-deploy-bcc5c945c-blsgx   1/1     Terminating   2 (37m ago)   157m    10.244.1.72    docker-55   <none>           <none>
[root@docker-54 ~]# 

可以看到,在更新完 deployment 之后,原先 docker-55 节点上的两个 Pod ,停止了一个,然后在 docker-56 节点上启动了一个 Pod。证明上面配置的容忍生效了。这就是容忍的一个效果。

另外由于上面使用的是 Equal ,这个在比对污点的 key 的同时,还会比对 value ,当全部匹配的时候,容忍才能生效。当然也可以使用 Exists ,无需配置 value,因为这样就仅仅匹配污点的 key即可生效。

测试下再次修改 deploy ,使用 Exists 来配置容忍,删除 value,保存,看下 Pod 的情况:

[root@docker-54 ~]# kubectl get po -o wide |grep nginx-deploy
nginx-deploy-b8886d997-46sm4   1/1     Terminating   0             19m    10.244.2.118   docker-56   <none>           <none>
nginx-deploy-b8886d997-d92xh   1/1     Terminating   0             19m    10.244.1.76    docker-55   <none>           <none>
nginx-deploy-b8976d7b5-77mgp   1/1     Running       0             29s    10.244.1.77    docker-55   <none>           <none>
nginx-deploy-b8976d7b5-fvqn8   1/1     Running       0             31s    10.244.2.119   docker-56   <none>           <none>
[root@docker-54 ~]# 
[root@docker-54 ~]# kubectl get po -o wide |grep nginx-deploy
nginx-deploy-b8976d7b5-77mgp   1/1     Running     0             2m10s   10.244.1.77    docker-55   <none>           <none>
nginx-deploy-b8976d7b5-fvqn8   1/1     Running     0             2m12s   10.244.2.119   docker-56   <none>           <none>
[root@docker-54 ~]# 

可以看到 Pod 被重新调度了,还是分别调度到两个从节点上。

有一点需要注意的是:如果设置了 NoExecute 的污点,这时候配置 NoSchedule 的容忍是没办法生效的。

可以这么理解,由于配置了 NoExecute 的污点,这时候上面所有没有配置容忍的 Pod 都会被驱离,即使 Pod 里面配置了 NoSchedule 的容忍。

在配置NoExecute 污点的容忍规则的时候,还有一种玩法使用tolerationSeconds参数,可以使用tolerationSeconds参数来设置Pod在被驱逐之前可以容忍的时间。如果没有配置,则可以一直容忍这个污点,Pod 可以一直运行。如果配置了这个时间,到这个时间就忍不下去了,这个 Pod 就会被停掉。

这里需要注意,在配置 tolerationSeconds参数的时候,可能会存在一个反复调度到上面,然后到容忍的时间之后被停掉,然后再次调度,再次被停掉的一个循环过程中。

所以,在配置tolerationSeconds参数时,需要仔细考虑集群的资源和调度策略,以避免出现Pod被循环停止和重新调度的问题。

你可能感兴趣的:(Kubernetes,ci/cd,kubernetes,容器)