03(中)| K8s控制器:DaemonSet+Job+CronJob 逐行解析与生产落地 目录5.1 DaemonSet 功能生活类比5.2 DaemonSet 示例原文件完整命令与代码核心代码逐行解析Line-by-Line Breakdown最容易踩的坑Gotchas企业级生产应用Enterprise Scenario千万级并发场景下的典型用途进阶优化空间课后防宕机指南Troubleshooting六 Job 控制器6.1 Job 控制器功能生活类比6.2 Job 控制器示例原文件完整命令与代码核心代码逐行解析Line-by-Line Breakdown最容易踩的坑Gotchas企业级生产应用Enterprise Scenario千万级并发场景下的典型用途进阶优化空间课后防宕机指南Troubleshooting七 CronJob 控制器7.1 CronJob 控制器功能生活类比7.2 CronJob 控制器 示例原文件完整命令与代码核心代码逐行解析Line-by-Line Breakdown最容易踩的坑Gotchas企业级生产应用Enterprise Scenario千万级并发场景下的典型用途进阶优化空间课后防宕机指南Troubleshooting5.1 DaemonSet 功能生活类比DaemonSet 就像每个小区单元楼必须配备的消防栓每一栋单元楼K8s 节点都必须有且仅有一个消防栓Pod 副本新建单元楼新节点加入集群时物业会自动安装消防栓单元楼拆除节点离开集群时消防栓也会同步拆除如果物业撤掉这个小区的消防栓配置删除 DaemonSet所有单元楼的消防栓都会被移除。【图片位置 1DaemonSet 节点分布示意图】示意图内容3 个节点 k8s-node1、k8s-node2、k8s-node3 横向排列每个节点下方对应 1 个 Pod每个 Pod 内部包含 3 层 container原文档笔误修正contaj/contai → container直观体现 雨露均沾每个人跑一个 的核心特性。DaemonSet 确保全部 (或者某些) 节点上运行一个 Pod 的副本。当有节点加入集群时也会为他们新增一个 Pod当有节点从集群移除时这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。DaemonSet 的典型用法:在每个节点上运行集群存储 DaemonSet例如 glusterd、ceph。在每个节点上运行日志收集 DaemonSet例如 fluentd、logstash。在每个节点上运行监控 DaemonSet例如 Prometheus Node Exporter、zabbix agent 等。一个简单的用法是在所有的节点上都启动一个 DaemonSet将被作为每种类型的 daemon 使用。一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet但具有不同的标志并且对不同硬件类型具有不同的内存、CPU 要求。5.2 DaemonSet 示例原文件完整命令与代码[rootk8s2 pod]# cat daemonset-example.ymlyamlapiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-example spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: tolerations: #对于污点节点的容忍 - effect: NoSchedule operator: Exists containers: - name: nginx image: nginx[rootk8s-master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-87h6s 1/1 Running 0 47s 10.244.0.8 k8s-master none none daemonset-n4vs4 1/1 Running 0 47s 10.244.2.38 k8s-node2 none none daemonset-vhxmq 1/1 Running 0 47s 10.244.1.40 k8s-node1 none none #回收 [rootk8s2 pod]# kubectl delete -f daemonset-example.yml核心代码逐行解析Line-by-Line Breakdown表格代码行底层触发动作apiVersion: apps/v1向 kube-apiserver 声明使用apps/v1API 组apiserver 将请求路由到 DaemonSet 控制器的 v1 版本处理逻辑废弃的 extensions/v1beta1 版本已在 K8s 1.16 移除kind: DaemonSet告诉 apiserver 当前创建的资源类型是 DaemonSet触发 DaemonSet 控制器的监听循环metadata: name: daemonset-example在 etcd 中创建一个 key 为/apis/apps/v1/namespaces/default/daemonsets/daemonset-example的资源对象spec: selector: matchLabels: app: nginxDaemonSet 控制器会持续筛选集群中所有标签为appnginx的 Pod作为自己的管控对象这是 DaemonSet 的核心关联逻辑template: metadata: labels: app: nginx定义 Pod 模板的标签必须与 selector.matchLabels 完全一致否则控制器无法关联 Pod创建失败tolerations: - effect: NoSchedule operator: Exists向 kube-scheduler 注册容忍规则允许该 Pod 被调度到带有任意 NoSchedule 类型污点的节点上原示例中用于让 Pod 能调度到 master 节点默认 master 有 node-role.kubernetes.io/master:NoSchedule 污点containers: - name: nginx image: nginx定义 Pod 内运行的容器kubelet 会拉取 nginx 镜像并启动容器容器名称在 Pod 内唯一最容易踩的坑Gotchasselector 与 template 标签不匹配这是 90% 新手会犯的错误。如果两者标签不一致kubectl apply不会报错但 DaemonSet 不会创建任何 Pod且没有明显错误提示。tolerations 格式错误原示例中tolerations是数组类型必须加-前缀如果漏写-会被解析为对象导致 master 节点永远不会调度该 Pod。忘记设置资源限制DaemonSet 的 Pod 会运行在所有节点上如果没有设置resources.limits单个 Pod 可能耗尽节点资源导致整个集群雪崩。企业级生产应用Enterprise Scenario千万级并发场景下的典型用途全节点日志采集在所有节点上部署 Fluentd DaemonSet采集容器和宿主机日志统一发送到 Elasticsearch 集群。千万级并发下每个节点每秒产生 GB 级日志DaemonSet 的本地采集模式避免了网络带宽瓶颈。节点监控部署 Prometheus Node Exporter DaemonSet采集节点 CPU、内存、磁盘、网络等指标是 K8s 集群监控的基础组件。分布式存储客户端部署 Ceph RBD DaemonSet为所有节点提供块存储客户端支持实现 Pod 的持久化存储。进阶优化空间节点亲和性 污点容忍精细化调度只在 GPU 节点上部署 GPU 监控 DaemonSet避免资源浪费。滚动更新策略配置设置updateStrategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1确保更新时每个节点最多只有一个 Pod 不可用避免监控 / 日志采集中断。资源 QoS 保障为 DaemonSet Pod 设置Guaranteed级别的 QoSrequestslimits确保在节点资源紧张时DaemonSet Pod 不会被 kubelet 驱逐。本地缓存优化日志采集 DaemonSet 使用本地磁盘缓存避免网络抖动导致日志丢失。课后防宕机指南Troubleshooting问题现象DaemonSet 创建成功但 master 节点没有运行 Pod报错信息kubectl describe daemonset daemonset-example会显示0 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didnt tolerate排查思路检查tolerations配置是否正确是否包含对 master 节点污点的容忍确认 master 节点是否被标记为不可调度。问题现象DaemonSet 创建后部分节点的 Pod 一直处于 Pending 状态报错信息kubectl describe pod pod-name会显示Insufficient cpu/memory排查思路检查节点剩余资源是否满足 Pod 的 requests 要求检查是否有其他 Pod 占用了大量节点资源调整 DaemonSet 的资源限制。六 Job 控制器6.1 Job 控制器功能生活类比Job 就像快递分拣中心的一次性分拣任务今天有 10000 个包裹需要分拣指定任务数安排 2 条分拣线同时工作并行数每条分拣线处理完一批包裹就结束Pod 运行一次就退出当 10000 个包裹全部分拣完成成功 Pod 数达到指定值整个任务就结束分拣线全部关停。【图片位置 2Job 控制器运行示意图】原文档示意图内容第一行 3 个 Pod 横向排列每个 Pod 内部包含 3 层 container原文档笔误修正contaj/containg → container下方标注 JOB END 表示任务完成第二行再启动 3 个 Pod继续完成剩余任务直到所有任务结束。在企业里做一次性的任务Job主要用于负责批量处理 (一次要处理指定数量任务) 短暂的一次性 (每个任务仅运行一次就结束) 任务。Job 特点如下:当 Job 创建的 pod 执行成功结束时Job 将记录成功结束的 pod 数量。当成功结束的 pod 达到指定的数量时Job 将完成执行。6.2 Job 控制器示例原文件完整命令与代码[rootk8s2 pod]# vim job.ymlyamlapiVersion: batch/v1 kind: Job metadata: name: pi spec: completions: 6 # 一共完成任务数为6 parallelism: 2 # 每次并行完成2个 template: spec: containers: - name: pi image: perl:5.34.0 command: [perl, -Mbignumbpi, -wle, print bpi(2000)] # 计算Π的后2000位 restartPolicy: Never # 关闭后不自动重启 backoffLimit: 4 # 运行失败后尝试4重新运行[rootk8s2 pod]# kubectl apply -f job.yml[!NOTE]关于重启策略设置的说明:如果指定为 OnFailure则 job 会在 pod 出现故障时重启容器而不是创建 podfailed 次数不变。如果指定为 Never则 job 会在 pod 出现故障时创建新的 pod并且故障 pod 不会消失也不会重启failed 次数加 1。如果指定为 Always 的话就意味着一直重启。核心代码逐行解析Line-by-Line Breakdown表格代码行底层触发动作apiVersion: batch/v1声明使用batch/v1API 组apiserver 将请求路由到 Job 控制器处理K8s 1.21 废弃了 batch/v1beta1 版本kind: Job触发 Job 控制器的监听循环在 etcd 中创建 Job 资源对象spec: completions: 6Job 控制器会持续统计成功结束的 Pod 数量当数量达到 6 时将 Job 状态标记为Completed并停止创建新的 Podspec: parallelism: 2限制 Job 同时运行的 Pod 数量最多为 2控制器会根据当前成功 Pod 数和并行数动态创建新的 Podcommand: [perl, ... print bpi(2000)]覆盖容器默认的 ENTRYPOINT容器启动后直接执行该命令命令执行完成后容器退出退出码为 0 表示成功restartPolicy: Never告诉 kubelet如果容器退出码不为 0失败不要重启容器Job 控制器会检测到 Pod 失败创建一个新的 Pod 重试backoffLimit: 4限制 Job 的最大重试次数为 4 次如果失败次数达到 4 次Job 状态会被标记为Failed并停止重试最容易踩的坑GotchasrestartPolicy 设置错误如果设置为AlwaysPod 会无限重启Job 永远不会完成这是 Job 最常见的致命错误。completions 与 parallelism 顺序写反很多新手会把completions总任务数和parallelism并行数写反导致任务要么运行过慢要么创建过多 Pod 耗尽集群资源。backoffLimit 理解错误backoffLimit是总重试次数不是每个 Pod 的重试次数如果设置为 0任务失败一次就会直接标记为 Failed。企业级生产应用Enterprise Scenario千万级并发场景下的典型用途离线数据处理每天凌晨批量处理前一天的用户行为数据生成报表。千万级用户下每天产生 TB 级数据使用 Job 并行处理可以将处理时间从小时级缩短到分钟级。数据库迁移一次性迁移千万级数据从旧库到新库使用多个 Job 并行处理不同分片的数据提高迁移效率。批量任务执行发送千万级营销短信、生成用户账单、清理过期数据等一次性批量任务。进阶优化空间分片处理将大任务拆分为多个小分片每个 Pod 处理一个分片避免单个 Pod 处理时间过长导致失败重试成本过高。失败重试指数退避设置backoffLimit和activeDeadlineSeconds避免失败任务无限重试占用资源使用指数退避算法减少重试频率。资源动态调整使用 K8s 的 Vertical Pod AutoscalerVPA自动调整 Job Pod 的资源请求提高资源利用率。任务队列集成将 Job 与 RabbitMQ/Kafka 集成实现任务的动态分发和负载均衡支持百万级任务的并发处理。课后防宕机指南Troubleshooting问题现象Job 一直处于 Running 状态永远不会完成报错信息kubectl describe job pi会显示Pods Statuses: 2 Running / 0 Succeeded / 0 Failed且持续很长时间排查思路检查 Pod 的restartPolicy是否设置为Always检查容器内的命令是否会无限循环查看 Pod 日志确认命令是否正常执行。问题现象Job 快速失败状态变为 Failed报错信息kubectl describe job pi会显示BackoffLimitExceeded: Job has reached the specified backoff limit排查思路查看失败 Pod 的日志确认命令执行失败的原因检查镜像是否存在、是否有权限拉取调整backoffLimit增加重试次数。七 CronJob 控制器7.1 CronJob 控制器功能生活类比CronJob 就像小区的垃圾清运车每天早上 6 点和晚上 8 点固定时间准时到达小区触发 Job每次到达后完成一次垃圾清运任务运行 Job 创建 Pod 处理任务清运完成后离开Job 完成Pod 销毁如果某次清运车坏了Job 失败会根据配置决定是否重新清运。【图片位置 3CronJob 控制器调度示意图】原文档示意图内容CronJob 在顶部下方周期性生成多个 Job每个 Job 对应 3 个 Pod每个 Pod 内部包含 3 层 container原文档笔误修正conta/contaj → containerJob 完成后标注 JOB END体现周期性调度的特点。定期在集群中运行指定的动作。Cron Job 创建基于时间调度的 Jobs。CronJob 控制器以 Job 控制器资源为其管控对象并借助它管理 pod 资源对象。CronJob 可以以类似于 Linux 操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。CronJob 可以在特定的时间点 (反复的) 去运行 job 任务。7.2 CronJob 控制器 示例原文件完整命令与代码[rootk8s2 pod]# vim cronjob.ymlyamlapiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: * * * * * jobTemplate: spec: template: spec: containers: - name: hello image: busybox imagePullPolicy: IfNotPresent command: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster restartPolicy: OnFailure[rootk8s2 pod]# kubectl apply -f cronjob.yml核心代码逐行解析Line-by-Line Breakdown表格代码行底层触发动作apiVersion: batch/v1声明使用batch/v1API 组apiserver 将请求路由到 CronJob 控制器处理K8s 1.21 废弃了 batch/v1beta1 版本kind: CronJob触发 CronJob 控制器的监听循环在 etcd 中创建 CronJob 资源对象spec: schedule: * * * * *CronJob 控制器会每分钟解析一次该 Cron 表达式当时间匹配时创建一个新的 Job 资源Cron 表达式格式与 Linux crontab 完全一致分 时 日 月 周jobTemplate:定义 CronJob 创建 Job 时使用的模板所有 Job 的配置都继承自该模板imagePullPolicy: IfNotPresent告诉 kubelet如果本地已经存在 busybox 镜像就不要从镜像仓库拉取只有本地不存在时才拉取节省网络带宽command: [/bin/sh, -c, ...]容器启动后执行 shell 命令打印当前时间和欢迎信息命令执行完成后容器退出restartPolicy: OnFailure告诉 kubelet如果容器执行失败退出码不为 0重启容器只有当容器执行成功退出码为 0时才标记 Pod 为成功最容易踩的坑GotchasCron 表达式时区问题CronJob 默认使用 UTC 时区而不是集群节点的本地时区如果需要使用北京时间必须在 CronJob 中设置timeZone: Asia/ShanghaiK8s 1.24 支持。并发策略设置错误默认并发策略是Allow即允许同时运行多个 Job如果任务不能并发执行必须设置concurrencyPolicy: Forbid否则会导致数据不一致。历史任务保留过多默认 CronJob 会保留 3 个成功的 Job 和 1 个失败的 Job如果不设置successfulJobsHistoryLimit和failedJobsHistoryLimit会导致 etcd 中积累大量历史 Job影响集群性能。企业级生产应用Enterprise Scenario千万级并发场景下的典型用途定时数据备份每天凌晨 2 点自动备份数据库和分布式存储数据确保数据安全。定时报表生成每天、每周、每月自动生成业务报表发送给相关人员。定时资源清理每天凌晨清理过期的日志、临时文件、无用的 Pod 和镜像释放集群资源。定时任务调度定时触发 CI/CD 流水线、定时发送通知、定时更新配置等。进阶优化空间时区统一配置所有 CronJob 统一使用timeZone: Asia/Shanghai避免时区混乱导致任务执行时间错误。并发策略与超时控制设置concurrencyPolicy: Forbid和activeDeadlineSeconds避免任务重叠和长时间运行。历史任务清理设置successfulJobsHistoryLimit: 1和failedJobsHistoryLimit: 1只保留最近一次的成功和失败任务减少 etcd 压力。监控与告警为 CronJob 添加 Prometheus 监控当任务失败或执行时间过长时发送告警通知。高可用调度使用多个 CronJob 控制器实例避免单点故障使用分布式锁确保任务只执行一次。课后防宕机指南Troubleshooting问题现象CronJob 到了指定时间没有创建 Job报错信息kubectl describe cronjob hello没有显示任何新创建的 Job排查思路检查 Cron 表达式是否正确检查 CronJob 控制器是否正常运行确认集群时间是否正确如果是 K8s 1.24 以下版本检查是否设置了正确的时区。问题现象CronJob 同时创建了多个 Job导致数据重复处理报错信息kubectl get jobs会显示多个同一时间创建的 hello-xxx Job排查思路检查concurrencyPolicy是否设置为Allow检查上一个 Job 是否还在运行设置concurrencyPolicy: Forbid禁止并发执行。