k8s-高级调度学习

1 CronJob计划任务

​ 在 k8s 中周期性运行计划任务,与 linux 中的 crontab 相同。换句话说就是提前写好程序命令,然后当CronJob任务再启动后会按照其设置的时间,定期去执行程序命令。

(1)定期任务时间格式如下。

*    *    *    *    *
-    -    -    -    -
|    |    |    |    |
|    |    |    |    +----- 星期中星期几 (0 - 6) (星期天 为0)
|    |    |    +---------- 月份 (1 - 12) 
|    |    +--------------- 一个月中的第几天 (1 - 31)
|    +-------------------- 小时 (0 - 23)
+------------------------- 分钟 (0 - 59

每分钟定时执行一次	* * * * *
每小时定时执行一次	0 * * * *
每天定时执行一次	0 0 * * *
每周定时执行一次	0 0 * * 0
每月定时执行一次	0 0 1 * *
每月最后一天定时执行一次	0 0 L * *
每年定时执行一次	0 0 1 1 *

(2)CroJob配置如下。jobTemplate可以换为自己需要执行的命令,此处的jobTemplate为示例演示。

apiVersion: batch/v1
kind: CronJob # 类型为定时任务
metadata:
  name: cron-job-test  # 定时任务的名字
spec:
  concurrencyPolicy: Allow # 并发调度策略:Allow 允许并发调度,Forbid:不允许并发执行,Replace:如果之前的任务还没执行完,就直接执行新的,放弃上一个任务
  failedJobsHistoryLimit: 1 # 保留多少个失败的任务
  successfulJobsHistoryLimit: 3 # 保留多少个成功的任务
  suspend: false # 是否挂起任务,若为 true 则该任务不会执行
#  startingDeadlineSeconds: 30 # 间隔多长时间检测失败的任务并重新执行,时间不能小于 10
  schedule: "* * * * *" # 调度策略,此处为每分钟调度一次,由于successfulJobsHistoryLimit为3,所以调度3次

# 以下为编写的程序,在busybox的命令行中进行执行,输出当前日期,并打印Hello from the Kubernetes cluster
 jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: busybox
            image: busybox:1.28
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

(3)对以上cronJob配置进行测试。其命令如下,结果如下如图所示。

# 创建定时任务
kubectl create -f xxx.yaml
# 查看定时任务是否启动成功
kubectl get cj
# 然后在pod中查看,可以发现3次任务的执行记录
kubectl get po
# 利用日志记录,可以观察到每个任务的执行记录
kubectl logs -f xxxx(pod名称)

在这里插入图片描述

在这里插入图片描述

2 InitContainer初始化容器

​ 在真正的容器启动之前,先启动 InitContainer,在初始化容器中完成真实容器所需的初始化操作,完成后再启动真实的容器。就比如,在很多容器启动前都需要进行mysql的连接配置,此时就可以写一个 InitContainer,在每次启动容器前都先启动InitContainer,这时就不需要在每个容器启动后再进行配置,有点像中间件。

(1)其配置内容如下所示。在podspec下进行添加。

# 比如此处的initContainer就是在nginx容器中执行将inited...输出到init中
spec:
  initContainers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "echo 'inited...' >> ~/.init"]
    name: init-test

3 污点和容忍

污点:是标注在节点上的,当我们在一个节点上打上污点以后,k8s 会认为尽量不要将 pod 调度到该节点上,除非该 pod 上面表示可以容忍该污点,且一个节点可以打多个污点,此时则需要 pod 容忍所有污点才会被调度该节点。

容忍:是标注在pod 上的,当 pod 被调度时,如果没有配置容忍,则该 pod 不会被调度到有污点的节点上,只有该 pod 上标注了满足某个节点的所有污点,则会被调度到这些节点。

3.1 污点的基本操作

(1)污点的操作。

# 为节点打上污点
kubectl taint node (节点名称) key=value:NoSchedule

# 移除污点
kubectl taint node (节点名称) key=value:NoSchedule-

# 查看污点
kubectl describe no (节点名称)

(2)污点的影响。

NoSchedule

  • 如果不能容忍该污点,那么 Pod 就无法调度到该节点上。但是已经部署在该节点上的Pod不会被驱逐。

NoExecute

  • 如果 Pod 不能忍受这类污点,Pod 会马上被驱逐。
  • 如果 Pod 能够忍受这类污点,但是在容忍度定义中没有指定 tolerationSeconds, 则 Pod 还会一直在这个节点上运行。
  • 如果 Pod 能够忍受这类污点,而且指定了 tolerationSeconds, 则 Pod 还能在这个节点上继续运行这个指定的时间长度。

(3)污点的使用示例。

# 1 先查看master节点的污点,master节点在集群搭建时会自带污点
kubectl describe no k8s-master
# 2 再查看所有pod的信息,会发现由于master节点存在污点,所以pod都部署在node1和node2上
kubectl get po -o wide

在这里插入图片描述

在这里插入图片描述

# 3 将master节点的污点去掉,然后重启deploy容器。
kubectl taint node master node-role.kubernetes.io/master:NoSchedule-
# 4 再次查看master节点的污点,会发现已经为none了。
# 5 由于deploy容器,在被删除后会自动进行创建。
kubectl delete po nginx-deploy-58f9984477-l292j nginx-deploy-58f9984477-qwdbc
# 6 由于deploy的副本数只有2个,所以删除后,部署在master节点的几率不大,所以直接修改了nginx-deploy的配置文件,将其副本数添加到了4个。此时就有容器部署到了master节点上。

在这里插入图片描述

# 7 此时给master节点添加NoExecute污点,将部署到master的容器进行驱逐
kubectl taint node master key=value:NoExecute
# 8 通过下图可以观察到之前部署到master节点的容器,已经停止了并重启了一个到node1上

在这里插入图片描述

# 9 实验到此结束,将master节点的污点设置为原来初始的值
kubectl taint node master key=value:NoExecute-
kubectl taint node master node-role.kubernetes.io/master:NoSchedule

3.2 容忍的配置与使用

(1)首先给node2节点添加上NoSchedule污点。此时如果不配置容忍,则无法将容器部署到node2节点上。

kubectl taint node node2 memory=low:NoSchedule

(2)添加容忍,这里还是以nginx-deploy为例。加入后,容器就可以部署到node2上了。

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

(3)此时将node2节点的污点换成NoExecute,会发现node2进行了驱逐,所有部署的容器都部署到了node1。虽然之前给nginx-deploy配置了容忍,但是那个配置的是NoSchedule的。

# 先将NoSchedule污点删除
kubectl taint node node2 memory=low:NoSchedule-
# 添加NoExecute污点
kubectl taint node node2 memory=low:NoExecute

在这里插入图片描述

(4)此时修改nginx-deploy的容忍配置。并加入了tolerationSeconds属性,设置为120,表示该pod最多在node2上运行120s,120s结束后,就会重新启动。如果不加tolerationSeconds属性,则可以在node2上长期运行。如下图所示。

# pod 的 spec 下面配置容忍
tolerations:
- key: memory # 污点的 key
  value: low # 污点的 value
  offect: NoExecute # 污点产生的影响
  operator: Equal # 表是 value 与污点的 value 要相等,也可以设置为 Exists 表示存在 key 即可,此时可以不用配置 value
  tolerationSeconds: 120 属性,则该 pod 还能继续在该节点运行 120

在这里插入图片描述

4 亲和力和反亲和力

​ 亲和力就是将几个强相关的容器部署到指定的节点上。就比如说有两个服务,他们之间需要经常进行通信操作,那么就可以将这两个服务部署到同一个节点上。而相对的反亲和力就是将容器尽量部署到不同的节点上。比如有两个都比较重要的服务,那么尽量就不要将他们放在同一个节点上,避免当节点出现问题时,这两个重要的服务都挂掉了。

4.1 NodeAffinity-节点亲和力

节点亲和力(NodeAffinity):进行 pod 调度时,优先调度到符合条件的亲和力节点上。

(1)此处使用官方的一个配置模板进行演示。本文仍然使用nginx-deploy做演示,将以下配置文件加入到了nginx-deploy的配置中。

spec:
  affinity:
    nodeAffinity:
    # 硬亲和力,即支持必须部署在指定的节点上,也支持必须不部署在指定的节点上
      requiredDuringSchedulingIgnoredDuringExecution:	
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/os
            operator: In
            values:
            - linux
     # 软亲和力:尽量部署在满足条件的节点上,或尽量不要部署在被匹配的节点上       
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1	# 权重为1
        preference:
          matchExpressions:	
          - key: label-1 
            operator: In  # 匹配类型
            values:
            - key-1
      - weight: 50 	# 权重为50
        preference:
          matchExpressions:
          - key: label-2
            operator: In # 若把这里改为NotIn,则就是不匹配label-2=key2的节点
            values:
            - key-2

(2)给node1node2打上标签。进行测试,会发现在添加了亲和力配置后的nginx-deploy都部署到了node2上面,这是因为在node1,node2节点都部署了硬亲和力的情况下,标签为label-2=key-2node2节点有更高的权重。

 kubectl label no node1 label-1=key-1
 kubectl label no node2 label-2=key-2

在这里插入图片描述

(3)匹配类型。

  • In:部署在满足条件的节点上。
  • NotIn:匹配不在条件中的节点,实现节点反亲和性。
  • Exists:只要存在 key 名字就可以,不关心值是什么。
  • DoesNotExist:匹配指定 key 名不存在的节点,实现节点反亲和性。
  • Gt:value 为数值,且节点上的值小于指定的条件。
  • Lt:value 为数值,且节点上的值大于指定条件。

4.2 PodAffinity-pod亲和力

Pod 亲和力:将与指定 pod 亲和力相匹配的 pod 部署在同一节点。

Pod 反亲和力:根据策略尽量部署或不部署到一块。

(1)首先创建一个带有pod亲和力和反亲和力的yaml文件,其配置文件如下。该文件就是使该容器与具有security=S1pod亲和,与security=S2pod反亲和。

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity: # 亲和力
      requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和力
      - labelSelector:
          matchExpressions:
          - key: security # 节点中的pod需要有 security=S1的标签
            operator: In
            values:
            - S1
        topologyKey: topology.kubernetes.io/zone # 节点必须带有该标签
    podAntiAffinity: # 反亲和力
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security  # 节点中的pod需要有 security=S2的标签
              operator: In
              values:
              - S2
          topologyKey: topology.kubernetes.io/zone # 节点必须带有该标签
  containers:
  - name: with-pod-affinity
    image: registry.k8s.io/pause:2.0

(2)给node1node2分别打上需要的标签。然后再给node1节点中的任意一个pod打上security=S1标签。然后给node2中的pod打上security=S1标签。

kubectl label no node1 topology.kubernetes.io/zone=V
kubectl label no node1 topology.kubernetes.io/zone=R

在这里插入图片描述

(3)创建该容器,进行观察会发现该容器被挂载到node1节点。因为node1其中有亲和力标签的pod,而node2具有反亲和力的pod

在这里插入图片描述

(4)将node1节点的topology.kubernetes.io/zone标签进行删除。会发现由于node2节点具有反亲和力,而node1节点又缺少了标签,所以不会被分配到任意节点。

kubectl label no node1 topology.kubernetes.io/zone-

在这里插入图片描述

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐