内容汇总:

  1. ReplicaSets

  2. Deployment

  3. DaemonSet

  4. Job

  5. 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 执行

四、极简背诵总结(考试/面试直接用)
  1. 控制器作用:持续监控资源状态,自动修正差异,保证集群始终处于用户期望的状态,实现自动化运维。

  2. 常驻服务控制器:ReplicaSet、Deployment、DaemonSet

  3. 任务类控制器:Job、CronJob

ReplicaSets

学习参考:ReplicaSets

一、ReplicaSet(RS)是什么?

ReplicaSet 简称 RS(副本控制器),是 K8s 的基础控制器。

核心作用:保证集群里永远有「指定数量、一模一样」的 Pod 在正常运行。

简单理解:RS 就是一个守数量的管理员,只负责维持 Pod 副本数量稳定。

二、RS 和 Deployment 的关系(重点)

我们几乎不会单独使用 RS

日常用的 Deployment(部署控制器),底层就是靠 ReplicaSet 来实现 Pod 的创建、删除、更新管理。Deployment 是上层工具,RS 是底层执行者。

三、ReplicaSet 三大核心字段(工作必备三要素)

RS 能正常工作,只靠这三个配置:

  1. Pod 选择算符 用来识别、绑定自己管理的一批 Pod,知道哪些 Pod 归自己管。

  2. 副本数量(replicas) 告诉 K8s 需要维持多少个正常运行的 Pod(期望数量)。

  3. Pod 模板 新建 Pod 的模板,定义 Pod 的镜像、配置、端口等,缺 Pod 时就按这个模板创建新 Pod。

四、ReplicaSet 工作原理(核心逻辑:补差、去多)

RS 会一直循环检查当前 Pod 实际数量,和设定的期望数量做对比,自动修复:

1. 实际 Pod 数量 > 设置数量

RS 会自动删掉多余的 Pod,保证数量不超标。

2. 实际 Pod 数量 < 设置数量

RS 会按照模板自动新建 Pod,补齐缺失数量。

举例场景:节点内核升级、节点宕机导致 Pod 消失,RS 会在其他正常节点重新创建 Pod,保证服务数量稳定。

五、极简背诵总结(考试/作业直接抄)

  1. ReplicaSet(RS)用于维持指定数量的相同 Pod 稳定运行,保障服务可用性。

  2. RS 一般被 Deployment 底层调用,不单独使用。

  3. 通过选择器、副本数、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

一、ReplicationController(RC)简要介绍

  1. 定位(大白话):RC是K8s早期最老的副本控制器,核心功能和现在的RS(ReplicaSet)一模一样,唯一作用就是:保证集群里始终运行指定数量的Pod,Pod挂了自动补。

  2. RC与RS核心区别(重点):RC是旧版本,标签匹配规则非常死板,只能做「完全相等匹配」;RS是RC的全面升级版,支持更多灵活的标签筛选规则(集合式选择器),功能更强、兼容性更好。

  3. 生产使用铁律:RC已经被淘汰,新版本K8s完全不推荐使用。我们日常开发、实验、生产,一律用Deployment,Deployment底层自动调用RS,彻底替代RC。

Deployment

学习参考:Deployment

二、Deployment(简写 deploy)核心详解

1. 基础定义 & 三层父子层级关系

定义

Deployment(简称deploy,部署控制器)是K8s管理无状态应用的标配控制器。它不直接管理Pod,而是专门统一管理ReplicaSet,在此基础上新增了企业必备能力:无痛滚动更新、版本一键回滚、自动扩缩容、故障自愈。简单说:RS只负责“保数量”,Deployment负责“管版本、管更新、管生命周期”。

核心极简逻辑:用户只需要操作Deployment(上层),不用手动碰RS和Pod(下层),所有Pod创建、更新、删除、重建,全部由Deployment自动调度完成。

三层绑定关系(ownerReferences 父子链)
  1. 第一层关系:Deployment 管控 ReplicaSet 每一个Deployment都会自动创建一个专属RS,执行命令查看资源时,能明确看到归属关系:Controlled By: Deployment/web,代表这个RS归web这个Deployment管。

  2. 第二层关系:ReplicaSet 管控 Pod 所有运行的Pod都是对应RS创建出来的,归属关系:Controlled By: ReplicaSet/web-xxx级联删除规则:上层资源删除,默认自动删除所有下层子资源(删deploy→自动删rs+pod),依靠Pod的ownerReferences(归属标记)实现。

2. Deployment 7 大典型使用场景

  1. 快速部署应用:创建Deployment后,自动生成RS、拉起指定数量Pod,一键完成业务部署。

  2. 无痛滚动更新:修改镜像、配置等Pod模板内容时,不会直接删旧Pod,而是新建一个RS、逐步替换旧Pod,服务全程不中断,每更新一次生成一个版本记录。

  3. 故障版本回滚:新版本更新后出现报错、异常,无需重新部署,可一键回滚到之前稳定的旧版本。

  4. 动态水平扩缩容:业务流量大就增加Pod数量扛负载,流量小就减少Pod数量节约资源。

  5. 批量配置更新:支持暂停发布,批量修改多项配置后,再统一更新上线,避免多次重复发布。

  6. 监控发布状态:可实时查看更新进度,快速判断发布是否卡住、成功或失败。

  7. 自动资源清理:更新迭代产生的旧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 三种方法
  1. 在线编辑(临时修改)kubectl edit deployments.apps web,直接在线修改配置,保存立即生效,适合临时微调。

  2. YAML文件修改(生产推荐):修改本地YAML配置文件,执行 kubectl apply -f xxx.yaml,配置可留存溯源。

  3. 命令快速扩缩容:单行命令直接修改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 两种模式
  1. 默认级联删除(推荐)

删除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 个阶段

  1. Node 节点上kubelet 默认 每 10s 发一次心跳上报自身状态(kubelet → kube-apiserver)

  2. Master 上 controller-manager5 秒检查一次心跳,连续 40s 没收到 Node节点心跳,判定 Node 节点不健康,b标记为 NotReady

    参数:node-monitor-period=5snode-monitor-grace-period=40s

    该参数属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点,路径:

    /etc/kubernetes/manifests/kube-controller-manager.yaml

    编辑静态 Pod 配置文件,找到 command 段,添加或修改 --pod-eviction-timeout 参数,保存文件,触发静态 Pod 重启。

  3. 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 值越大, 初始销毁的旧副本数量就越多,更新初期造成不可用副本数量越多。

理想情况下, 我们这个案例滚动更新的过程应该是这样的:

  1. 创建3个新副本,此时Running副本数为10,maxSurge副本总数达到13。

  2. 销毁2个旧副本,同时再创建2个新副本。此时Running副本数为8。如果之前创建的3个副本状态没有变更为Running,则ContainerCreating副本数为5,maxSurge副本总数仍为13。

  3. 当新副本状态变更为Running, 例如之前创建的5个新副本在同一时刻状态变为running。当然这是一种理想情况。

  4. 此时running状态副本为13个,那么此时可以一次性销毁5个旧副本,同时又可以一次性创建5个新副本,使running副本数回到8。

  5. 这个过程会持续进行, 直到所有的旧副本被新副本替换,滚动更新完成。

实践:更新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 核心区别:

  1. Deployment:指定总副本数,Pod 随机打散到各个节点,一个节点可以跑多个 Pod;

  2. DaemonSet:不设置总副本,由集群节点数量决定 Pod 数量,一个节点最多 1 个该 DS 的 Pod

节点生命周期联动规则:

  • 新节点加入集群 → DS 自动在新节点创建 1 个 Pod;

  • 节点下线 / 删除 → 节点上对应的 DS Pod 会被同步回收删除。

DaemonSet 典型使用场景

所有需要每个节点都部署一份的底层组件,都用 DS:

  1. 日志收集:fluent-bit、filebeat,每个节点采集本机容器日志;

  2. 节点监控:node-exporter,抓取服务器 CPU、内存、磁盘指标;

  3. 底层存储客户端:ceph、gluster 存储代理;

  4. 集群网络组件: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

  1. 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 小时
  1. 分析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 # 存放磁盘、网卡硬件信息

image-20260628101808270

DaemonSet 一句话核心特点

不用手动设置副本数量,有几台符合条件的机器,就自动创建几个 Pod,一台机器只跑 1 个; 删 Pod 会自动重建,机器新增 / 下线会自动增减 Pod; 适用场景:网络组件、日志收集、服务器监控这种每台机器都需要跑的底层工具。

和 Deployment 简单区分

Deployment:自己设置要跑多少个 Pod,随便分散在各个机器,一台机器能跑多个,用来部署业务项目(Nginx、后端服务); DaemonSet:跟着机器数量走,一台机器固定 1 个 Pod,用来部署集群底层运维工具。

Job

学习参考:Job

Job 是干嘛的?

Deployment、DaemonSet 都是长期一直运行的程序(Nginx、网络组件、监控,不关)。

Job 专门跑一次性短期任务:任务干完程序正常退出,这件事就结束了。

Job 自带规则

  1. 任务正常跑完(程序退出码 = 0)→ Job 标记完成,不再动;

  2. 任务中途失败报错:会自动重试;

  3. 跑任务的节点宕机失联:Pod 会调度到别的机器重新执行;

  4. 手动删除 Job:默认连带删掉所有它创建的 Pod; 加参数 --cascade=orphan:只删 Job,保留已经跑完的 Pod;

  5. 挂起 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目录内容。

思路:

  1. 清理目录:rm -fr /var/data/*

  2. pod每次都在worker31上运行:使用 nodeName: worker31.laoma.cloud

  3. 将物理主机/var/data挂载给pod:使用 hostPath 类型 volume

  4. 周期性执行使用 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

更多推荐