跳过正文
  1. 所有文章/

选择合适的workload

·2809 字·6 分钟
目录

在 Kubernetes 中,DaemonSetJobCronJob 是三种用于管理非长期服务型工作负载的核心控制器。它们的设计目标和适用场景截然不同,选型的关键在于判断 Pod 是否需要常驻运行以及是否由定时或一次性任务驱动。

核心特性对比表
#

维度DaemonSetJobCronJob
设计目标确保每个节点都运行一个 Pod 副本执行一次性任务,完成后退出基于时间表执行周期性任务
Pod 数量与节点数强相关(通常每节点 1 个)用户指定(可并行)每次调度创建 1 个或多个 Job
生命周期长期运行(直到节点下线或手动删除)短时运行(任务完成即终止)定时触发(按 Cron 表达式循环)
调度策略节点亲和性(自动绑定到特定节点)一次性调度(支持并行/串行控制)时间驱动调度(Cron 表达式)
典型场景节点监控 Agent、日志收集(Filebeat)、网络插件(CNI)数据迁移、批处理计算、CI/CD 构建任务每日报表生成、定时数据备份、周期清理任务
关键字段spec.template(Pod 模板)spec.completions(完成次数)、spec.parallelism(并行度)spec.schedule(Cron 表达式)、spec.jobTemplate(Job 模板)
完成行为无完成状态,持续运行达到 completions 后 Job 状态转为 Complete依赖 Job 的状态,每次触发生成新 Job
适用节点通常部署在所有节点(含 Master)可调度到任意满足资源的节点可调度到任意满足资源的节点

选型决策指南
#

什么时候选 DaemonSet?
#

核心特征:你需要每个节点都运行一个完全相同的 Pod,且这个 Pod 需要常驻运行,通常用于节点级别的基础设施服务。

  • ✅ 适用场景
    • 日志收集:每个节点部署 Filebeat 或 Fluentd 采集本机日志。
    • 网络代理:部署 CNI 网络插件(如 Calico、Cilium 的节点组件)。
    • 节点监控:部署 Node Exporter 或监控 Agent。
  • ❌ 不适用场景
    • 不需要覆盖所有节点的服务(如普通的 Web 后端)。
    • 任务跑完就结束的一次性工作。

什么时候选 Job?
#

核心特征:你需要执行一个一次性的批处理任务,任务完成后 Pod 就应该退出,且不需要重复执行。

  • ✅ 适用场景
    • 数据处理:从数据库导出一份报表。
    • CI/CD 构建:运行一次单元测试或镜像构建。
    • 数据迁移:执行一次性的数据库 Schema 变更。
  • ❌ 不适用场景
    • 需要 7x24 小时运行的服务(应用 Deployment)。
    • 需要按固定周期重复执行的任务。

什么时候选 CronJob?
#

核心特征:你需要像 Linux Crontab 一样,按照时间计划重复执行某个任务。

  • ✅ 适用场景
    • 定时任务:每天凌晨 2 点清理临时文件。
    • 周期报表:每小时生成一次业务指标汇总。
    • 定时备份:每周日凌晨 1 点备份数据库。
  • ❌ 不适用场景
    • 需要立即执行且仅执行一次的任务(用 Job)。
    • 需要常驻守护进程。

YAML 关键配置差异
#

为了更直观地理解三者的区别,可以观察它们 YAML 定义中的核心 spec 字段:

DaemonSet (关注节点部署)

apiVersion: apps/v1
kind: DaemonSet
spec:
  selector:
    matchLabels:
      name: node-log-agent
  template:
    spec:
      containers:
      - name: agent
        image: filebeat:latest
      # 通常无需配置 restartPolicy,默认为 Always

Job (关注任务完成)

apiVersion: batch/v1
kind: Job
spec:
  completions: 1    # 需要成功完成的 Pod 数量
  parallelism: 1    # 同时运行的 Pod 数量
  template:
    spec:
      containers:
      - name: task
        image: busybox
        command: ["echo", "hello job"]
      restartPolicy: Never  # Job 通常设为 Never 或 OnFailure

CronJob (关注时间调度)

apiVersion: batch/v1
kind: CronJob
spec:
  schedule: "*/5 * * * *"  # 每 5 分钟执行一次
  jobTemplate:              # 内嵌 Job 模板
    spec:
      template:
        spec:
          containers:
          - name: cron-task
            image: busybox
            command: ["echo", "hello cron"]
          restartPolicy: OnFailure

如果你的wordl不属于上述任何一种(例如需要运行一个可伸缩的 Web 服务),那么你应该选择 DeploymentStatefulSet

有了deployment为什么还要有daemonset?
#

Deployment 和 DaemonSet 在 Kubernetes 中解决的是完全不同维度的部署需求。简单来说,Deployment 关心的是“跑几个副本”,而 DaemonSet 关心的是“在哪些节点上跑”

核心定位的根本差异
#

维度Deployment(通用部署)DaemonSet(守护进程集)
调度逻辑副本数驱动:只关心集群中是否有足够数量的 Pod 在运行,不关心具体在哪台节点。节点标签驱动:确保每个符合条件的节点上都运行且仅运行一个 Pod 副本。
典型场景无状态应用(如 Web 服务、API 后端)节点级基础设施(如日志收集、网络插件、监控代理)
扩缩容通过 replicas 字段自由调整副本数自动随集群节点数量增减而增减(每节点一个)

为什么有了 Deployment 还要 DaemonSet?
#

因为有些服务必须在每个节点上部署,这是 Deployment 无法保证的。

1. 节点级基础设施的“刚性需求”

  • 日志收集 Agent(如 Fluentd、Filebeat):你需要每个节点上的日志都能被采集,如果某个节点没有部署,该节点的日志就会丢失。DaemonSet 能确保新节点加入时,Agent 自动部署。
  • 网络插件(如 Calico、Flannel):每个节点都需要网络组件来管理 Pod 网络,缺一个节点整个集群网络就可能不通。
  • 监控代理(如 Node Exporter):必须从每个节点采集硬件指标。

2. 节点亲和性的极致要求

  • DaemonSet 的调度逻辑是“节点级”的,它与节点是强绑定的。而 Deployment 的 Pod 可以被调度到任意节点,即使使用 nodeSelector,也无法严格保证“每节点一个”。

场景对比:日志收集 Agent 的部署
#

假设你要部署一个日志收集服务:

  • ❌ 使用 Deployment 的问题: 你设置 replicas: 3,但集群有 5 个节点。结果只有 3 个节点有 Agent,另外 2 个节点的日志无人收集。如果你手动设置 replicas: 5,当集群扩容到 10 个节点时,你又需要手动改为 10,且无法保证 Pod 均匀分布在所有节点上(可能出现一个节点跑多个 Agent,另一个节点没有)。

  • ✅ 使用 DaemonSet 的优势: 你只需定义一个 DaemonSet。它会自动在当前所有节点上各部署一个 Pod。当集群新增节点时,Kubernetes 会自动在新节点上创建 Pod,无需人工干预。

如何选择?
#

你的需求选用对象
运行无状态应用(如 Web Server)Deployment
需要水平扩缩容(HPA)Deployment
每个节点都必须运行的服务(如网络、存储、监控)DaemonSet
服务与节点硬件/内核强相关(如 GPU 驱动)DaemonSet

daemonset是如何保证每一个节点上都有pod?
#

最关键的是根据你定义的 nodeSelectortolerations,筛选出目标节点集合

DaemonSet 的运作逻辑可以拆解为三个关键步骤:

  1. 监听(Watch):DaemonSet Controller 实时监听集群中 节点(Node) 的变化(新增、删除、标签变更),同时也监听 Pod 的状态。
  2. 匹配(Match):根据你定义的 nodeSelectortolerations,筛选出目标节点集合
  3. 调谐(Reconcile):对比“目标节点”和“现有 Pod 所在节点”,执行差异修正
    • 节点多了 Pod -> 删除多余的 Pod(确保一个节点只有一个)。
    • 节点少了 Pod -> 立即创建 Pod。
    • Pod 挂了 -> 原地重启(类似 restartPolicy: Always)。

关键配置:如何控制“每一个”?
#

DaemonSet 的“全覆盖”行为可以通过以下配置精确控制:

  1. nodeSelector:不是所有节点都跑,只有带特定标签的节点才跑。
    spec:
      template:
        spec:
          nodeSelector:
            disktype: ssd # 只在有 disktype=ssd 标签的节点上运行
    
  2. Tolerations(污点容忍):为了在 Master 节点或特殊节点上运行(如网络插件)。
    tolerations:
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
    
  3. 滚动更新策略:虽然每节点一个,但更新时默认是 RollingUpdate,会逐个节点更新 Pod,避免全量宕机。

DaemonSet Controller 会自动将一组容忍度添加到 DaemonSet Pod 上,确保 Pod 可以在所有节点上运行。具体添加了哪些容忍度,可以参考官方文档:Taints and tolerations