Bootstrap

K8s高级调度--CronJob与污点容忍及亲和力

CronJob

在 Kubernetes 中,CronJob 是用于周期性调度任务的资源,类似于 Linux 系统中的 cron。CronJob 通过定义一个特定的时间表自动创建和运行 Job,通常用于执行周期性的批处理任务,例如定期备份数据、发送报告或清理过期数据等。

CronJob 的核心概念

Job

CronJob 的核心是 Job,Job 是 Kubernetes 中的一种资源,用于在集群中运行一个或多个 Pod,并确保 Pod 成功完成。如果 Pod 失败,Job 会重新启动直到成功,或者达到失败重试的限制。

调度时间表

CronJob 使用 Cron 表达式来定义任务何时执行。Cron 表达式的格式为 minute hour day-of-month month day-of-week,

Cron表达式
  minute:       表示任务在每小时的第几分钟执行,范围 0-59。
  hour:         表示任务在一天中的第几小时执行,范围 0-23。
  day-of-month: 表示任务在一个月中的哪一天执行,范围 1-31。
  month:        表示任务在一年中的哪一个月执行,范围 1-12。
  day-of-week:  表示任务在一周中的哪一天执行,范围 0-6(0 表示星期日)。

并发策略

并发策略:
  Allow: 默认值,允许多个 CronJob 实例并行运行。
  Forbid: 禁止并发运行,如果前一个任务尚未完成,新的任务不会启动。
  Replace: 如果新的任务到达时旧任务还在运行,会终止旧任务并启动新任务。

启动历史保留

启动历史保留:
  successfulJobsHistoryLimit: 保留的成功任务的历史记录数,默认为 3。
  failedJobsHistoryLimit: 保留的失败任务的历史记录数,默认为 1

CronJob YAML 配置示例

以下是一个基本的 CronJob 配置示例,该 CronJob 每分钟运行一次,打印当前时间并显示 “Hello from the Kubernetes cluster!” 消息。

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello-cronjob
spec:
  schedule: "*/1 * * * *"  # 每分钟运行一次
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster!
          restartPolicy: OnFailure
  successfulJobsHistoryLimit: 3  # 成功任务历史保留 3 条
  failedJobsHistoryLimit: 1      # 失败任务历史保留 1 条

解释:
  schedule:*/1 * * * * 
    表示每分钟执行一次该 CronJob。Cron 表达式中每个字段的含义是:每 1 分钟执行一次。
  
  jobTemplate:
    定义了创建的 Job 模板。
  
  containers:
    定义了容器的配置,这里使用 busybox 镜像来执行任务。
  
  args:
    定义容器启动时运行的命令,即打印当前时间并显示一条消息。
  
  restartPolicy:
    指定 Pod 的重启策略为 OnFailure,即仅当任务失败时重新启动容器。
  
  successfulJobsHistoryLimit 和 failedJobsHistoryLimit:
    限制保留的成功和失败任务历史记录的数量。

Cron 表达式

* * * * *
| | | | |
| | | | +----- 一周中的星期几 (0 - 6) (0 代表星期天)
| | | +------- 一年中的月份 (1 - 12)
| | +--------- 一个月中的天 (1 - 31)
| +----------- 一天中的小时 (0 - 23)
+------------- 每小时的分钟 (0 - 59)

示例:
  "*/5 * * * *":    每 5 分钟运行一次。
  "0 0 * * *":      每天午夜(00:00)运行一次。
  "0 12 * * 1-5":   每周一至周五中午 12 点运行一次。

CronJob 实际应用场景

定期数据备份

定期数据备份 在生产环境中,定期备份数据库或应用数据是常见的需求。可以设置一个 CronJob,每天凌晨备份数据库,并将其存储在持久化存储或云存储上。

apiVersion: batch/v1
kind: CronJob
metadata:
  name: db-backup
spec:
  schedule: "0 0 * * *"  # 每天凌晨 0 点执行
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: postgres:13
            env:
            - name: PGHOST
              value: "database-service"
            - name: PGUSER
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: username
            - name: PGPASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: password
            args:
            - /bin/sh
            - -c
            - pg_dumpall -c -U $PGUSER > /backups/backup.sql
          restartPolicy: OnFailure
      volumes:
      - name: backup-storage
        persistentVolumeClaim:
          claimName: backup-pvc

这个例子展示了如何使用 PostgreSQL 镜像备份数据库,并将其保存到挂载的持久卷中。该任务每天凌晨运行一次。

日志清理任务

日志清理任务 定期清理旧日志文件或临时数据是另一种常见的需求。可以设置一个 CronJob 每周执行一次清理操作。

apiVersion: batch/v1
kind: CronJob
metadata:
  name: clean-logs
spec:
  schedule: "0 2 * * 0"  # 每周日凌晨 2 点执行
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cleaner
            image: busybox
            args:
            - /bin/sh
            - -c
            - rm -rf /var/log/*.log
          restartPolicy: OnFailure

Kubernetes 中的 CronJob 用于定期执行任务,类似于传统操作系统中的 cron。通过设置 CronJob,可以实现如数据备份、日志清理、报告生成等周期性任务。CronJob 的配置灵活,支持并发策略、启动期限、任务历史等配置项。使用 Cron 表达式可以精确定义任务的调度时间,满足生产环境中的多种定期任务需求。

污点和容忍

在 Kubernetes 中,污点(Taint) 和 容忍(Toleration) 是用于控制 Pod 调度的一种机制。通过给节点添加污点,可以避免不希望的 Pod 被调度到该节点上,除非这些 Pod 对应的容忍(Toleration)允许它们被调度到该节点。

污点的核心思想是:节点会“驱逐”掉不具备相应容忍的 Pod。这意味着 Kubernetes 可以防止某些节点上的 Pod 执行,除非它们显式允许容忍这些污点。

污点的概念

污点的概念
  1.Taint (污点):
      给节点添加污点,表示“不允许”某些 Pod 调度到该节点,除非 Pod 有相应的容忍。
      
      污点由键(key)、值(value) 和 效应(effect) 三部分组成:
        key=value:effect,其中 key 和 value 表示自定义的标识信息,effect 表示污点对 Pod 的影响。
  
  2.Toleration (容忍):
      Pod 通过设置容忍来允许自己被调度到带有污点的节点上。Pod 中的容忍允许其忽略节点的污点并继续调度到该节点。
      
      容忍使用与污点相同的键、值和效应,但它们的目的正好相反,表示 Pod 可以在含有该污点的节点上运行。

污点的三种效应

污点的三种效应
  1.NoSchedule:
      有这个污点的节点不允许调度不具备相应容忍的 Pod。
      意味着没有容忍的 Pod 不会被调度到这个节点上。

  2.PreferNoSchedule:
      Kubernetes 会尽量避免将没有容忍的 Pod 调度到该节点,但不是强制的。
      这是一种软约束,意味着 Kubernetes 会优先避免在该节点上调度不符合条件的 Pod。

  3.NoExecute:
      一旦污点被添加到节点上,所有没有相应容忍的 Pod 都会从该节点驱逐出去。
      这种效应会同时影响已经在节点上运行的 Pod 和即将调度的 Pod。

污点和容忍的工作流程

污点和容忍的工作流程
  1.管理员通过给节点设置污点,防止 Pod 被调度到不合适的节点上。
  2.开发者可以为 Pod 添加容忍,允许 Pod 被调度到带有特定污点的节点上。
  3.如果 Pod 没有容忍某节点的污点,那么它将不会被调度到该节点,或被驱逐出节点。

设置污点和容忍

1. 给节点添加污点

假设我们希望给一个名为 node1 的节点添加一个污点,防止普通 Pod 被调度到这个节点上。可以使用以下命令:

kubectl taint nodes node1 key1=value1:NoSchedule

这个命令为节点 node1 添加了一个污点 key1=value1:NoSchedule,没有相应容忍的 Pod 将无法被调度到这个节点上。

2. 给 Pod 添加容忍

要让某些 Pod 容忍这个污点,可以在 Pod 的 YAML 文件中添加 tolerations 字段,例如:

apiVersion: v1
kind: Pod
metadata:
  name: tolerant-pod
spec:
  containers:
  - name: nginx
    image: nginx
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoSchedule"

在这个例子中,Pod tolerant-pod 通过添加容忍,允许它被调度到带有 key1=value1:NoSchedule 污点的节点上。

实际应用中的场景

1.专用节点

如果有些节点专门用于运行某些特定的工作负载(如 GPU 计算),可以使用污点避免其他非 GPU 工作负载被调度到这些节点上。

kubectl taint nodes gpu-node gpu=true:NoSchedule

这个命令会给节点 gpu-node 添加一个污点,防止没有 GPU 容忍的 Pod 被调度到该节点。

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
  - name: gpu-container
    image: nvidia/cuda
  tolerations:
  - key: "gpu"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

这个 Pod gpu-pod 可以被调度到带有 gpu=true:NoSchedule 污点的节点上,因为它包含了相应的容忍。

2.隔离不稳定节点

当 Kubernetes 检测到某些节点出现问题时,可以给这些节点添加污点,使其不再调度新的 Pod,同时驱逐已经运行的 Pod。

kubectl taint nodes node1 node-problem=true:NoExecute

当节点 node1 被标记为有问题时,所有没有 NoExecute 容忍的 Pod 会被从该节点上驱逐。

3.临时节点维护

如果一个节点需要维护,管理员可以通过添加 NoSchedule 污点来避免新的 Pod 被调度到该节点,同时不影响已经在节点上运行的 Pod。

kubectl taint nodes node1 maintenance=true:NoSchedule

此时,没有 maintenance=true:NoSchedule 容忍的 Pod 将不会被调度到这个节点。

污点和容忍的管理

添加污点:

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

删除污点

要删除污点,可以在命令末尾加上 -,例如:

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

查看节点上的污点:

使用以下命令查看节点上的污点:

kubectl describe node <node-name>
总结
  污点(Taint) 是在节点上设置的限制,用于阻止不符合条件的 Pod 被调度到该节点。
  
  容忍(Toleration) 是在 Pod 上设置的配置,用于允许特定的 Pod 调度到带有污点的节点。
  
  污点和容忍主要用于隔离和调度策略的控制,帮助管理员将不同的工作负载分配到合适的节点上,或者隔离有问题的节点。

通过合理使用污点和容忍,Kubernetes 提供了强大的调度控制能力,可以确保特定 Pod 的调度规则,适合多种不同的场景和需求。

亲和力

在 Kubernetes 中,亲和力(Affinity) 是用于控制 Pod 如何在集群中的节点上分布的机制。它通过设置规则,定义哪些 Pod 更倾向于或必须被调度到特定节点上。亲和力机制可以帮助你优化应用的资源利用率、提高可靠性以及实现应用隔离。亲和力分为 节点亲和性(Node Affinity) 和 Pod 亲和性(Pod Affinity),相对应的还有 Pod 反亲和性(Pod Anti-Affinity)。

节点亲和性(Node Affinity)

节点亲和性 是基于节点的标签来定义 Pod 对节点的调度策略。它类似于 nodeSelector,但提供了更多的表达方式和灵活性,允许你指定"软"(preferred)或"硬"(required)规则。

节点亲和性(Node Affinity)
  1.硬性亲和性(requiredDuringSchedulingIgnoredDuringExecution)
      Pod 必须调度到满足特定条件的节点上,否则无法启动。
      
  2.软性亲和性(preferredDuringSchedulingIgnoredDuringExecution)
      Pod 更倾向于调度到满足条件的节点上,但如果没有可用节点,也不会阻止 Pod 的调度。

示例:节点亲和性
以下例子展示了一个 Pod 必须调度到带有 disktype=ssd 标签的节点上(硬性要求),并且更倾向于调度到带有 zone=us-west 标签的节点上(软性要求)。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: disktype
                operator: In
                values:
                  - ssd
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
              - key: zone
                operator: In
                values:
                  - us-west

在这个例子中:
  1.硬性亲和性要求 Pod 只能调度到标签 disktype=ssd 的节点上。
  2.软性亲和性表示,Pod 优先调度到标签 zone=us-west 的节点上,但不强制。

Pod 亲和性(Pod Affinity)

Pod 亲和性 用于指定某些 Pod 倾向于与特定的其他 Pod 一起运行。Pod 亲和性允许你将具有协作关系的 Pod 安排在同一个节点或节点组上,例如需要低延迟通信的应用。

示例:Pod 亲和性
下面的例子展示了一个 Pod 需要与带有标签 app=web 的 Pod 部署在同一个节点上。

apiVersion: v1
kind: Pod
metadata:
  name: backend
spec:
  containers:
    - name: backend
      image: nginx
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        labelSelector:
          matchExpressions:
            - key: app
              operator: In
              values:
                - web
        topologyKey: "kubernetes.io/hostname"

在这个例子中:
  该 Pod 需要与带有标签 app=web 的 Pod 在同一主机(由 kubernetes.io/hostname 定义的拓扑键)上运行,这是硬性要求。

Pod 反亲和性(Pod Anti-Affinity)

Pod 反亲和性 用于指定某些 Pod 不应与特定的其他 Pod 一起运行。Pod 反亲和性通常用于确保 Pod 分布在不同节点上,以避免单点故障(比如高可用性应用)或避免资源争用。

示例:Pod 反亲和性
以下例子展示了一个 Pod 不能与带有标签 app=frontend 的 Pod 部署在同一个节点上。

apiVersion: v1
kind: Pod
metadata:
  name: database
spec:
  containers:
    - name: database
      image: postgres
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        labelSelector:
          matchExpressions:
            - key: app
              operator: In
              values:
                - frontend
        topologyKey: "kubernetes.io/hostname"

在这个例子中:
  该Pod不能与带有标签 app=frontend 的 Pod 部署在同一个节点上,这是一个硬性要求。
  topologyKey: "kubernetes.io/hostname" 指定 Pod 必须分布在不同的节点上。

亲和力的使用场景

亲和力的使用场景
  1.高可用性:
      使用 Pod 反亲和性 可以确保相同类型的 Pod 分布在不同的节点上,以实现高可用性。
      比如,在多副本数据库部署中,避免多个副本调度到同一节点,以降低单点故障的风险。
  
  2.低延迟要求的应用:
      使用 Pod 亲和性 可以确保互相依赖的 Pod 部署在相同的节点或相近的拓扑上,减少网络延迟,
      例如微服务架构中的前端和后端服务。
  
  3.节点资源优化:
      使用节点亲和性 确保应用调度到具有特定硬件资源(如 GPU 或 SSD)的节点上,以满足性能要求。
      多租户隔离:通过 节点亲和性 和 Pod 反亲和性 可以确保不同租户的 Pod 部署在不同的节点上,实现资源隔离。

亲和力与调度策略的结合

亲和力可以与 Kubernetes 调度策略结合使用,进一步优化应用的调度。例如,结合 资源请求和限制 来确保应用不仅调度到特定节点,还能够合理分配资源。同时,配合 优先级和抢占 策略可以确保高优先级的 Pod 可以调度到最适合的节点上。

Kubernetes 的亲和力机制提供了灵活的方式来控制 Pod 的调度,帮助优化资源利用、提高可用性并满足应用的各种需求。通过配置 节点亲和性、Pod 亲和性 和 Pod 反亲和性,可以实现精确的调度控制。

;