kubernetes-Pod基于污点、容忍度、亲和性的多种调度策略(二)

Pod调度策略

一.污点-Taint

在 Kubernetes 中,污点(Taint)是一种标记,用于标识一个Node节点上的某些资源或条件不可用或不可接受。当一个节点被标记了污点后,只有那些能够容忍该污点的 Pod 才能被调度到该节点上。

污点常用与以下场景:

  • 将某些节点标记为"故障",以防止新的 Pod 被调度到这些节点上;
  • 将某些节点标记为"高负载",以防止过多的 Pod 被调度到这些节点上,导致节点过载;
  • 将某些节点标记为"专用",以保证只有特定的 Pod 能够被调度到这些节点上。

pod亲和性是pod属性;但是污点是节点的属性,污点定义在k8s集群的节点上的一个字段。

shell 复制代码
# 查看控住节点定义的污点
[root@master1]# kubectl describe nodes master1 | grep Taints
Taints:             node-role.kubernetes.io/control-plane:NoSchedule
 
# 两个工作节点是没有定义污点
[root@node1]# kubectl describe nodes node1 | grep Taints
Taints:             <none>
 
[root@node2]# kubectl describe nodes node2 | grep Taints
Taints:             <none>

1.查看定义taint的信息

shell 复制代码
# 查看帮助命令
[root@master1]# kubectl explain node.spec
······
   taints	<[]Object>
     If specified, the node's taints.
[root@master1]# kubectl explain node.spec.taints
KIND:     Node
VERSION:  v1
RESOURCE: taints <[]Object>
DESCRIPTION:
     If specified, the node's taints.
 
     The node this Taint is attached to has the "effect" on any pod that does
     not tolerate the Taint.
 
FIELDS:
   effect	<string> -required-
     Required. The effect of the taint on pods that do not tolerate the taint.
     Valid effects are NoSchedule, PreferNoSchedule and NoExecute.
 
     Possible enum values:
     - `"NoExecute"` Evict any already-running pods that do not tolerate the
     taint. Currently enforced by NodeController.
     - `"NoSchedule"` Do not allow new pods to schedule onto the node unless
     they tolerate the taint, but allow all pods submitted to Kubelet without
     going through the scheduler to start, and allow all already-running pods to
     continue running. Enforced by the scheduler.
     - `"PreferNoSchedule"` Like TaintEffectNoSchedule, but the scheduler tries
     not to schedule new pods onto the node, rather than prohibiting new pods
     from scheduling onto the node entirely. Enforced by the scheduler.
 
   key	<string> -required-
     Required. The taint key to be applied to a node.
 
   timeAdded	<string>
     TimeAdded represents the time at which the taint was added. It is only
     written for NoExecute taints.
 
   value	<string>
     The taint value corresponding to the taint key.

污点排斥等级:

  • NoSchedule:表示Pod不会被调度到具有该污点的节点上,不影响已经存在的Pod
  • PreferNoSchedule:表示调度器会尽量避免将Pod调度到具有该污点的节点上。(但是Pod没有定义容忍度,依然会被调度到这两个节点上)
  • NoExecute:既影响Pod调度过程,又影响现存Pod对象,如果现存Pod不能容忍节点加的污点,那么这个Pod就会被驱逐

2.定义污点

shell 复制代码
kubectl taint nodes node1 node-type=dev:NoSchedule

3.查看污点

shell 复制代码
kubectl describe nodes node1 | grep Taint

4.删除污点

shell 复制代码
kubectl taint nodes node1 node-type=dev:NoSchedule-

二.容忍度-Tolerations

当我们节点定义污点后,如果我们不定义对应的容忍度,那么Pod将不会调度到此Node节点。

方便下面实验,我把所有node节点全部定义上污点

shell 复制代码
kubectl taint nodes node1 node-type=dev:NoSchedule
kubectl taint nodes node2 node-type=dev:NoSchedule

查看容忍度的帮助:

shell 复制代码
kubectl explain pod.spec.tolerations

1.定义Pod容忍度,容忍node-type=dev,且排斥等级等于NoExecute,使用了operator=Equal这三点必须同时能满足。

shell 复制代码
cat pod1.yml 
---
apiVersion: v1
kind: Pod
metadata:
  name: pod1
  namespace: default
  labels:
    app: nginx
    env: dev

spec:
  tolerations:
  - effect: "NoExecute"   # 指定排斥等级
    key: "node-type"      # 污点key
    operator: "Equal"     # Equal表示等于
    value: "dev"          # 污点value
    tolerationSeconds: 3600 # 删除Pod前等待时间,默认30s

  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

执行文件

shell 复制代码
kubectl  apply  -f pod1.yaml

查看状态,因为没有任何节点满足该Pod容忍,所以该Pod处于Pending状态

shell 复制代码
kubectl get pods pod1

NAME    READY   STATUS    RESTARTS   AGE
pod1    0/1     Pending   0          10m

2.定义Pod容忍度,将排斥等级改为 NoSchedule,这样我们污点key,value,排斥等级都满足了,Pod才会调度 Pod资源清单文件如下:

shell 复制代码
cat pod2.yml 
---
apiVersion: v1
kind: Pod
metadata:
  name: pod2
  namespace: default
  labels:
    app: nginx
    env: dev

spec:
  tolerations:
  - effect: "NoSchedule"  # 指定排斥等级
    key: "node-type"      # 污点key
    operator: "Equal"     # Equal表示等于
    value: "dev"          # 污点value

  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

执行文件

shell 复制代码
kubectl apply -f pod2.yaml

查看状态,Pod成功调度,且状态为 Running

shell 复制代码
kubectl get pods pod2

NAME    READY   STATUS    RESTARTS   AGE
pod2    1/1     Running   0          5m32s

3.定义Pod容忍度,将 operator=Exists表示满足其中一项即可容忍,下面Pod没有定义key,value,表示没有key,value方面限制,容忍排斥等级=NoSchedule的节点。

shell 复制代码
cat pod3.yml 
---
apiVersion: v1
kind: Pod
metadata:
  name: pod3
  namespace: default
  labels:
    app: nginx
    env: dev

spec:
  tolerations:
  - effect: "NoSchedule"  # 指定排斥等级 
    operator: "Exists"    # Exists表示满足一项即可

  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

执行文件

shell 复制代码
kubectl  apply -f pod3.yaml

查看状态,Pod调度成功,且状态为Running

shell 复制代码
kubectl get pods pod-3

NAME    READY   STATUS    RESTARTS   AGE
pod3   1/1     Running   0          5m16s

三.Pod常见状态和重启策略

1.Pod常见状态

第一阶段:

  • 挂起(Pending):
    • 正在创建Pod,但是Pod中的容器还没有全部被创建完成,处于此状态的Pod应该检查Pod依赖的存储是否有权限挂载、镜像是否可以下载、调度是否正常等;
    • 我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度没有完成。
  • 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
  • 未知(Unknown):未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown,通常是由于与pod所在的node节点通信错误。
  • Error 状态:Pod 启动过程中发生了错误
  • 成功(Succeeded):Pod中的所有容器都被成功终止,即pod里所有的containers均已terminated。

第二阶段:

  • Unschedulable:Pod不能被调度, scheduler没有匹配到合适的node节点PodScheduled:pod正处于调度中,在scheduler刚开始调度的时候,还没有将pod分配到指定的node,在筛选出合适的节点后就会更新etcd数据,将pod分配到指定的node
  • Initialized:所有pod中的初始化容器已经完成了
  • ImagePullBackOff:Pod所在的node节点下载镜像失败
  • Running:Pod内部的容器已经被创建并且启动。

扩展:还有其他状态,如下:

  • Evicted状态:出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其是一些大文件、docker镜像。
  • CrashLoopBackOff:容器曾经启动了,但可能又异常退出了。如pod一直在重启

2.Pod的重启策略

Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,当某个容器异常退出或者健康检查失败时,kubelet将根据 重启策略来进行相应的操作。

    Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
  • Always:只要容器异常退出,kubelet就会自动重启该容器。(这个是默认的重启策略)
  • OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。(生产环境中常用)
  • Never:不论容器运行状态如何,kubelet都不会重启该容器。

2.1测试Always重启策略

shell 复制代码
[root@master1]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
  namespace: default
  labels:
    app: myapp
spec:
  restartPolicy: Always
  containers:
  - name:  tomcat
    ports:
    - containerPort: 8080
    image: tomcat:latest
    imagePullPolicy: IfNotPresent
 
[root@master1]# kubectl apply -f pod.yaml 
pod/demo-pod created
[root@master1]# kubectl get pods -o wide 
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
demo-pod   1/1     Running   0          10s   10.244.169.153     node2      <none>           <none>
 
# 动态显示pod状态信息
[root@master1]# kubectl get pods -o wide -w
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
demo-pod   1/1     Running   0          22s   10.244.169.153   node2       <none>           <none>
 
# 另起一个终端会话,进入pod内部容器,正常停止 tomcat 容器服务。-c 指定容器名称。
[root@master1]# kubectl exec -it demo-pod -c tomcat -- bash
root@demo-pod:/usr/local/tomcat# ls
root@demo-pod:/usr/local/tomcat# bin/shutdown.sh 

可以看到容器服务停止后被重启了一次,Pod又恢复正常

shell 复制代码
# 非正常停止容器里的tomcat服务
[root@master1]# kubectl exec -it demo-pod -c tomcat -- bash
root@demo-pod:/usr/local/tomcat# ps -ef | grep tomcat
root@demo-pod:/usr/local/tomcat# kill 1

容器被终止,再一次重启,重启次数加一

2.2测试Never重启策略

shell 复制代码
# 修改 pod.yaml,把 Always 改为 Never
[root@master1]# kubectl delete pods demo-pod 
pod "demo-pod" deleted
[root@master1]# kubectl apply -f pod.yaml 
pod/demo-pod created
[root@master1]# kubectl get pods -o wide -w
 
# 在另一个终端进入容器,正常停止服务
[root@master1]# kubectl exec -it demo-pod -c tomcat-pod-java -- bash
root@demo-pod:/usr/local/tomcat# bin/shutdown.sh 

查看Pod状态,发现正常停止tomcat服务,Pod正常运行,但是容器没有重启

shell 复制代码
# 非正常停止容器里的tomcat服务
[root@master1]# kubectl delete pods demo-pod 
pod "demo-pod" deleted
[root@master1]# kubectl apply -f pod.yaml 
pod/demo-pod created
[root@master1]# kubectl get pods -o wide -w
 
# 在另一终端进入容器内容
[root@master1]# kubectl exec -it demo-pod -c tomcat-pod-java -- bash
root@demo-pod:/usr/local/tomcat# kill 1

看到容器的状态时Pod的状态是Error,并且没有重启,说明重启策略是Never,那么Pod里容器服务无论如何终止,都不会重启

2.3测试OnFailure重启策略(生产环境中常用)

shell 复制代码
# 修改 pod.yaml 文件,把 Never 改为 OnFailure
[root@master1]# kubectl delete pods demo-pod 
pod "demo-pod" deleted
[root@-master1]# kubectl apply -f pod.yaml 
pod/demo-pod created
[root@master1]# kubectl get pods -o wide -w
 
# 在另一终端进入容器内部,正常停止服务
[root@master1]# kubectl exec -it demo-pod -c tomcat-pod-java -- bash
root@demo-pod:/usr/local/tomcat# bin/shutdown.sh

发现正常通知容器,退出码时0,容器不会重启

shell 复制代码
# 非正常停止容器里的tomcat服务
[root@master1]# kubectl delete pods demo-pod 
pod "demo-pod" deleted
[root@master1]# kubectl apply -f pod.yaml 
pod/demo-pod created
[root@master1]# kubectl get pods -o wide -w
 
# 在另一终端进入容器内部
[root@master1]# kubectl exec -it demo-pod -c tomcat-pod-java -- bash
root@demo-pod:/usr/local/tomcat# kill 1

看到非正常停止的pod里的容器,容器退出码不是0,容器会被重启。

相关推荐
妍妍的宝贝3 小时前
k8s 中的金丝雀发布(灰度发布)
云原生·容器·kubernetes
梆子井欢喜坨4 小时前
《Cloud Native Data Center Networking》(云原生数据中心网络设计)读书笔记 -- 12数据中心中的EVPN
网络·云原生
iangyu5 小时前
docker常用命令
运维·docker·容器
Dylanioucn5 小时前
【分布式微服务云原生】掌握 Redis Cluster架构解析、动态扩展原理以及哈希槽分片算法
算法·云原生·架构
飞酱不会电脑7 小时前
云计算第四阶段 CLOUD2周目 01-03
云原生·容器·kubernetes
程序那点事儿9 小时前
k8s 之安装busybox
云原生·容器·kubernetes
weixin_4539650010 小时前
master节点k8s部署]33.ceph分布式存储(四)
分布式·ceph·kubernetes
是芽芽哩!10 小时前
【Kubernetes】常见面试题汇总(五十八)
云原生·容器·kubernetes
福大大架构师每日一题21 小时前
22.1 k8s不同role级别的服务发现
容器·kubernetes·服务发现
莹雨潇潇21 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器