Kubernetes中ReplicaSets、Deployment、DaeonSet、Job、CronJob详解
内容汇总:
-
ReplicaSets
-
Deployment
-
DaemonSet
-
Job
-
CronJob
Kubernetes Controllers
学习参考:控制器
环境准备
root@master30:~# kubectl create ns controllers root@master30:~# kubectl config set-context --current --namespace controllers
Controllers 介绍
Controller 主要作用是确保所管理的资源处于用户期望的状态,通过不断地监控资源的状态,并根据实际状态与期望状态之间的差异执行相应的动作,来实现资源的自愈、自动扩展等功能。
先简单回顾一下:容器按照是否持续运行可分为两类。
-
服务类容器: 一直运行任务,通常持续提供服务, 比如HTTP等。
-
工作类容器:一次性任务, 比如批处理程序,完成后容器就退出。
Kubernetes 中用于管理服务类容器的控制器有 ReplicaSet 、Deployment 和 DaemonSet 等。
Kubernetes 中用于管理工作类容器的控制器有 Job 和 CronJob。
Kubernetes Controller 控制器 专属易懂笔记
一、控制器核心作用(一句话吃透)
控制器就像是 K8s 的自动管理员。
它会一直监控集群里的资源,不断对比:我现在的状态(实际状态) vs 我想要的状态(期望状态)。
如果两者不一样,它就会自动干活,帮我们修复、创建、删除容器,实现自动自愈、自动维护,不用人工干预。
核心逻辑:有错就改,永远维持用户想要的状态
二、容器的两大类(按运行方式区分)
1. 服务类容器(一直跑)
启动后永久持续运行,专门对外提供服务,不会主动退出。
例子:网页服务、后端微服务、Nginx、数据库。
2. 工作类容器(跑完就退)
只做一次性/定时任务,任务执行完成后,容器就正常退出,不需要一直挂着。
例子:数据备份、日志清理、批量数据计算。
三、对应控制器分类(重点考点)
1. 管理【服务类容器】的控制器(常驻服务用)
专门用来管理需要 一直运行 的程序:
-
ReplicaSet:基础控制器,只负责保证固定数量的 Pod 正常运行
-
Deployment:最常用!管理普通微服务,支持更新、回滚、自愈
-
DaemonSet:保证集群每台节点上,都自动跑一个 Pod(多用于监控、日志采集)
2. 管理【工作类容器】的控制器(任务类用)
专门管理 一次性/定时任务:
-
Job:执行一次性任务,跑完就结束,失败会自动重试
-
CronJob:定时任务(比如每天凌晨备份数据),按时间自动创建 Job 执行
四、极简背诵总结(考试/面试直接用)
-
控制器作用:持续监控资源状态,自动修正差异,保证集群始终处于用户期望的状态,实现自动化运维。
-
常驻服务控制器:ReplicaSet、Deployment、DaemonSet
-
任务类控制器:Job、CronJob
ReplicaSets
学习参考:ReplicaSets。
一、ReplicaSet(RS)是什么?
ReplicaSet 简称 RS(副本控制器),是 K8s 的基础控制器。
核心作用:保证集群里永远有「指定数量、一模一样」的 Pod 在正常运行。
简单理解:RS 就是一个守数量的管理员,只负责维持 Pod 副本数量稳定。
二、RS 和 Deployment 的关系(重点)
我们几乎不会单独使用 RS。
日常用的 Deployment(部署控制器),底层就是靠 ReplicaSet 来实现 Pod 的创建、删除、更新管理。Deployment 是上层工具,RS 是底层执行者。
三、ReplicaSet 三大核心字段(工作必备三要素)
RS 能正常工作,只靠这三个配置:
-
Pod 选择算符 用来识别、绑定自己管理的一批 Pod,知道哪些 Pod 归自己管。
-
副本数量(replicas) 告诉 K8s 需要维持多少个正常运行的 Pod(期望数量)。
-
Pod 模板 新建 Pod 的模板,定义 Pod 的镜像、配置、端口等,缺 Pod 时就按这个模板创建新 Pod。
四、ReplicaSet 工作原理(核心逻辑:补差、去多)
RS 会一直循环检查当前 Pod 实际数量,和设定的期望数量做对比,自动修复:
1. 实际 Pod 数量 > 设置数量
RS 会自动删掉多余的 Pod,保证数量不超标。
2. 实际 Pod 数量 < 设置数量
RS 会按照模板自动新建 Pod,补齐缺失数量。
举例场景:节点内核升级、节点宕机导致 Pod 消失,RS 会在其他正常节点重新创建 Pod,保证服务数量稳定。
五、极简背诵总结(考试/作业直接抄)
-
ReplicaSet(RS)用于维持指定数量的相同 Pod 稳定运行,保障服务可用性。
-
RS 一般被 Deployment 底层调用,不单独使用。
-
通过选择器、副本数、Pod 模板三大配置,实现「多删少补」,自动维持 Pod 副本数量恒定。
ReplicaSet 使用
ReplicaSet 创建
[root@master30 ~ 11:55:51]# vim rs.yaml
apiVersion: apps/v1 # RS 固定API版本
kind: ReplicaSet # 资源类型:副本控制器RS
metadata:
name: nginx # RS控制器名称
spec:
replicas: 3 # 期望Pod副本总数3个(核心参数)
selector: # 标签选择器:用来识别自己管理的Pod
matchLabels:
app: nginx # 匹配标签 app=nginx
template: # Pod模板:缺Pod时按这个模板新建Pod
metadata:
name: nginx
labels:
app: nginx # Pod自带标签,必须和selector匹配
spec:
containers:
- name: nginx
image: hub.laoma.cloud/library/nginx:latest # 使用私有镜像
imagePullPolicy: IfNotPresent # 本地有镜像就不拉取
ports:
- containerPort: 80 # 容器暴露80端口
# 1. 应用yaml,创建ReplicaSet [root@master30 ~ 13:44:44]# kubectl apply -f rs.yaml replicaset.apps/nginx created # 2. 查看ReplicaSet状态 [root@master30 ~ 13:46:01]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx 3 3 3 6s # 字段说明: # DESIRED:期望Pod数量3 # CURRENT:当前运行Pod数量3 # READY:就绪可用Pod数量3 # 3. 查看自动创建的Pod # Pod命名规则:RS名称 + 随机字符串,例如 nginx-c9ggp [root@master30 ~ 13:46:07]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-c9ggp 1/1 Running 0 43s nginx-lfz4z 1/1 Running 0 43s nginx-pq9dv 1/1 Running 0 43s # 4. 查看Pod归属哪个控制器 [root@master30 ~ 13:46:44]# kubectl describe pod nginx-c9ggp | grep Controlled Controlled By: ReplicaSet/nginx [root@master30 ~ 13:48:02]# kubectl describe pod nginx-lfz4z | grep Controlled Controlled By: ReplicaSet/nginx [root@master30 ~ 13:48:52]# kubectl describe pod nginx-pq9dv | grep Controlled Controlled By: ReplicaSet/nginx # 输出 Controlled By: ReplicaSet/nginx # 底层原理:Pod内部 ownerReferences 字段记录父控制器,建立父子绑定关系
ReplicaSet 健壮性测试
测试1:删除单个副本
[root@master30 ~ 13:51:14]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx 3 3 3 5m19s [root@master30 ~ 13:53:02]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-c9ggp 1/1 Running 0 7m4s nginx-lfz4z 1/1 Running 0 7m4s nginx-pq9dv 1/1 Running 0 7m4s # 删除一个pod [root@master30 ~ 13:53:05]# kubectl delete pod nginx-c9ggp --force Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely. pod "nginx-c9ggp" force deleted #现象:被删除的 Pod 消失,立刻生成全新名称的 Pod,集群 Pod 总数依然维持 3 个。 #RS 持续循环对比「期望副本数」和「实际运行 Pod 数」,检测到数量不足,会根据template模板新建 Pod,实现自动自愈。 [root@master30 ~ 13:53:56]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-lfz4z 1/1 Running 0 7m57s nginx-pq9dv 1/1 Running 0 7m57s nginx-rdgsp 1/1 Running 0 2s
1.Pod 的 metadata.ownerReferences 字段,显示所属主资源。 正是通过这一连接,ReplicaSet 知道它所维护的 Pod 集合的状态, 并据此计划其操作行为。
通俗比喻
ownerReferences 就是每个 Pod 的户口本监护人信息。
只要是 ReplicaSet(RS)自动创建出来的 Pod,K8s 会自动在这个字段里写上:父控制器是哪个 RS、RS 的唯一 ID,把 RS 和 Pod 绑定成「父子关系」。
这个绑定有 3 个核心作用
1.区分 “自家 Pod”
RS 遍历集群所有 Pod 时,靠这个字段筛选出「自己创建、归自己管」的 Pod,统计当前运行副本数量;
2.实现级联删除
执行 kubectl delete rs nginx 时,K8s 识别到所有 Pod 的监护人是这个 RS,会同步全部删除 Pod;
3.状态同步依据
RS 对比「期望副本数 replicas」和「自己名下带监护人标记的 Pod 数量」,判断要不要新建 / 删除 Pod。
验证命令
[root@master30 ~ 13:58:14]# kubectl get pod nginx-lfz4z -o yaml | grep ownerReferences -A 10
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx
uid: 0ef9c293-15f7-48ee-adc9-7ecd0bbd157c
resourceVersion: "167783"
uid: 26f84e83-852c-4301-ae2e-164daf6aba75
spec:
containers:
输出里能清晰看到父资源为 ReplicaSet/nginx。
2.ReplicaSet 使用 selector 获得 Pod 集合。如果某个 Pod 没有 OwnerReference 或者其 OwnerReference 不是一个控制器, 且其匹配到某 ReplicaSet 的选择算符,则该 Pod 立即被此 ReplicaSet 获得。
通俗易懂: 一、拆出触发接管的全部条件(必须同时满足) 1.标签匹配:Pod 的 labels 和 RS 的 selector.matchLabels 完全一致(你的案例里都是 app: nginx); 2.Pod 无合法控制器监护人(满足任意一条即可): 情况 A:Pod 完全没有 ownerReferences 字段(手动单独创建的 Pod,天生无监护人); 情况 B:就算有 ownerReferences,里面记录的父资源不是控制器(比如绑定的是 ConfigMap、Secret 这类普通资源,不是 RS/Deployment)。 同时满足上面两点 → RS 会直接把这个 Pod 收归自己管理。 二、对应你实操里的现象解释 你执行这条命令手动新建 Pod: kubectl run nginx --image=xxx -l app=nginx 1.这个 Pod 是手动创建,没有 ownerReferences(无监护人); 2.标签 app=nginx 和 RS 的选择器完全匹配; 3.满足接管条件,RS 立刻收下这个 Pod; 4.RS 设置期望副本是 3,原本已经有 3 个归自己管的 Pod,现在多了 1 个,总数超标; 5.RS 执行调谐逻辑:删除多余 Pod,所以你看到新建 Pod 直接变成 Terminating(删除中)。 三、反向场景举例 如果 RS 当前只运行了 2 个 Pod(节点故障少了 1 个),此时手动创建一个同标签无主 Pod: RS 接管这个 Pod 后,副本数刚好达到 3; 数量匹配期望值,RS 不会删除它,也不会再新建 Pod。 四、核心区分:原生 Pod vs 被接管的孤儿 Pod 1.RS 模板自动创建的 Pod(原生 Pod) 自带 ownerReferences,天生属于这个 RS,是 “亲生”; 2.手动创建、匹配标签、无 ownerRef 的 Pod(孤儿 Pod) 没有监护人,只要标签对上,就会被就近匹配的 RS 强制接管,受 RS 的副本数量规则约束。
测试2:创建具有相同标签的pod,会被 RS 自动销毁
# 新建一个标签为 app=nginx 的独立Pod(不属于当前RS管理) # -l app=nginx:给这个 Pod 打上一个标签,Key 是 app,Value 是 nginx。(注意是 -l,小写 L,不是管道符 |) [root@master30 ~ 14:21:59]# kubectl run nginx --image=hub.laoma.cloud/library/nginx:latest -l app=nginx;kubectl get pods pod/nginx created NAME READY STATUS RESTARTS AGE nginx 0/1 Terminating 0 1s nginx-lfz4z 1/1 Running 0 36m nginx-pq9dv 1/1 Running 0 36m nginx-rdgsp 1/1 Running 0 28m #现象:刚创建的 Pod 直接进入 Terminating(正在删除)状态。 [root@master30 ~ 14:22:36]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-lfz4z 1/1 Running 0 36m nginx-pq9dv 1/1 Running 0 36m nginx-rdgsp 1/1 Running 0 28m 底层逻辑 RS 通过selector匹配所有标签app=nginx的 Pod; 这个手动创建的 Pod 没有ownerReferences(没有绑定父控制器),RS 会直接接管它; 当前已有 3 个合规 Pod,新增后总数量超过replicas:3,RS 自动删除多余 Pod,保证副本数严格等于 3。
ReplicaSet 删除
方式 1:默认级联删除(控制器 + Pod 一起删)
删除RS控制器,会删除它管理的pods。
[root@master30 ~ 14:22:49]# kubectl delete rs nginx replicaset.apps "nginx" deleted [root@master30 ~ 15:02:19]# kubectl get pods No resources found in controllers namespace. 行为:基于ownerReferences父子关联,删除 RS 的同时,自动删除它管理的所有 Pod。 执行后 kubectl get pods 看不到任何 nginx Pod。
方式 2:孤儿删除 --cascade=orphan(只删 RS,保留 Pod)
使用--cascade=orphan选项,只删除RS,保留pod。
[root@master30 ~ 15:02:28]# kubectl apply -f rs.yaml replicaset.apps/nginx created [root@master30 ~ 15:02:52]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-4hsmn 1/1 Running 0 7s nginx-g4mbh 1/1 Running 0 7s nginx-t55h5 1/1 Running 0 7s [root@master30 ~ 15:02:59]# kubectl delete rs nginx --cascade=orphan replicaset.apps "nginx" deleted [root@master30 ~ 15:03:25]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-4hsmn 1/1 Running 0 36s nginx-g4mbh 1/1 Running 0 36s nginx-t55h5 1/1 Running 0 36s 行为:仅删除 ReplicaSet 控制器,保留底下所有运行中的 Pod; 变化:Pod 的ownerReferences绑定关系被清空,不再受控制器管理; 后果:后续手动删除 Pod,不会自动重建,集群失去自愈能力。 #清理残留无控制器 Pod # 根据标签批量删除所有带 app=nginx 的Pod [root@master30 ~ 15:03:28]# kubectl delete all -l app=nginx pod "nginx-4hsmn" deleted pod "nginx-g4mbh" deleted pod "nginx-t55h5" deleted
底层核心知识点总结
1.ownerReferences Pod 内置字段,记录父控制器信息,是 RS 管理 Pod、级联删除的底层依据;孤儿删除会清空该字段。 2.selector 选择器接管规则 只要 Pod 标签匹配 RS 的matchLabels,且无控制器归属,就会被 RS 纳入管理;数量超标则删除,数量不足则新建。 3.RS 核心能力一句话:死死维持固定数量、标签匹配的 Pod,自动多删少补。
速记背诵版
1.创建 RS 需要 3 要素:副本数 replicas、标签选择器 selector、Pod 模板 template; 2.删 Pod 会自动重建,新建同标签无主 Pod 会被 RS 删掉; 3.默认删 RS 连带删 Pod,加--cascade=orphan只删控制器、保留 Pod。
ReplicationController
一、ReplicationController(RC)简要介绍
-
定位(大白话):RC是K8s早期最老的副本控制器,核心功能和现在的RS(ReplicaSet)一模一样,唯一作用就是:保证集群里始终运行指定数量的Pod,Pod挂了自动补。
-
RC与RS核心区别(重点):RC是旧版本,标签匹配规则非常死板,只能做「完全相等匹配」;RS是RC的全面升级版,支持更多灵活的标签筛选规则(集合式选择器),功能更强、兼容性更好。
-
生产使用铁律:RC已经被淘汰,新版本K8s完全不推荐使用。我们日常开发、实验、生产,一律用Deployment,Deployment底层自动调用RS,彻底替代RC。
Deployment
学习参考:Deployment
二、Deployment(简写 deploy)核心详解
1. 基础定义 & 三层父子层级关系
定义
Deployment(简称deploy,部署控制器)是K8s管理无状态应用的标配控制器。它不直接管理Pod,而是专门统一管理ReplicaSet,在此基础上新增了企业必备能力:无痛滚动更新、版本一键回滚、自动扩缩容、故障自愈。简单说:RS只负责“保数量”,Deployment负责“管版本、管更新、管生命周期”。
核心极简逻辑:用户只需要操作Deployment(上层),不用手动碰RS和Pod(下层),所有Pod创建、更新、删除、重建,全部由Deployment自动调度完成。
三层绑定关系(ownerReferences 父子链)
-
第一层关系:Deployment 管控 ReplicaSet 每一个Deployment都会自动创建一个专属RS,执行命令查看资源时,能明确看到归属关系:
Controlled By: Deployment/web,代表这个RS归web这个Deployment管。 -
第二层关系:ReplicaSet 管控 Pod 所有运行的Pod都是对应RS创建出来的,归属关系:
Controlled By: ReplicaSet/web-xxx。 级联删除规则:上层资源删除,默认自动删除所有下层子资源(删deploy→自动删rs+pod),依靠Pod的ownerReferences(归属标记)实现。
2. Deployment 7 大典型使用场景
-
快速部署应用:创建Deployment后,自动生成RS、拉起指定数量Pod,一键完成业务部署。
-
无痛滚动更新:修改镜像、配置等Pod模板内容时,不会直接删旧Pod,而是新建一个RS、逐步替换旧Pod,服务全程不中断,每更新一次生成一个版本记录。
-
故障版本回滚:新版本更新后出现报错、异常,无需重新部署,可一键回滚到之前稳定的旧版本。
-
动态水平扩缩容:业务流量大就增加Pod数量扛负载,流量小就减少Pod数量节约资源。
-
批量配置更新:支持暂停发布,批量修改多项配置后,再统一更新上线,避免多次重复发布。
-
监控发布状态:可实时查看更新进度,快速判断发布是否卡住、成功或失败。
-
自动资源清理:更新迭代产生的旧RS(副本数为0),系统会自动清理,避免集群资源冗余堆积。
Deployment 管理
创建
3. 两种创建方式对比
方式 1:命令行快速创建(临时测试用)
-
优点:命令极简、一秒创建,无需编写复杂YAML文件,非常适合课堂实验、临时测试、快速验证功能。
-
致命缺点:没有配置文件留存,无法记录部署参数,不能复用、无法统一管理,绝对不能用于正式生产环境。
[root@master30 ~ 10:06:43]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2
deployment.apps/web created
# 查看deployment创建的资源
[root@master30 ~ 10:07:01]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/web-768f99776c-k4zpv 1/1 Running 0 27s
pod/web-768f99776c-zwl2f 1/1 Running 0 27s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/web 2/2 2 2 27s
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-768f99776c 2 2 2 27s
# 查看deployment详细信息
[root@master30 ~ 10:07:22]# kubectl describe deployments.apps web
Name: web
Namespace: controllers
CreationTimestamp: Sat, 27 Jun 2026 10:06:55 +0800
Labels: app=web
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=web
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: docker.io/library/nginx:1.27
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Node-Selectors: <none>
Tolerations: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-768f99776c (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 76s deployment-controller Scaled up replica set web-768f99776c to 2
# ReplicaSet与Deployment关系
[root@master30 ~ 10:08:11]# kubectl describe replicasets.apps web-768f99776c | grep Controlled
Controlled By: Deployment/web
# 指明ReplicaSet是由Deployment/web创建的。
# pod与ReplicaSet关系
[root@master30 ~ 10:11:33]# kubectl describe pod web-768f99776c-k4zpv | grep Controlled
Controlled By: ReplicaSet/web-768f99776c
# 指明pod是由ReplicaSet/web-b78cbd74b创建的。
方式 2:YAML 配置文件创建(生产正式环境)
-
核心优点(生产必备):配置永久留存、可版本管控、可跨服务器重复部署,所有环境配置统一,是企业标准化部署方式。
-
关键命令特性:
kubectl apply是万能命令,文件不存在则创建资源,文件修改后重新执行则更新资源,无需删除重建。
# 获取deployment的yaml文件
[root@master30 ~ 10:11:41]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2 --dry-run=client -o yaml > deployment-web.yaml
[root@master30 ~ 10:14:12]# cat deployment-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 2
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: docker.io/library/nginx:1.27
name: nginx
resources: {}
status: {}
格式说明:
① apiVersion,是当前配置格式的版本。 ② kind,是要创建的资源类型, 这里是Deployment。 ③ metadata,是该资源的元数据, name是必需的元数据项。 ④ spec,是该Deployment的规格说明。 ⑤ spec.replicas,指明副本数量, 默认为1。 ⑥ spec.template,定义Pod的模板, 这是配置文件的重要部分。 ⑦ spec.template.metadata,定义Pod的元数据, 至少要定义一个label。 label的key和value可以任意指定。 ⑧ spec.template.spec,描述Pod的规格, 此部分定义Pod中每一个容器的属性,name和image是必需的。
[root@master30 ~ 10:15:54]# kubectl apply -f deployment-web.yaml deployment.apps/web configured
创建方式进行比较
-
基于命令行的方式:
-
简单、 直观、 快捷, 上手快。
-
适合临时测试或实验。
-
-
基于配置文件的方式:
-
配置文件描述了What, 即应用最终要达到的状态。
-
配置文件提供了创建资源的模板, 能够重复部署。
-
可以像管理代码一样管理部署。
-
适合正式的、 跨环境的、 规模化部署。
-
这种方式要求熟悉配置文件的语法, 有一定难度。
-
kubectl apply 命令不但能够创建Kubernetes资源, 也能对资源进行更新, 非常方便。
编辑
4. 基础运维操作
(1)编辑修改 Deployment 三种方法
-
在线编辑(临时修改):
kubectl edit deployments.apps web,直接在线修改配置,保存立即生效,适合临时微调。 -
YAML文件修改(生产推荐):修改本地YAML配置文件,执行
kubectl apply -f xxx.yaml,配置可留存溯源。 -
命令快速扩缩容:单行命令直接修改Pod副本数,无需改配置,适合快速调整负载:
kubectl scale deployment web --replicas=4
# 方法1:命令行直接修改 [root@master30 ~ 10:17:32]# kubectl edit deployments.apps web # 方法2:编辑资源文件,然后apply应用 root@master30:~# kubectl apply -f xxx.yaml # 方法3:命令行修改,例如修改deployment副本数 [root@master30 ~ 10:18:26]# kubectl scale deployment web --replicas=4 deployment.apps/web scaled
(2)删除 Deployment 两种模式
-
默认级联删除(推荐)
删除deployments时,默认会删除deployments管理的子资源,会同步删除下层所有 RS、Pod。
[root@master30 ~ 10:19:09]# kubectl delete deployments.apps web deployment.apps "web" deleted
2.孤儿删除(仅删 Deployment,保留 RS 和 Pod)
使用--cascade=orphan选项删除deployments,不会删除deployments管理的子资源。
[root@master30 ~ 10:19:32]# kubectl apply -f deployment-web.yaml deployment.apps/web created [root@master30 ~ 10:19:52]# kubectl get pods NAME READY STATUS RESTARTS AGE web-768f99776c-r6fpz 1/1 Running 0 8s web-768f99776c-v5bm7 1/1 Running 0 8s [root@master30 ~ 10:20:00]# kubectl get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE web 2/2 2 2 14s [root@master30 ~ 10:20:06]# kubectl delete deployments.apps web --cascade=orphan deployment.apps "web" deleted [root@master30 ~ 10:20:36]# kubectl get deployments.apps No resources found in controllers namespace. [root@master30 ~ 10:20:51]# kubectl get pods NAME READY STATUS RESTARTS AGE web-768f99776c-r6fpz 1/1 Running 0 62s web-768f99776c-v5bm7 1/1 Running 0 62s # 先确山删除对象 [root@master30 ~ 10:20:54]# kubectl get all -l app=web NAME READY STATUS RESTARTS AGE pod/web-768f99776c-r6fpz 1/1 Running 0 119s pod/web-768f99776c-v5bm7 1/1 Running 0 119s NAME DESIRED CURRENT READY AGE replicaset.apps/web-768f99776c 2 2 2 119s [root@master30 ~ 10:21:51]# kubectl delete all -l app=web # 然后再删除 [root@master30 ~ 10:21:51]# kubectl delete all -l app=web pod "web-768f99776c-r6fpz" deleted pod "web-768f99776c-v5bm7" deleted replicaset.apps "web-768f99776c" deleted [root@master30 ~ 10:22:08]# kubectl get all -l app=web No resources found in controllers namespace. 孤儿删除只会删掉Deployment这个“管理员”,保留正在运行的RS和Pod。此时Pod没有上层控制器管理,彻底失去自愈能力:Pod挂了不会自动重建、无法自动扩缩容,沦为孤儿资源。如需清理这些残留资源,执行精准清理命令:kubectl delete all -l app=web
(3)水平扩缩容(增减 Pod 数量)
三种实现方式:
1.scale 命令快速修改副本数
kubectl scale deployment web --replicas=3
2.kubectl edit 在线修改 spec.replicas 数值
3.修改本地 yaml 文件 replicas 字段,执行 apply 生效
# 创建 deployment [root@master30 ~ 10:22:09]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2 deployment.apps/web created # 或者直接输入edit命令编辑这个deployment.apps web这个文件,把--replicas=2改为--replicas=4,验证发现副本数立刻变成4个 [root@master30 ~ 10:25:25]# kubectl edit deployments.apps web deployment.apps/web edited #又新创建了两个副本 [root@master30 ~ 10:26:02]# kubectl get pods NAME READY STATUS RESTARTS AGE web-768f99776c-lw48v 1/1 Running 0 117s web-768f99776c-nr6zd 1/1 Running 0 7s web-768f99776c-t82sb 1/1 Running 0 2m47s web-768f99776c-wf9mz 1/1 Running 0 7s # 或者修改yaml文件并apply [root@master30 ~ 16:16:09]# kubectl get pods NAME READY STATUS RESTARTS AGE web-768f99776c-lw48v 1/1 Running 0 5h51m web-768f99776c-nr6zd 1/1 Running 0 5h50m web-768f99776c-t82sb 1/1 Running 0 5h52m web-768f99776c-wf9mz 1/1 Running 0 5h50m [root@master30 ~ 10:27:41]# kubectl get deployments.apps web -o yaml > web.yaml #修改副本数为3 [root@master30 ~ 16:15:36]# vim web [root@master30 ~ 16:16:01]# kubectl apply -f web.yaml Warning: resource deployments/web is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. deployment.apps/web configured #发现副本数从四变成三 [root@master30 ~ 16:16:10]# kubectl get pods NAME READY STATUS RESTARTS AGE web-768f99776c-lw48v 1/1 Running 0 5h52m web-768f99776c-t82sb 1/1 Running 0 5h53m web-768f99776c-wf9mz 1/1 Running 0 5h50m
5. 健壮性测试:节点宕机自动重建 Pod
现象
K8s集群具备节点故障自愈能力:当某一台Worker节点关机、宕机、故障后,Master节点不会一直等待,会通过心跳检测判定节点异常,随后将该节点上的所有Pod驱逐,自动在集群内正常的Worker节点上重建Pod,始终维持用户设定的副本总数,保证服务不中断。
关闭 worker 节点,测试pod重建。
[root@master30 ~ 16:16:29]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-768f99776c-lw48v 1/1 Running 0 5h54m 10.224.170.53 worker32.zy.cloud <none> <none>
web-768f99776c-t82sb 1/1 Running 0 5h55m 10.224.215.170 worker31.zy.cloud <none> <none>
web-768f99776c-wf9mz 1/1 Running 0 5h52m 10.224.215.171 worker31.zy.cloud <none> <none>
# 关闭 worker32
[root@worker32 ~ 16:19:44]# init 0
#查看状态
[root@master30 ~ 16:27:33]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-768f99776c-lw48v 1/1 Terminating 0 6h3m 10.224.170.53 worker32.zy.cloud <none> <none>
web-768f99776c-t82sb 1/1 Running 0 6h4m 10.224.215.170 worker31.zy.cloud <none> <none>
web-768f99776c-wf9mz 1/1 Running 0 6h2m 10.224.215.171 worker31.zy.cloud <none> <none>
web-768f99776c-wnjqs 1/1 Running 0 2m40s 10.224.215.172 worker31.zy.cloud <none> <none>
#把worker32节点开机后出现的状态,在worker32.zy.cloud的Terminating状态的pod被删除
[root@master30 ~ 16:29:08]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-768f99776c-t82sb 1/1 Running 0 6h12m 10.224.215.170 worker31.zy.cloud <none> <none>
web-768f99776c-wf9mz 1/1 Running 0 6h10m 10.224.215.171 worker31.zy.cloud <none> <none>
web-768f99776c-wnjqs 1/1 Running 0 10m 10.224.215.172 worker31.zy.cloud <none> <none>
#关于当前 Pod 状态(正常现象)
• web-768f99776c-lw48v 原本运行在 worker32 上,因为节点被 init 0 关闭,Kubernetes 控制平面检测到该节点不可达(NotReady),于是将该 Pod 标记为 Terminating,并在其他可用节点(worker31)上重新创建了一个新 Pod(wnjqs)来维持副本数。
• 目前集群已自动完成故障转移,你的应用仍然有 3 个 Running 副本(在 worker31 上),服务正常。
注意:这个 Terminating 的 Pod 会一直停留在该状态,直到节点恢复或 Pod 被强制删除。当 worker32 重新启动并加入集群后,该 Pod 会被自动清理。
# 等待一段时间(5分钟), Kubernetes 判定 worker32不可用, 将worker32上的Pod标记为Unknown状态, 并在worker31上重建Pod,维持总副本数为3
# 当worker32恢复后, Unknown的Pod会被删除, 已经运行的Pod不会重新调度回worker32。
1. 为什么是 5 分钟?(驱逐超时)
你提到的“等待 5 分钟”非常精准。Kubernetes 控制平面(kube-controller-manager)中有一个参数叫 --pod-eviction-timeout,默认值就是 5 分钟。
• 0 ~ 40秒:worker32 关机后,kubelet 停止上报心跳。控制平面将节点标记为 NotReady。
• 40秒 ~ 5分钟:Pod 状态变为 Unknown(因为无法确认 Pod 是否还在运行)。
• 5分钟整:超时时间到,控制平面判定节点不可恢复,开始执行 Pod 驱逐(Eviction)。它会在 API Server 中删除这些 Pod 对象,并立即在 worker31 上创建新的 Pod(wnjqs)来满足副本数 3。
2. 为什么是 Unknown 而不是 Terminating?
为什么你之前 init 0 没有看到 Unknown,而是直接看到了 Terminating?
因为 init 0 是一个“优雅关机”流程,系统在关闭前会主动通知 Kubelet,Kubelet 会向 API Server 发送“我要注销了”的信号,所以 API Server 直接将其标记为 Terminating。
而 systemctl stop kubelet 相当于“突然失联”(模拟断网/断电),API Server 收不到任何下线通知,只能等待超时,这期间就会显示出 Unknown。
[root@master30 ~ 16:32:54]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-768f99776c-t82sb 1/1 Running 0 6h17m 10.224.215.170 worker31.zy.cloud <none> <none>
web-768f99776c-wf9mz 1/1 Running 0 6h15m 10.224.215.171 worker31.zy.cloud <none> <none>
web-768f99776c-wnjqs 1/1 Running 0 15m 10.224.215.172 worker31.zy.cloud <none> <none>
[root@worker31 ~ 10:01:29]# systemctl stop kubelet.service
[root@worker31 ~ 16:38:20]# systemctl status kubelet.service
○ kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; preset: enabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: inactive (dead) since Sat 2026-06-27 16:38:20 CST; 3min 38s ago
Duration: 6h 38min 13.194s
Docs: https://kubernetes.io/docs/
Process: 928 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUB>
Main PID: 928 (code=exited, status=0/SUCCESS)
CPU: 4min 2.081s
#查看
[root@master30 ~ 16:41:21]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-768f99776c-5svj8 1/1 Running 0 16s 10.224.170.55 worker32.zy.cloud <none> <none>
web-768f99776c-fjwqt 1/1 Running 0 16s 10.224.170.59 worker32.zy.cloud <none> <none>
web-768f99776c-pb429 1/1 Running 0 16s 10.224.170.56 worker32.zy.cloud <none> <none>
web-768f99776c-t82sb 1/1 Terminating 0 6h21m 10.224.215.170 worker31.zy.cloud <none> <none>
web-768f99776c-wf9mz 1/1 Terminating 0 6h18m 10.224.215.171 worker31.zy.cloud <none> <none>
web-768f99776c-wnjqs 1/1 Terminating 0 18m 10.224.215.172 worker31.zy.cloud <none> <none>
看不到,太快了。为什么你看到的是 Terminating 而不是 Unknown?
驱逐流程:当节点超过超时时间(默认 5 分钟)未上报心跳时,节点生命周期控制器会执行两个连续动作:
标记 Unknown:先将该节点上的 Pod 状态设置为 Unknown(这是瞬间完成的 API 更新)。
发起删除:紧接着立即向 API Server 发送 Pod 的删除请求,打上 deletionTimestamp,Pod 状态随即变为 Terminating。
3. 节点恢复后,为什么 Pod 不会回来?(重点)
当 worker32 重新启动并 Ready 后,你观察到的现象是:
• Unknown/Terminating 的旧 Pod 被删掉(因为它们的生命周期已经随着驱逐流程结束了)。
• Running 的新 Pod 留在 worker31,不会自动迁回 worker32。
原因:Kubernetes 的调度器(Scheduler)只在 Pod 初次创建时负责“找位置”。一旦 Pod 处于 Running 状态,调度器就不再管它了。Kubernetes 不会自动进行负载均衡或重新平衡。只要 worker31 的资源够用,这些 Pod 就会永远待在 worker31 上,即使 worker32 空下来了。
K8s 判断节点宕机,要经过 3 个阶段:
-
Node 节点上kubelet 默认 每 10s 发一次心跳上报自身状态(kubelet → kube-apiserver)
-
Master 上
controller-manager每 5 秒检查一次心跳,连续 40s 没收到 Node节点心跳,判定 Node 节点不健康,b标记为NotReady。参数:node-monitor-period=5s 和 node-monitor-grace-period=40s。
该参数属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点,路径:
/etc/kubernetes/manifests/kube-controller-manager.yaml
编辑静态 Pod 配置文件,找到
command段,添加或修改--pod-eviction-timeout参数,保存文件,触发静态 Pod 重启。 -
pod-eviction-timeout=300s**:节点 NotReady 持续满 5 分钟,开始把 Pod 驱逐到别的节点。最终驱逐时间,节点持续5分钟未恢复就绪状态,K8s正式判定节点故障,开始驱逐该节点所有Pod,在其他正常节点重建。参数:pod-eviction-timeout=300s。
该参数也属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点。修改方法同上。
更新镜像
整套操作核心目标:将名为 web 的 Deployment 原有 nginx:1.27 镜像,升级为私有仓库 hub.laoma.cloud/library/nginx:1.28,全程演示查看配置、两种更新方式、滚动更新底层机制、结果验证。
# 设置 deployment 的 image 为 hub.laoma.cloud/library/nginx:1.28
# 获取容器名称
[root@master30 ~ 16:22:55]# kubectl get deployments.apps -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
web 3/3 3 3 6h3m nginx docker.io/library/nginx:1.27 app=web
# 或者
[root@master30 ~ 17:02:36]# kubectl describe deployments.apps web | grep Container -i -A2
Containers:
nginx:
Image: docker.io/library/nginx:1.27
# 更新镜像为hub.docker.io/library/nginx:1.28
#方式 1:kubectl set image(命令行快速更新,脚本自动化首选)
[root@master30 ~ 17:05:17]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record
deployment.apps/web image updated
#验证确实改了
[root@master30 ~ 17:07:54]# kubectl describe deployments.apps web | grep Container -i -A2 Containers:
nginx:
Image: docker.io/library/nginx:1.28
#完整语法拆解:kubectl set image <资源类型/资源名> <容器名>=新镜像地址 附加参数
#方式 2:kubectl edit deployments.apps web(可视化编辑 YAML,适合多配置同时修改
root@master30:~# kubectl edit deployments.apps web
#查看滚动更新底层:ReplicaSet(副本集)变化,发现新增了一个replicaset,用于创建新的pod
#更新镜像后执行查看副本集命令:
[root@master30 ~ 17:11:31]# kubectl get rs
NAME DESIRED CURRENT READY AGE
web-768f99776c 0 0 0 6h50m
web-7f7967f9f4 3 3 3 5m46s
#为什么是这个现象
核心原理:Deployment 不直接管理 Pod,依靠 ReplicaSet(RS)管控
RS 命名规则:部署名-随机哈希值,哈希由 Pod 模板(镜像、标签、配置)计算生成;
只要镜像 / 配置发生改动,哈希值变化,生成全新 ReplicaSet
两行 RS 解读
旧 RS web-5899d78c9:DESIRED=0
代表不再调度新 Pod,滚动更新过程中会逐步销毁该 RS 下所有 1.27 版本旧 Pod;保留旧 RS 不删除,用于版本回滚。
新 RS web-6c57bdf5f4:DESIRED=3
集群根据新镜像模板创建 3 个 1.28 新版本 Pod,等待 Pod 就绪后逐步下线旧 Pod。
默认滚动更新策略:
先创建新版 Pod → 就绪后再销毁旧 Pod,全程保证至少有可用 Pod,业务无中断。
# 查看镜像版本
root@master30:~# kubectl get deployments.apps web -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
web 3/3 3 3 26m nginx hub.laoma.cloud/library/nginx:1.28 app=web
版本控制
kubectl rollout 是专门管理Deployment/StatefulSet/DaemonSet滚动发布、版本历史、回滚、暂停发布的工具,核心实现 k8s 灰度版本管理。
使用 kubectl rollout 命令控制deployment版本。
[root@master30 ~ 17:13:40]# kubectl rollout -h
Manage the rollout of one or many resources.
Valid resource types include:
* deployments
* daemonsets
* statefulsets
Examples:
# Rollback to the previous deployment
kubectl rollout undo deployment/abc
# Check the rollout status of a daemonset
kubectl rollout status daemonset/foo
# Restart a deployment
kubectl rollout restart deployment/abc
# Restart deployments with the 'app=nginx' label
kubectl rollout restart deployment --selector=app=nginx
Available Commands:
history View rollout history
pause Mark the provided resource as paused
restart Restart a resource
resume Resume a paused resource
status Show the status of the rollout
undo Undo a previous rollout
Usage:
kubectl rollout SUBCOMMAND [options]
Use "kubectl rollout <command> --help" for more information about a given
command.
Use "kubectl options" for a list of global command-line options (applies to all
commands).
示例:
# 更新镜像为 docker.io/library/nginx:1.28 root@master30:~# kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record # 更新镜像为 docker.io/library/nginx:1.29 [root@master30 ~ 17:18:14]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.29 --record deployment.apps/web image updated # 查看更新记录 [root@master30 ~ 17:23:22]# kubectl rollout history deployment web deployment.apps/web REVISION CHANGE-CAUSE 1 <none> 2 kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record=true 3 kubectl set image deployment/web nginx=docker.io/library/nginx:1.29 --record=true # 回滚到版本1,指定版本回滚参数: --to-revision [root@master30 ~ 17:23:25]# kubectl rollout undo deployment web --to-revision=1 deployment.apps/web rolled back [root@master30 ~ 17:24:21]# kubectl rollout history deployment web deployment.apps/web REVISION CHANGE-CAUSE 2 kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record=true 3 kubectl set image deployment/web nginx=docker.io/library/nginx:1.29 --record=true 4 <none>
滚动更新
前置条件: 业务期望固定跑 10 个 Pod(desired=10),默认滚动更新规则 maxSurge=25%、maxUnavailable=25% 先算出固定阈值: maxSurge:10×25%=2.5,向上取整 = 3 更新期间,新旧 Pod 加起来最多只能同时存在 13 个(10+3) maxUnavailable:10×25%=2.5,向下取整 = 2 更新期间,最多同时关掉 2 个旧 Pod,线上最少保证 8 个 Pod 正常对外提供服务
Kubernetes提供了两个参数maxSurge和maxUnavailable来精细控制Pod的替换数量 。
-
两个参数直白解释
1.maxSurge:最多多启动几个新版本 Pod**
意思:更新时可以额外多开多少个新 Pod。
-
数值越大:一次性创建更多新 Pod,更新速度快,但会临时占用更多服务器资源
-
硬限制:所有新旧 Pod 总数,绝对不能超过
期望副本数 + maxSurge
2. maxUnavailable:最多同时下线几个旧版本 Pod
意思:更新时允许同时关停多少个还在运行的旧 Pod。
-
数值越大:一次性删掉更多旧 Pod,更新速度快,但线上可用服务变少,高峰期容易扛不住流量
-
硬底线:正常提供服务的 Pod,绝对不能少于
期望副本数 - maxUnavailable
-
总结:
-
maxSurge 值越大, 初始创建的新副本数量就越多。
-
maxUnavailable 值越大, 初始销毁的旧副本数量就越多,更新初期造成不可用副本数量越多。
理想情况下, 我们这个案例滚动更新的过程应该是这样的:
-
创建3个新副本,此时Running副本数为10,maxSurge副本总数达到13。
-
销毁2个旧副本,同时再创建2个新副本。此时Running副本数为8。如果之前创建的3个副本状态没有变更为Running,则ContainerCreating副本数为5,maxSurge副本总数仍为13。
-
当新副本状态变更为Running, 例如之前创建的5个新副本在同一时刻状态变为running。当然这是一种理想情况。
-
此时running状态副本为13个,那么此时可以一次性销毁5个旧副本,同时又可以一次性创建5个新副本,使running副本数回到8。
-
这个过程会持续进行, 直到所有的旧副本被新副本替换,滚动更新完成。
实践:更新deployment镜像,并使用以下脚本监控:
一:前置条件准备
[root@master30 ~ 17:40:46]# vim web-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 10 # 副本数固定10
selector:
matchLabels:
app: web
# 滚动更新策略(默认值,写出来方便查看)
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: docker.io/library/nginx:1.27
[root@master30 ~ 17:41:06]# kubectl apply -f web-deploy.yaml
deployment.apps/web created
#验证环境是否符合要求
#验证1:副本数是否为 10
[root@master30 ~ 17:42:34]# kubectl get deploy web
NAME READY UP-TO-DATE AVAILABLE AGE
web 10/10 10 10 98s
#验证 2:滚动更新策略参数
[root@master30 ~ 17:43:22]# kubectl get deploy web -o yaml | grep -A4 rollingUpdate
--
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
#验证3:确认 Pod 正常运行 10 个
[root@master30 ~ 17:41:44]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-768f99776c-4kq2k 1/1 Running 0 50s
web-768f99776c-5dvng 1/1 Running 0 50s
web-768f99776c-89k5d 1/1 Running 0 50s
web-768f99776c-8fkft 1/1 Running 0 50s
web-768f99776c-8x52j 1/1 Running 0 50s
web-768f99776c-d6m6g 1/1 Running 0 50s
web-768f99776c-dwhsl 1/1 Running 0 50s
web-768f99776c-mrw8f 1/1 Running 0 50s
web-768f99776c-ptkkg 1/1 Running 0 50s
web-768f99776c-sbhwg 1/1 Running 0 50s
二:创建 Pod 状态监控脚本 monitor_pod_numbers
[root@master30 ~ 17:44:44]# vim monitor_pod_numbers
#!/bin/bash
# 无限循环持续采集Pod状态
while true
do
# 分割线区分每一次采样
echo '===================' >> output.log
# 1. kubectl get pods --no-headers:不输出表头,只保留Pod数据
# 2. awk '{print $3}':提取第3列,即Pod运行状态(Running/ContainerCreating/Terminating)
# 3. sort | uniq -c:统计每种状态的Pod数量
# 4. sed -r 's/^ +//':删除行首多余空格,格式化输出
kubectl get pods --no-headers |awk '{print $3}' |sort | uniq -c |sed -r 's/^ +//' >> output.log
# 每0.5秒采集一次,高频捕捉滚动瞬间变化
sleep 0.5
done
#添加脚本执行权限
[root@master30 ~ 17:46:45]# chmod +x monitor_pod_numbers
#后台运行监控脚本,开始记录日志,使用 & 将脚本放入后台执行,不占用当前终端,所有 Pod 状态自动写入 output.log
[root@master30 ~ 17:50:32]# bash monitor_pod_numbers &
[1] 160706
# 更新nginx镜像版本,自动触发滚动更新
[root@master30 ~ 17:58:55]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.29
deployment.apps/web image updated
#执行后集群立刻创建新 ReplicaSet,启动滚动替换 Pod。,查看日志
[root@master30 ~ 17:58:55]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.29
deployment.apps/web image updated
[root@master30 ~ 17:59:30]# cat output.log
===================
10 Running // 更新镜像命令执行前,10个旧版本Pod稳定运行,无新建、销毁动作
===================
10 Running // 持续采样,集群状态无任何变化
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
===================
3 ContainerCreating // 新版Pod正在拉取镜像、初始化
1 Pending // 新版Pod等待节点调度分配资源
8 Running // maxUnavailable限制,最少保留8个可用Pod保障业务
2 Terminating // 最多同时销毁2个旧Pod,达到下线数量上限
===================
5 ContainerCreating // 新建新版Pod达到峰值,8+5=13触发maxSurge总Pod上限
8 Running // 可用服务Pod维持最低8台
2 Terminating // 依旧仅允许同时删除2个旧Pod
===================
3 ContainerCreating // 部分新版Pod启动完成,新建数量下降
2 Pending // 新增2个待调度新版Pod
8 Running // 业务可用数量不变
2 Terminating // 同步下线2台旧Pod
===================
5 ContainerCreating // 重新开满超额新版Pod,总Pod数再次到13
8 Running // 最少8台正常提供流量
5 Terminating // 多台新Pod就绪,可批量销毁5台旧Pod,加速替换
===================
5 ContainerCreating // 保持最大新建Pod数量
8 Running // 可用Pod底线不变
4 Terminating // 旧Pod持续清理,销毁数量动态变化
===================
4 ContainerCreating // 部分新Pod转为运行状态,创建数减少
8 Running // 服务稳定性不受影响
2 Terminating // 剩余旧Pod变少,每次仅销毁2台
===================
10 Running // 绝大多数新版Pod正常运行,可用Pod恢复到目标10个
2 Terminating // 只剩最后2个旧Pod等待删除
===================
10 Running // 旧Pod全部销毁完成,10台均为新版本Pod,滚动更新结束
===================
10 Running // 集群稳定,无创建、删除操作,持续稳态运行
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
===================
10 Running
#结束这个脚本
[root@master30 ~ 18:03:04]# kill 160706
DaemonSet
学习参考:DaemonSet
DaemonSet(简称 DS)到底是什么
一句话:满足条件的每个节点上,固定只运行 1 个 Pod。 和 Deployment 核心区别:
-
Deployment:指定总副本数,Pod 随机打散到各个节点,一个节点可以跑多个 Pod;
-
DaemonSet:不设置总副本,由集群节点数量决定 Pod 数量,一个节点最多 1 个该 DS 的 Pod。
节点生命周期联动规则:
-
新节点加入集群 → DS 自动在新节点创建 1 个 Pod;
-
节点下线 / 删除 → 节点上对应的 DS Pod 会被同步回收删除。
DaemonSet 典型使用场景
所有需要每个节点都部署一份的底层组件,都用 DS:
-
日志收集:fluent-bit、filebeat,每个节点采集本机容器日志;
-
节点监控:node-exporter,抓取服务器 CPU、内存、磁盘指标;
-
底层存储客户端:ceph、gluster 存储代理;
-
集群网络组件:calico-node、kube-proxy,每个节点负责网络转发。
DaemonSet 使用
DaemonSet 创建
[root@master30 ~ 18:03:17]# vim daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet # 资源类型改为DaemonSet,不是Deployment
metadata:
name: busybox
spec:
selector:
matchLabels:
app: busybox
template:
metadata:
labels:
app: busybox
spec:
containers:
- name: busybox
image: docker.io/library/busybox
imagePullPolicy: IfNotPresent
# 容器持续休眠,防止启动后立刻退出
command:
- sleep
- "36000"
[root@master30 ~ 18:16:52]# kubectl apply -f daemonset.yaml daemonset.apps/busybox created
DaemonSet 查看
[root@master30 ~ 18:18:32]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox-dfvt4 1/1 Running 0 97s 10.224.215.137 worker31.zy.cloud <none> <none> busybox-vfrqg 1/1 Running 0 97s 10.224.170.23 worker32.zy.cloud <none> <none> #输出里能看到:每个 worker 节点各一个 busybox Pod,master 没有。 #查看 DaemonSet 资源核心命令 [root@master30 ~ 18:18:34]# kubectl get ds NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE busybox 2 2 2 2 2 <none> 115s - DESIRED:预期 Pod 数量 = 符合调度条件的节点总数(当前 2 个 worker 节点) - CURRENT:已经创建出来的 Pod 数量 - READY:正常运行就绪的 Pod - NODE SELECTOR:节点选择器,为空代表匹配所有节点
DaemonSet 调度
核心调度:污点 (Taint) 控制 Master 节点是否运行 DS Pod
[root@master30 ~ 18:18:34]# kubectl get ds NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE busybox 2 2 2 2 2 <none> 115s # master节点是默认是不可调度节点,控制平面节点自带污点: [root@master30 ~ 18:23:00]# kubectl describe nodes master30.zy.cloud | grep Taints Taints: node-role.kubernetes.io/control-plane:NoSchedule #NoSchedule 规则:任何控制器(DS/Deployment)都不会把 Pod 调度到该节点,所以 master 不会生成 busybox Pod。 # 设置master节点可调度,去掉污点,允许 master 调度 Pod,# 末尾减号代表移除该污点 [root@master30 ~ 18:23:38]# kubectl taint node master30.zy.cloud node-role.kubernetes.io/control-plane- node/master30.zy.cloud untainted #原来两个,现在变成三个 [root@master30 ~ 18:25:19]# kubectl get ds NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE busybox 3 3 3 3 3 <none> 8m31s # 设置master节点不可调度,重新加上污点,禁止调度 master [root@master30 ~ 18:27:39]# kubectl taint node master30.zy.cloud node-role.kubernetes.io/control-plane:NoSchedule node/master30.zy.cloud tainted [root@master30 ~ 18:28:10]# kubectl get ds NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE busybox 2 2 2 2 2 <none> 11m 重点特性: 重新打污点不会立刻删除 master 上已经运行的 DS Pod,只是: 1. 不再新建 Pod; 2. 现有 Pod 如果手动删除,不会重建; 所以 kubectl get ds 的 DESIRED 数值变回 2,但 master 上旧 Pod 还会残留。
DaemonSet 健壮性
DaemonSet 自带自愈能力 DS 控制器持续巡检:每个符合条件的节点必须存在 1 个 Pod。
[root@master30 ~ 10:05:57]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox-dfvt4 1/1 Running 1 (117s ago) 15h 10.224.215.130 worker31.zy.cloud <none> <none> busybox-h7skq 1/1 Running 1 (116s ago) 15h 10.224.166.202 master30.zy.cloud <none> <none> busybox-vfrqg 1/1 Running 1 (118s ago) 15h 10.224.170.22 worker32.zy.cloud <none> <none> # 删除其中一个pod [root@master30 ~ 10:06:17]# kubectl delete pod busybox-dfvt4 pod "busybox-dfvt4" deleted # 自动创建新pod,控制器检测到节点缺少 Pod,立刻自动新建一个同名 Pod 补齐,永远保证一节点一 Pod。 [root@master30 ~ 10:07:31]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox-h7skq 1/1 Running 1 (3m23s ago) 15h 10.224.166.202 master30.zy.cloud <none> <none> busybox-mf4dn 1/1 Running 0 14s 10.224.215.139 worker31.zy.cloud <none> <none> busybox-vfrqg 1/1 Running 1 (3m25s ago) 15h 10.224.170.22 worker32.zy.cloud <none> <none>
DaemonSet 删除
删除 DaemonSet 的两种模式 模式 1:默认删除(连带清除所有 Pod)
#DS 资源 + 所有节点上的 busybox Pod 一起删掉。 [root@master master]# kubectl delete daemonsets.apps busybox daemonset.apps "busybox" deleted [root@master30 ~ 10:11:57]# kubectl delete daemonsets.apps busybox daemonset.apps "busybox" deleted [root@master30 ~ 10:12:28]# kubectl get pods NAME READY STATUS RESTARTS AGE busybox-h7skq 1/1 Terminating 1 (8m15s ago) 15h busybox-mf4dn 1/1 Terminating 0 5m6s busybox-vfrqg 1/1 Terminating 1 (8m17s ago) 15h [root@master30 ~ 10:12:59]# kubectl get pods No resources found in controllers namespace.
模式 2:只删 DS 资源,保留所有运行中的 Pod
#适应于业务场景:临时下线控制器,但节点采集 / 网络组件不能中断,保留 Pod 继续运行。 [root@master30 ~ 10:14:04]# kubectl apply -f daemonset.yaml daemonset.apps/busybox created [root@master30 ~ 10:14:41]# kubectl delete daemonsets.apps busybox --cascade=orphan daemonset.apps "busybox" deleted [root@master30 ~ 10:15:06]# kubectl get pods NAME READY STATUS RESTARTS AGE busybox-5ktzw 1/1 Running 0 29s busybox-mtpgr 1/1 Running 0 29s
K8s 集群中 DS
-
Kubernetes 使用 DaemonSet 控制器运行系统组件,例如kube-proxy、calico-node。
#kube-system 是集群系统组件专用文件夹,这条命令用来查看集群底层自带的后台守护程序。 [root@master30 ~ 10:16:18]# kubectl get daemonsets.apps --namespace kube-system NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE calico-node 3 3 3 3 3 kubernetes.io/os=linux 4d19h kube-proxy 3 3 3 3 3 kubernetes.io/os=linux 4d19h 1.NAME:程序名字 calico-node:负责集群所有 Pod 之间互相通信的网络工具 kube-proxy:负责 Service 负载均衡、转发流量 2.DESIRED=3:集群有 3 台 Linux 服务器,要求每台机器都跑 1 个该程序 Pod,一共需要 3 个 3.CURRENT=3:已经成功创建出 3 个 Pod 4.READY=3:3 个 Pod 全部正常启动完毕 5.NODE SELECTOR:只在 Linux 系统机器上运行,Windows 机器不部署 6.AGE:这个组件已经运行 4 小时
-
分析calico-node 的yaml文件:
apiVersion: apps/v1
kind: DaemonSet # 控制器类型:DaemonSet,特点是每台符合条件的机器只跑1个Pod
metadata:
name: calico-node
namespace: kube-system # 放到系统组件专属空间,不和业务程序混在一起
labels:
k8s-app: calico-node # 给自身打标签,方便管理
spec:
selector:
matchLabels:
k8s-app: calico-node # 通过标签找到自己管理的Pod
updateStrategy: # 更新镜像的规则
type: RollingUpdate # 滚动更新,不会一次性全停
rollingUpdate:
maxUnavailable: 1 # 重点:同一时间最多只停一台机器的网络Pod,防止集群断网
template: # 定义每台机器上运行的Pod长什么样
metadata:
labels:
k8s-app: calico-node
annotations:
scheduler.alpha.kubernetes.io/critical-pod: '' # 标记为核心程序,机器资源不够时最后才删它
spec:
nodeSelector:
kubernetes.io/os: linux # 只部署Linux机器
hostNetwork: true # 超级关键:直接共用宿主机真实网卡,不用容器虚拟IP,才能管控全网路由
containers:
- name: calico-node
image: hub.laoma.cloud/calico/node:v3.28.0 # 使用的镜像
注意: 完整配置文件内容要更复杂一些, 为了方便学习DaemonSet, 这里只保留了最重要的内容。
生产级示例
采集节点日志-Fluent Bit (必须用 DS)
作用 每台服务器部署一个日志收集工具,抓取本机系统日志、所有容器打印的业务日志,统一传到日志平台排查问题。 为什么只能用 DaemonSet? 日志存在本机硬盘里,收集工具只能读取当前机器文件,不能跨服务器拿日志,所以每台机器都要单独跑一个。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit-ds
namespace: kube-system # 属于集群运维基础工具
spec:
selector:
matchLabels:
app: fluent-bit
template:
metadata:
labels:
app: fluent-bit
spec:
containers:
- name: fluent-bit
image: cr.fluentbit.io/fluent/fluent-bit:latest
volumeMounts: # 把服务器本地文件夹挂载进容器,读取日志
- name: varlog
mountPath: /var/log # 容器里读取日志的位置
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true # 只读,防止误删原始日志
volumes:
- name: varlog
hostPath:
path: /var/log # 服务器存放系统日志的文件夹
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers # 存放容器业务日志的文件夹
采集节点监控指标-Node Exporter(必须用 DS)
作用 收集每台服务器 CPU、内存、磁盘、网卡使用情况,给监控平台展示、告警。 为什么只能用 DaemonSet? 硬件数据是每台机器独有的,程序只能读取本机硬件信息,一台机器一个采集程序。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter-ds
namespace: monitoring # 监控工具单独放一个分类
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
containers:
- name: node-exporter
image: prom/node-exporter:latest
ports:
- containerPort: 9100 # 对外开放端口,监控平台拉取硬件数据
volumeMounts: # 挂载服务器内核文件夹,读取硬件信息
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc # 存放CPU、内存实时数据
- name: sys
hostPath:
path: /sys # 存放磁盘、网卡硬件信息

DaemonSet 一句话核心特点
不用手动设置副本数量,有几台符合条件的机器,就自动创建几个 Pod,一台机器只跑 1 个; 删 Pod 会自动重建,机器新增 / 下线会自动增减 Pod; 适用场景:网络组件、日志收集、服务器监控这种每台机器都需要跑的底层工具。
和 Deployment 简单区分
Deployment:自己设置要跑多少个 Pod,随便分散在各个机器,一台机器能跑多个,用来部署业务项目(Nginx、后端服务); DaemonSet:跟着机器数量走,一台机器固定 1 个 Pod,用来部署集群底层运维工具。
Job
学习参考:Job
Job 是干嘛的?
Deployment、DaemonSet 都是长期一直运行的程序(Nginx、网络组件、监控,不关)。
Job 专门跑一次性短期任务:任务干完程序正常退出,这件事就结束了。
Job 自带规则
-
任务正常跑完(程序退出码 = 0)→ Job 标记完成,不再动;
-
任务中途失败报错:会自动重试;
-
跑任务的节点宕机失联:Pod 会调度到别的机器重新执行;
-
手动删除 Job:默认连带删掉所有它创建的 Pod; 加参数
--cascade=orphan:只删 Job,保留已经跑完的 Pod; -
挂起 Job:直接杀掉所有正在运行的 Pod,恢复后从头执行。
适合 Job 的场景
所有无需常驻、只需定时/单次执行的操作,全部用Job:
-
数据库:数据备份、数据清理、数据迁移、批量更新数据
-
集群运维:K8s集群备份、日志归档、垃圾文件清理
-
计算任务:批量运算、数据分析、文件批量处理
-
初始化任务:项目首次部署、初始化配置、创建数据库表结构
Job 使用
两种创建 Job 的方式
方式 1:命令行快速创建(测试用)
# 格式:kubectl create job 任务名 --镜像 -- 要执行的命令 root@master30:~# kubectl create job -h Create a job with the specified name. Examples: # Create a job kubectl create job my-job --image=busybox # Create a job with command kubectl create job my-job --image=busybox -- date ...... Usage: kubectl create job NAME --image=image [--from=cronjob/name] -- [COMMAND] [args...] [options]
示例1:
# 格式:kubectl create job 任务名 --镜像 -- 要执行的命令 [root@master30 ~ 10:22:13]# kubectl create job myjob --image=docker.io/library/busybox -- echo hello k8s job! job.batch/myjob created [root@master30 ~ 10:38:41]# kubectl get all NAME READY STATUS RESTARTS AGE pod/myjob-fmtsk 0/1 Completed 0 4m3s NAME STATUS COMPLETIONS DURATION AGE job.batch/myjob Complete 1/1 5s 4m4s 逐字段超详细解读: - Pod状态 0/1 Completed:1个容器就绪0个(正常!一次性任务跑完就退出,不需要常驻就绪),任务执行完成 - Job状态 1/1:目标完成数1个,实际成功完成1个,任务彻底结束 - DURATION 20s:任务总共耗时5秒执行完毕 #查看任务执行日志(核心排查命令) [root@master30 ~ 10:40:24]# kubectl logs myjob-fmtsk hello k8s job! # 删除 Job 的操作会清除所创建的全部 Pod # 使用--cascade=orphan选项,可以保留job创建的pod [root@master30 ~ 10:42:01]# kubectl delete jobs.batch myjob job.batch "myjob" deleted [root@master30 ~ 10:42:37]# kubectl get all No resources found in controllers namespace.
方式 2:YAML 文件创建(生产必用,可配置各种限制)
root@master30:~# vim job.yaml
# 专属API版本:Job属于批处理资源 batch/v1
apiVersion: batch/v1
# 资源类型:一次性任务Job
kind: Job
metadata:
name: myjob # 自定义任务名称
spec:
# Pod模板:定义执行任务的容器配置
template:
spec:
containers:
- name: hello
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent # 本地有镜像就不拉取,加速执行
command: ["echo", "hello k8s job! "] # 任务执行的命令
# Job专属重启策略:只能填 Never / OnFailure,禁止Always
restartPolicy: Never
root@master30:~# kubectl apply -f job.yaml
示例2:计算pi,保留小数点200位。
root@master30:~# vim job-pi.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: docker.io/library/perl
imagePullPolicy: IfNotPresent
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(200)"]
restartPolicy: Never
backoffLimit: 4
root@master30:~# kubectl apply -f job-pi.yaml # 等几分钟 #kubectl get all 作用:列出默认命名空间(default)下最常用的几种资源类型。注意,all 并不是指所有资源(它不包含 ConfigMap、Secret 等),它通常包括 Pod、Service、Deployment、ReplicaSet 和 Job 等。 [root@master30 ~ 10:50:29]# kubectl get all NAME READY STATUS RESTARTS AGE pod/pi-hr7n7 0/1 Completed 0 81s NAME STATUS COMPLETIONS DURATION AGE job.batch/pi Complete 1/1 42s 81s #作用:获取指定 Pod 内容器的标准输出(stdout)日志 [root@master30 ~ 10:50:09]# kubectl logs pi-hr7n7 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303820
restartPolicy 重启策略(Job 最核心、最容易混淆)
硬性规则:Job 绝对不能用 restartPolicy: Always(常驻服务专属),仅支持两种:Never、OnFailure
① restartPolicy: Never (新建Pod重试)
核心逻辑:容器执行失败退出 → 不重启当前Pod,直接废弃旧Pod,新建全新Pod重试
② restartPolicy: OnFailure (内部重启重试)
核心逻辑:容器执行失败退出 → 不新建Pod,只在当前Pod内部重启容器
实操现象:永远只有1个Pod,RESTARTS(重启次数)持续上涨,不会新增Pod
我们做个试验, 修改job.yaml, 故意引入一个错误 :echo 修改为 echoxxx。
[root@master30 ~ 11:17:26]# vim job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
template:
metadata:
name: myjob
spec:
containers:
- name: hello
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ["echoxxx", "hello k8s job! "]
restartPolicy: Never
再次应用,验证。
[root@master30 ~ 11:17:49]# kubectl apply -f job.yaml job.batch/myjob created [root@master30 ~ 11:18:43]# kubectl get all NAME READY STATUS RESTARTS AGE pod/myjob-fqhlc 0/1 StartError 0 26s pod/myjob-k4xdt 0/1 StartError 0 46s pod/myjob-q4qlw 0/1 StartError 0 57s NAME STATUS COMPLETIONS DURATION AGE job.batch/myjob Running 0/1 57s 57s #Job默认需要1个成功任务,当前一直0/1完成,旧Pod作废,持续新建Pod无限重试,不限制次数会卡死。。 #适用场景:任务执行环境损坏、单次执行不可逆,必须新建Pod重试的场景。 # 查看某个 pod 详细信息 [root@master30 ~ 11:18:53]# kubectl describe pod myjob-fqhlc #只看Events下面的内容: Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 50s default-scheduler Successfully assigned controllers/myjob-fqhlc to worker32.zy.cloud Normal Pulled 50s kubelet Container image "hub.laoma.cloud/library/busybox" already present on machine Normal Created 50s kubelet Created container hello Warning Failed 50s kubelet Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "echoxxx": executable file not found in $PATH: unknown
日志显示没有可执行程序, 符合我们的预期。
问题现象: 为什么会看到这么多失败的Pod?
解释: 当第一个Pod启动时, 容器失败退出, 根据 restartPolicy: Never, 此失败容器不会被重启, 但 Job 默认预期完成的Pod数量是1, 目前COMPLETIONS为0, 不满足, 所以 Job 会创建新的Pod, 直到 COMPLETIONS 为1。 对于我们这个例子, SUCCESSFUL 永远也到不了1, 所以Job 会一直创建新的Pod。 为了终止这个行为, 我们删除Job 。
清理 job
root@master30:~# kubectl delete jobs.batch myjob
如果将 restartPolicy 设置为 OnFailure 会怎么样?
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
template:
metadata:
name: myjob
spec:
containers:
- name: hello
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ["echoxxxx", "hello k8s job! "]
restartPolicy: OnFailure
再次应用,验证。
[root@master30 ~ 11:28:15]# kubectl apply -f job.yaml job.batch/myjob created [root@master30 ~ 11:28:29]# kubectl get all NAME READY STATUS RESTARTS AGE pod/myjob-48flc 0/1 CrashLoopBackOff 1 (3s ago) 4s NAME STATUS COMPLETIONS DURATION AGE job.batch/myjob Running 0/1 4s 4s [root@master30 ~ 11:28:55]# kubectl get all NAME READY STATUS RESTARTS AGE pod/myjob-48flc 0/1 RunContainerError 3 (9s ago) 45s NAME STATUS COMPLETIONS DURATION AGE job.batch/myjob Running 0/1 45s 45s # pod执行失败后,会重启。 # 永远只有1个Pod,RESTARTS(重启次数)持续上涨,不会新增Pod #适用场景:临时网络波动、参数临时错误,重启即可恢复的任务。
backoffLimit 最大失败重试次数(解决无限重试问题)
作用:限制Job最大重试次数,避免任务永久失败、无限创建Pod卡死集群。
默认值:6次
[root@master30 ~ 11:31:42]# vim job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
backoffLimit: 2 #任务最多失败重试2次,累计3次失败(初始1次+重试2次)后,Job直接标记失败,停止一切重试。
template:
metadata:
name: myjob
spec:
containers:
- name: hello
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ["echoxx", "hello k8s job! "]
restartPolicy: Never
[root@master30 ~ 11:32:20]# kubectl apply -f job.yaml
job.batch/myjob created
[root@master30 ~ 11:33:27]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/myjob-426nd 0/1 StartError 0 21s
pod/myjob-czv4s 0/1 StartError 0 1s
pod/myjob-jp99d 0/1 StartError 0 32s
NAME STATUS COMPLETIONS DURATION AGE
job.batch/myjob Running 0/1 32s 32s
#实操现象:只会出现3个失败Pod,之后不再新建任何Pod,Job状态永久0/1。
completions 任务完成总数(自定义需要多少个成功Pod)
默认值:1
作用:定义Job需要多少个Pod成功执行,才算任务整体完成。
示例:completions: 4
[root@master30 ~ 11:35:11]# vim job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
completions: 4 #必须4个独立Pod全部正常跑完、退出码0,Job状态才会变成 4/4 完成,单个成功不算结束。
template:
metadata:
name: myjob
spec:
containers:
- name: hello
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ["echo", "hello k8s job! "]
restartPolicy: Never
[root@master30 ~ 11:38:31]# kubectl apply -f job.yaml
job.batch/myjob created
[root@master30 ~ 11:38:34]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/myjob-c7x79 0/1 Completed 0 2s
NAME STATUS COMPLETIONS DURATION AGE
job.batch/myjob Running 0/4 2s 2s
[root@master30 ~ 11:38:36]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/myjob-2xsw5 0/1 Completed 0 17s
pod/myjob-bjj7r 0/1 Completed 0 20s
pod/myjob-c7x79 0/1 Completed 0 26s
pod/myjob-ggc8t 0/1 Completed 0 23s
NAME STATUS COMPLETIONS DURATION AGE
job.batch/myjob Complete 4/4 12s 26s
如果不指定completions, 默认值均为1。
parallelism
有时我们希望Job同时运行多个Pod, 提高Job的执行效率,通过parallelism设置并行Pod数量 。
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
completions: 6 # 全局目标:总共需要6个成功Pod
parallelism: 2 # 并行限制:同一时间最多跑2个Pod
template:
metadata:
name: myjob
spec:
containers:
- name: hello
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ["echo", "hello k8s job! "]
restartPolicy: Never
root@master30:~# kubectl get all NAME READY STATUS RESTARTS AGE pod/myjob-72zgz 0/1 Completed 0 4s pod/myjob-8brdq 0/1 Completed 0 8s pod/myjob-8l5cx 0/1 Completed 0 8s pod/myjob-9gkt8 0/1 Completed 0 12s pod/myjob-wcwwh 0/1 Completed 0 12s pod/myjob-xs6pd 0/1 Completed 0 4s NAME COMPLETIONS DURATION AGE job.batch/myjob 6/6 12s 12s 详细执行流程: 1. 第一轮:同时启动2个Pod → 执行完成 2. 第二轮:再启动2个Pod → 执行完成 3. 第三轮:再启动2个Pod → 执行完成 4. 累计6个成功Pod,Job 100%完成 生产价值:大批量数据处理、文件迁移,并行执行可直接缩短数倍耗时。
效果: 每次运行2个Pod, 直到总共有6个Pod成功完成。
如果不指定parallelism, 默认值均为1。
上面的例子只是为了演示Job的并行特性, 实际用途不大。 不过现实中确实存在很多需要并行处理的场景。 比如批处理程序, 每个副本(Pod) 都会从任务池中读取任务并执行, 副本越多, 执行时间就越短, 效率就越高。这种类似的场景都可以用Job来实现。
activeDeadlineSeconds 全局超时时间(最高优先级)
核心重点:所有参数中优先级最高,高于backoffLimit重试次数
作用:限制Job的整体运行时长,从Job创建开始计时,超时直接强制终止。
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-timeout
spec:
backoffLimit: 5
activeDeadlineSeconds: 10
template:
spec:
containers:
- name: pi
image: hub.laoma.cloud/library/perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
activeDeadlineSeconds: 10
无论任务是否执行完、无论重试次数是否达标,只要运行满10秒:
- 立刻杀死所有运行中的Pod
- Job标记为失败(Reason: DeadlineExceeded)
- 不再进行任何重试
生产用途:防止任务卡死、死循环,兜底保护集群资源。
参数优先级终极排序(面试必背)
activeDeadlineSeconds(超时) > backoffLimit(重试次数)
举例:Job设置最大重试5次,但全局超时10秒,10秒内只重试了2次,依然会强制终止,不再继续重试。
ttlSecondsAfterFinished 任务结束自动清理
作用:Job无论成功/失败,任务结束后,等待指定秒数,自动删除Job和所有Pod,无需手动清理。
-
ttlSecondsAfterFinished: 100:任务结束100秒后自动清理 -
ttlSecondsAfterFinished: 0:任务结束立刻自动清理 -
不配置:永久保留Job和Pod,必须手动删除(默认)
生产价值:避免大量历史结束任务堆积,浪费集群资源。
例如:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-ttl
spec:
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: pi
image: hub.laoma.cloud/library/perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
Job pi-with-ttl 在结束 100 秒之后,可以成为被自动删除的对象。
如果该字段设置为 0,Job 在结束之后立即成为可被自动删除的对象。 如果该字段没有设置,Job 不会在结束之后被 TTL 控制器自动清除。
注意这种 TTL 机制仍然是一种 Alpha 状态的功能特性,需要配合 TTLAfterFinished 特性门控使用。有关详细信息,可参考 TTL 控制器的文档。
CronJob
学习参考:CronJob
一:CronJob 介绍
-
Job:一次性任务,跑完就结束(手动执行、只跑一次)
-
CronJob:定时 Job,周期性自动执行(每分钟/每天/每周定时跑任务)
CronJob = 定时触发器 + Job
所有 CronJob 底层,都是自动创建 Job,Job 再创建 Pod 执行任务。
二:CronJob 使用
root@master30:~# kubectl create cronjob -h Create a cronjob with the specified name. Aliases: #别名 cronjob, cj Examples: # Create a cronjob kubectl create cronjob my-job --image=busybox --schedule="*/1 * * * *" # Create a cronjob with command kubectl create cronjob my-job --image=busybox --schedule="*/1 * * * *" -- date ...... Usage: kubectl create cronjob NAME --image=image --schedule='0/5 * * * ?' -- [COMMAND] [args...] [flags] [options]
示例:
#语法:kubectl create cronjob 任务名 --image=镜像地址 --schedule="cron定时表达式" -- 执行命令 参数 [root@master30 ~ 11:39:00]# kubectl create cronjob mycronjob --image=docker.io/library/busybox --schedule='*/2 * * * *' -- echo hello k8s job! cronjob.batch/mycronjob created 逐段拆分: kubectl create cronjob mycronjob 创建 CronJob 资源,名字叫 mycronjob --image=hub.laoma.cloud/library/busybox 定时任务每次拉起 Pod 使用的镜像 --schedule='*/2 * * * *' 定时规则:每 2 分钟执行一次 -- echo hello k8s job! -- 固定分隔符,后面是 Pod 内部运行的命令:打印字符串
等效的配置文件:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: mycronjob
spec:
schedule: "*/2 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: hub.laoma.cloud/library/busybox
command: ["echo", "hello k8s job! "]
restartPolicy: Never
[root@master30 ~ 12:26:47]# kubectl get all NAME READY STATUS RESTARTS AGE pod/mycronjob-29710342-v5qhf 0/1 Completed 0 5m35s pod/mycronjob-29710344-4n2gp 0/1 Completed 0 3m35s pod/mycronjob-29710346-k2q97 0/1 Completed 0 95s NAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/mycronjob */2 * * * * <none> False 0 95s 8m9s NAME STATUS COMPLETIONS DURATION AGE job.batch/mycronjob-29710342 Complete 1/1 3s 5m35s job.batch/mycronjob-29710344 Complete 1/1 3s 3m35s job.batch/mycronjob-29710346 Complete 1/1 4s 95s #kubectl get all 输出解读: 1、Pod 列表 Completed:一次性任务正常跑完,容器退出,属于正常状态,不是报错 一共 3 个 Pod,对应 3 次定时执行记录 名字中间一串数字是批次 ID,区分每一轮定时任务 AGE:距离本次任务执行完成过去了多久 2、CronJob 定时任务主体 SCHEDULE: */2 * * * *:每 2 分钟执行一次 TIMEZONE: <none>:未配置时区,默认使用集群节点本地时区 SUSPEND: False:定时任务正常运行,没有暂停;True 则不再生成新任务 ACTIVE: 0:当前没有正在运行中的任务 Pod,全部执行完毕 LAST SCHEDULE: 95s:上一次触发执行距离现在 95 秒 AGE: 8m9s:这个定时任务创建至今已经 8 分 9 秒 3.Job 批次列表 每到定时时间,CronJob 自动生成一个独立 Job Complete:该次任务全部执行成功 1/1:需要 1 个成功 Pod,已经完成 1 个,任务闭环 DURATION:本次任务从启动到执行完毕只花了 3~4 秒,速度很快 核心现象解释:为什么只看到 3 组 Job/Pod? CronJob 默认参数: successfulJobsHistoryLimit: 3 含义:只保留最近3 次成功执行的 Job 和 Pod,更早的历史记录会自动删除,防止无限堆积占用集群资源。 你每 2 分钟执行一次,现在刚好留存最近三轮记录。
三、CronJob 五大核心参数(逐行大白话)
1. schedule:定时规则(必写)
就是 Linux 定时任务 cron 表达式,控制 什么时候执行。
表达式格式(牢记顺序)
# 分 时 日 月 周 # 0-59 0-23 1-31 1-12 0-6(周日=0或7) * * * * *
通俗示例
-
* * * * *:每分钟执行一次 -
0 3 * * *:每天凌晨3点执行 -
0 0 * * 5:每周五零点执行 -
0 0 13 * 5:每月13号零点 + 每周五零点(题目示例)
重点:日和周是“或”的关系,满足任意一个就执行,不是同时满足!
2. jobTemplate:任务模板(必写)
CronJob 不会自己跑任务,它只是一个“闹钟”。
闹钟响了 = 自动创建一个 Job
所以 jobTemplate 里面写的内容,和你之前学的 Job yaml 完全一模一样。
区别:
-
普通 Job:有 apiVersion、kind
-
jobTemplate:嵌套模板,不需要 apiVersion、kind
里面可以写:重启策略、容器命令、挂载、节点选择、镜像、重试次数等所有 Job 参数。
3. startingDeadlineSeconds:超时兜底时间(重点生产参数)
场景:节点宕机、调度卡顿、集群卡住,错过了定时时间
这个参数作用:最多允许迟到多少秒执行。
举例
startingDeadlineSeconds: 200
-
定时时间到了
-
只要在 200秒内恢复,就补跑这次任务
-
超过200秒没跑:直接放弃本次任务,不补跑、不重试,等下一次定时
生产意义
比如每日备份:昨天的备份太晚跑没有意义,宁可放弃,保证只跑有效任务。
不配置:默认无限等待、无限补跑(容易堆积大量过期任务)
4. concurrencyPolicy:并发策略(解决任务重叠)
场景:上一次任务还没跑完,下一次定时时间又到了,怎么办?
三种模式(面试高频):
① Allow(默认)允许并发
新旧任务同时跑,可能多个备份、多个清理任务同时执行,容易冲突、脏数据。
② Forbid 禁止并发
旧任务没跑完 → 直接跳过本次新任务,不执行、不创建新Job。
适合:数据备份、清理任务(不能重叠)
③ Replace 替换旧任务
新时间到了、旧任务还在跑 → 直接杀掉旧任务,启动新任务
适合:实时性高、旧任务无效的场景
注意:并发策略 只限制同一个 CronJob 的任务,不同 CronJob 互相不影响。
5. 历史保留限制(自动清理历史 Job)
-
successfulJobsHistoryLimit:成功任务保留几个(默认3) -
failedJobsHistoryLimit:失败任务保留几个(默认1)
作用:防止成千上万的历史 Job、Pod 堆积占满集群。
设置为 0:不保留任何历史记录
生产建议:成功保留3,失败保留5,方便排错。
综合案例
案例1:定期清理主机目录内容
创建一个pod定期每分钟执行一次清空worker31节点/var/data目录内容。
思路:
-
清理目录:rm -fr /var/data/*
-
pod每次都在worker31上运行:使用 nodeName: worker31.laoma.cloud
-
将物理主机/var/data挂载给pod:使用 hostPath 类型 volume
-
周期性执行使用 cronjob
apiVersion: batch/v1
kind: CronJob # 定时任务控制器
metadata:
name: clean
spec:
# 定时规则:每分钟执行
schedule: '* * * * *'
# Job模板:每次定时触发,就创建这个Job执行任务
jobTemplate:
metadata:
name: clean
spec:
template:
spec:
# 强制固定运行在 worker31 节点
nodeName: worker31.laoma.cloud
containers:
- name: clean
image: hub.laoma.cloud/library/busybox
# 延迟3秒再删除,避免文件占用,清空目录所有内容
command: ["sh","-c","sleep 3 && rm -fr /var/data/*"]
# 挂载宿主机目录到容器
volumeMounts:
- mountPath: /var/data
name: data
volumes:
- name: data
# 映射宿主机真实目录
hostPath:
path: /var/data
# 容器失败就重启,保证清理成功
restartPolicy: OnFailure
核心原理通俗总结
1. nodeName:锁死节点,只清理 worker31,不碰其他机器
2. hostPath挂载:让容器能读到宿主机真实目录
3. sleep 3:防止文件正在写入、删除报错
4. OnFailure:删文件失败就重启重试
5. 每分钟触发:自动创建 Job、创建 Pod、执行删除、跑完销毁
生产案例2:CronJob 自动操作 K8s 集群(定时删Pod)
需求
每分钟自动删除指定标签的业务 Pod,实现定时重建服务、释放内存。
核心难点
默认 Pod 内部没有权限操作 K8s 集群,需要挂载 kubeconfig 凭据。
#提前创建 configMap 保存集群权限 # 创建cm保存kubectl凭据 [root@master controller]# kubectl create cm kubeconfig --from-file=config=/root/.kube/config # 通过 volume 挂载给pod
apiVersion: batch/v1
kind: CronJob
metadata:
name: clean
spec:
schedule: '* * * * *' # 每分钟执行
jobTemplate:
spec:
template:
spec:
restartPolicy: Never # 删Pod一次性操作,失败不重启
containers:
- name: kubectl
# 自带kubectl命令的镜像
image: hub.laoma.cloud/kubernetes/kubectl:v1.36.0
imagePullPolicy: IfNotPresent
# 执行命令:强制删除标签 app=hello 的 Pod
args:
- delete
- pods
- -l
- app=hello
- --force
- -n
- controllers
# 挂载集群凭据到容器内 /.kube
volumeMounts:
- name: kubeconfig
mountPath: "/.kube"
# 引用上面创建的 cm 凭据
volumes:
- name: kubeconfig
configMap:
name: kubeconfig
环境清理
root@master30:~# kubectl delete ns controllers
更多推荐
所有评论(0)