K8S控制器全解-从RS到DaemonSet实战完全指南

K8S控制器全解:从RS到DaemonSet,掌握五大控制器的核心原理与实战

导读 :在 Kubernetes 中,你几乎不会直接创建 Pod------而是通过控制器(Controller) 来管理 Pod 的生命周期。控制器是 K8S 实现声明式 API 和自愈能力的核心机制。本文将从 ReplicaSet 到 DaemonSet,逐一拆解五大控制器的工作原理、标签选择器机制、升级策略,并通过完整实战帮你建立系统性的控制器知识体系。最后附上面试高频题:"如何通过 Pod 反向查找控制器"。


一、为什么需要控制器?

在 K8S 中,直接创建的 Pod 是"裸奔"的------节点故障 Pod 不会自动迁移,进程崩溃不会自动恢复,应用更新无法平滑过渡。控制器就是来解决这些问题的:

复制代码
┌──────────────────────────────────────────────────────────┐
│                    K8S 控制器核心能力                       │
├──────────────┬───────────────────────────────────────────┤
│  自愈能力     │  Pod 挂了自动重建,节点宕机自动迁移          │
│  弹性伸缩     │  自动维持期望的 Pod 副本数量                │
│  滚动更新     │  零停机升级应用版本                        │
│  版本回滚     │  更新出问题可以快速回退到上一个版本          │
│  声明式管理   │  只需声明期望状态,控制器自动调和差异        │
└──────────────┴───────────────────────────────────────────┘

控制器的核心工作原理:控制循环(Reconciliation Loop)

复制代码
  期望状态(Desired State)    实际状态(Current State)
  ┌──────────────────┐        ┌──────────────────┐
  │ replicas: 3      │        │ running pods: 2  │
  │ image: nginx:v2  │        │ image: nginx:v1  │
  └────────┬─────────┘        └────────┬─────────┘
           │                           │
           └───────────┬───────────────┘
                       ▼
              ┌─────────────────┐
              │  控制循环比较差异  │
              │  (Reconcile)    │
              └────────┬────────┘
                       ▼
              ┌─────────────────┐
              │  执行调和动作     │
              │  创建/删除/更新Pod│
              └─────────────────┘

二、K8S 控制器全景图

复制代码
┌─────────────────────────────────────────────────────────┐
│                 K8S 工作负载控制器                         │
├──────────────────┬──────────────────────────────────────┤
│  Deployment      │  无状态应用(Web服务、API)             │
│  ├─ ReplicaSet   │  副本管理(底层控制器)                  │
│  └─ Pod          │                                      │
├──────────────────┼──────────────────────────────────────┤
│  DaemonSet       │  每个节点一个Pod(监控、日志采集)        │
├──────────────────┼──────────────────────────────────────┤
│  Job             │  一次性任务(数据库备份、数据迁移)        │
│  └─ CronJob      │  定时任务(增量备份、日志清理)           │
├──────────────────┼──────────────────────────────────────┤
│  StatefulSet     │  有状态应用(数据库、消息队列)           │
├──────────────────┼──────────────────────────────────────┤
│  HPA/VPA         │  自动伸缩(动态调整副本/资源)           │
└──────────────────┴──────────────────────────────────────┘

控制器选型决策表:

场景 推荐控制器 原因
Web 服务、API Deployment 支持滚动更新、回滚、弹性伸缩
监控 Agent、日志采集 DaemonSet 每个节点一个 Pod,自动跟随节点
数据库全量备份 Job 一次性任务,执行完成即终止
定时清理日志 CronJob 周期性执行,类似 Linux crontab
MySQL、Redis 集群 StatefulSet 需要稳定的网络标识和存储
批处理任务 Job + parallelism 并行处理多个任务

三、ReplicaSet:副本管理的基石

3.1 RS 与 RC 的关系

ReplicaSet(RS)是 ReplicationController(RC)的升级版,官方已废弃 RC。两者的核心区别在于标签选择器的能力:

特性 RC RS
等值选择 支持 支持(matchLabels
集合选择 不支持 支持matchExpressions
当前状态 已废弃 推荐使用(但通常被 Deployment 管理)

生产提示 :虽然 RS 功能更强大,但在实际工作中几乎不会直接创建 RS------而是通过 Deployment 间接管理。Deployment 是对 RS 的上层封装,增加了声明式更新和版本管理能力。

3.2 RS 基础实战:matchLabels

yaml 复制代码
# rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs
spec:
  replicas: 3                       # 期望副本数
  selector:
    matchLabels:                     # 等值匹配:标签必须完全一致
      apps: lingxi
  template:                          # Pod 模板
    metadata:
      labels:
        apps: lingxi
        version: v1
    spec:
      containers:
      - name: c1
        image: nginx:1.20
bash 复制代码
kubectl apply -f rs.yaml

# 查看 RS 和 Pod(Pod 名称自动带上 RS 名称前缀)
kubectl get rs,pods -o wide
# NAME                         DESIRED   CURRENT   READY
# replicaset.apps/rs   3         3         3
#
# NAME               READY   STATUS    IP             NODE
# pod/rs-xxx   1/1     Running   10.100.2.103   worker233
# pod/rs-xxx   1/1     Running   10.100.1.124   worker232
# pod/rs-xxx   1/1     Running   10.100.2.104   worker233

验证自愈能力: 删除所有 Pod,RS 会自动重建:

bash 复制代码
kubectl delete pods -l apps=lingxi
# pod "rs-xxx" deleted (x3)

kubectl get pods -o wide
# NAME               READY   STATUS    AGE    IP             NODE
# pod/rs-new  1/1     Running   4s     10.100.1.125   worker232
# pod/rs-new  1/1     Running   4s     10.100.2.105   worker233
# pod/rs-new  1/1     Running   4s     10.100.1.126   worker232

3.3 RS 进阶:matchExpressions 集合选择

matchExpressions 支持四种操作符,能力远超 RC 的等值匹配:

yaml 复制代码
# rs-matchExpressions.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-match-expressions
spec:
  replicas: 5
  selector:
    matchExpressions:                  # 集合选择器
    - key: version
      values:
      - v1
      - v2
      - v3
      operator: In                     # version 的值在 [v1,v2,v3] 中
  template:
    metadata:
      labels:
        apps: lingxi
        version: v1
    spec:
      containers:
      - name: c1
        image: nginx:1.20

四种操作符:

操作符 说明 示例
In key 的值在 values 列表中 version In [v1, v2, v3]
NotIn key 的值不在 values 列表中 env NotIn [prod]
Exists key 存在即可(忽略 values) version Exists
DoesNotExist key 不存在 debug DoesNotExist

关键行为: RS 的 matchExpressions同时管理已存在的匹配 Pod 。例如集群中已有标签 version=v1 的独立 Pod,创建 RS 后这些 Pod 也会被纳入管理。删除 RS 后,被纳入管理的 Pod 也会被一并删除。


四、Deployment:无状态应用的"最佳拍档"

4.1 Deployment 与 RS 的关系

Deployment 是对 RS 的上层封装,核心价值在于声明式更新版本管理

复制代码
┌──────────────┐     管理      ┌──────────────────┐     管理      ┌─────┐
│  Deployment  │ ──────────→ │  ReplicaSet (v1)  │ ──────────→ │ Pod │
│              │              │  ReplicaSet (v2)  │ ──────────→ │ Pod │
│              │              │  ReplicaSet (v3)  │ ──────────→ │ Pod │
└──────────────┘              └──────────────────┘             └─────┘
  版本管理                      历史版本保留                       实例
  滚动更新                      每次更新创建新RS                   运行中
  回滚能力                      旧RS保留用于回滚

核心机制:每次更新 Deployment 的 Pod 模板(如修改镜像版本),会创建一个新的 RS,逐步将流量从旧 RS 的 Pod 切换到新 RS 的 Pod。旧 RS 默认保留,支持快速回滚。

4.2 Deployment 基础实战

yaml 复制代码
# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      apps: lingxi
  template:
    metadata:
      labels:
        apps: lingxi
        version: v1
    spec:
      containers:
      - name: c1
        image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest
bash 复制代码
kubectl apply -f deploy.yaml

# 查看 Deployment、RS、Pod 的层级关系
kubectl get deploy,rs,po --show-labels
# deployment.apps/deploy   3/3   3   3   13s
#
# replicaset.apps/deploy-568cf47956   3   3   3
#   标签: apps=lingxi,pod-template-hash=568cf47956,version=v1
#
# pod/deploy-568cf47956-hwglc   1/1   Running
#   标签: apps=lingxi,pod-template-hash=568cf47956,version=v1

关键标签pod-template-hash 是 K8S 自动添加的标签,值由 Pod 模板内容哈希生成。相同模板的 Pod 拥有相同的 hash,用于 RS 精确匹配自己的 Pod。

4.3 滚动更新(RollingUpdate)

更新 Deployment 的镜像版本,观察滚动更新过程:

yaml 复制代码
# 修改 image: apps:v2 → apps:v3
spec:
  containers:
  - name: c1
    image: registry.openanolis.cn/openanolis/nginx:1.14.1-8.6
bash 复制代码
kubectl apply -f deploy-update.yaml

# 观察更新过程:新RS创建,旧RS缩容
kubectl get deploy,rs,po -o wide
# deployment.apps/deploy   5/5   5   5
#
# replicaset.apps/deploy-5f77fddbd7   0/0/0  ← 旧RS(v2),Pod已清空
# replicaset.apps/deploy-78ddbbdbfb   5/5/5  ← 新RS(v3),Pod已就绪

4.4 升级策略详解

Deployment 支持两种升级策略:

yaml 复制代码
spec:
  strategy:
    type: RollingUpdate     # 默认策略
    rollingUpdate:
      maxSurge: 2           # 滚动更新时最多允许超出期望副本数2个
      maxUnavailable: 1     # 滚动更新时最多允许1个Pod不可用
参数 Recreate RollingUpdate
更新方式 先删全部旧Pod,再创建新Pod 逐步替换,新旧Pod共存
停机时间 (删除到创建的间隔) (始终有Pod在运行)
资源开销 低(同一时刻只有一套Pod) 高(新旧Pod共存,需要maxSurge资源)
回滚速度 慢(需要重新创建全部Pod) 快(旧RS还在,直接扩容)
适用场景 不兼容的多版本更新 绝大多数场景(推荐)

maxSurge 和 maxUnavailable 的计算规则:

场景 replicas=5, maxSurge=25%(默认) replicas=5, maxSurge=2
更新时最多Pod数 ceil(5 * 1.25) = 7 5 + 2 = 7
场景 replicas=1, maxUnavailable=25%(默认) replicas=1, maxUnavailable=1
更新时最少可用Pod floor(1 * 0.75) = 0 1 - 1 = 0

生产建议 :设置 maxUnavailable: 0(零停机),配合 maxSurge: 25%,确保更新过程中始终有足够的 Pod 处理流量。

4.5 版本回滚

bash 复制代码
# 查看更新历史
kubectl rollout history deployment deploy

# 回滚到上一个版本
kubectl rollout undo deployment deploy

# 回滚到指定版本
kubectl rollout undo deployment deploy --to-revision=2

# 查看回滚状态
kubectl rollout status deployment deploy

五、Job:一次性任务的执行器

5.1 Job 控制器概述

Job 用于运行一次性任务,任务执行完成后 Pod 自动终止。典型的应用场景:

  • 数据库全量备份
  • 数据迁移
  • 批量邮件发送
  • CI/CD 流水线中的构建任务
  • 大数据处理任务

5.2 Job 实战:Python 脚本执行

yaml 复制代码
# job-python.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: jobs-py
spec:
  template:
    spec:
      containers:
      - name: py
        image: python:3.9.16-alpine3.16
        command:
        - python3
        - -c
        - "print('https://www.baidu.com/')"
      restartPolicy: Never           # Job 只能是 Never 或 OnFailure
  backoffLimit: 4                    # 失败重试次数(创建新Pod重试)
bash 复制代码
kubectl apply -f job-python.yaml

# 查看执行状态
kubectl get jobs,pods -o wide
# NAME                COMPLETIONS   DURATION   AGE
# job.batch/jobs-py   1/1           4s         6s
#
# NAME              READY   STATUS      RESTARTS   AGE
# pod/jobs-py-xxx    0/1     Completed   0          6s

# 查看执行日志
kubectl logs jobs-py-965q5

5.3 Job 关键参数

参数 说明 默认值
backoffLimit 失败重试次数(创建新 Pod 重试) 6
completions 需要成功完成的 Pod 数 1
parallelism 并行运行的 Pod 数 1
activeDeadlineSeconds Job 超时时间,超时自动标记失败 无限制
ttlSecondsAfterFinished 完成后自动清理的延迟时间 永不清理
restartPolicy 重启策略,只能是 Never 或 OnFailure Never

5.4 Job 的 restartPolicy 详解

策略 行为 适用场景
Never 失败后创建新 Pod 重试(Pod 数量会增加) 大多数场景(推荐)
OnFailure 失败后在同一个 Pod 内重启容器 需要保留容器状态

关键区别Never 会创建新的 Pod 来重试,每次重试都是"干净的"环境;OnFailure 在同一 Pod 内重启容器,可能残留上次的状态。


六、CronJob:定时任务的调度器

6.1 CronJob 概述

CronJob 基于 Job 控制器,按 Cron 表达式 定期创建 Job。它不直接管理 Pod,而是周期性地调用 Job 控制器。

复制代码
CronJob ──(按Cron触发)──→ Job ──(创建)──→ Pod
  定时调度                   任务管理              执行

典型应用场景:

  • 数据库增量备份(每天凌晨2点)
  • 证书续期检查(每周一)
  • 日志清理(每天)
  • 数据报表生成(每月1号)

6.2 CronJob 实战

yaml 复制代码
# cronjob-demo.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-hello
spec:
  schedule: "* * * * *"            # Cron 表达式:每分钟执行
  jobTemplate:
    spec:
      template:
        spec:
          volumes:
          - name: dt
            hostPath:
              path: /etc/localtime    # 同步宿主机时区
          containers:
          - name: hello
            image: busybox:1.28
            volumeMounts:
            - name: dt
              mountPath: /etc/localtime
            command:
            - /bin/sh
            - -c
            - date -R; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure
bash 复制代码
kubectl apply -f cronjob-demo.yaml

# 等待几分钟后查看(每分钟创建一个Job,每个Job创建一个Pod)
kubectl get cj,jobs,pods -o wide
# NAME                     SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE
# cronjob.batch/cj-hello   * * * * *   False     0        22s
#
# NAME                          COMPLETIONS   DURATION   AGE
# job.batch/cj-hello-29413519   1/1           3s         2m22s
# job.batch/cj-hello-29413520   1/1           3s         82s
# job.batch/cj-hello-29413521   1/1           3s         22s
#
# pod/cj-hello-29413519-xxx   Completed
# pod/cj-hello-29413520-xxx   Completed
# pod/cj-hello-29413521-xxx   Completed

6.3 Cron 表达式格式

复制代码
┌─── 分钟 (0 - 59)
│ ┌─── 小时 (0 - 23)
│ │ ┌─── 日 (1 - 31)
│ │ │ ┌─── 月 (1 - 12)
│ │ │ │ ┌─── 星期 (0 - 6, 0=周日)
│ │ │ │ │
* * * * *

常用表达式速查:

表达式 含义
*/5 * * * * 每 5 分钟
0 2 * * * 每天凌晨 2 点
0 2 * * 1 每周一凌晨 2 点
0 0 1 * * 每月 1 号零点
0 9-18 * * 1-5 工作日 9~18 点每小时
30 2 1,15 * * 每月 1 号和 15 号凌晨 2:30

6.4 CronJob 历史记录管理

yaml 复制代码
spec:
  successfulJobsHistoryLimit: 3    # 保留最近3个成功的Job
  failedJobsHistoryLimit: 1        # 保留最近1个失败的Job
  concurrencyPolicy: Forbid        # 禁止并发:上一个未完成时不创建新的
  # concurrencyPolicy: Allow       # 允许并发(默认)
  # concurrencyPolicy: Replace     # 替换:取消上一个,创建新的
  startingDeadlineSeconds: 200     # 错过调度后的宽容时间(秒)
  suspend: false                   # 暂停调度(true=暂停)

七、DaemonSet:每个节点的守护进程

7.1 DaemonSet 概述

DaemonSet(DS)确保每个(或特定)节点上运行一个 Pod 副本。当节点加入集群时自动创建 Pod,节点移除时自动回收 Pod。

复制代码
┌─────────────────────────────────────────┐
│           DaemonSet: node-exporter       │
│                                         │
│  ┌──────────┐  ┌──────────┐  ┌────────┐│
│  │ Worker-1 │  │ Worker-2 │  │ Worker-3││
│  │ [Pod-1]  │  │ [Pod-2]  │  │ [Pod-3] ││
│  └──────────┘  └──────────┘  └────────┘│
│                                         │
│  每个节点有且仅有一个 Pod                 │
│  新节点加入 → 自动创建 Pod               │
│  节点移除 → 自动回收 Pod                 │
└─────────────────────────────────────────┘

典型应用场景:

  • 监控采集:Prometheus Node Exporter、Zabbix Agent
  • 日志采集:Fluentd、Filebeat、Flume
  • 网络插件:Calico、Flannel(CNI 组件本身就是 DaemonSet)
  • 存储插件:Ceph OSD(Rook 部署的 Ceph 使用 DaemonSet)

7.2 DaemonSet 实战

yaml 复制代码
# ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds
spec:
  selector:
    matchLabels:
      apps: lingxi
  template:
    metadata:
      labels:
        apps: lingxi
    spec:
      volumes:
      - name: dt
        hostPath:
          path: /etc/localtime
      containers:
      - name: c1
        image: nginx:1.20
        volumeMounts:
        - name: dt
          mountPath: /etc/localtime
bash 复制代码
kubectl apply -f ds.yaml

# 每个 Worker 节点上创建一个 Pod
kubectl get pods -o wide
# NAME               READY   STATUS    IP             NODE
# ds-hgqt4   1/1     Running   10.100.2.203   worker233
# ds-lrf5x   1/1     Running   10.100.1.213   worker232

# 注意:Master 节点默认不调度(因为有污点)
kubectl get nodes
# NAME        STATUS   ROLES                  ...
# master231   Ready    control-plane,master   ← 有污点,DS Pod 不会调度到此
# worker232   Ready    <none>
# worker233   Ready    <none>

污点与 DaemonSet :如果需要在有污点的节点(如 Master)上也运行 DaemonSet Pod,需要在 Pod 模板中配置 tolerations。这是 DaemonSet 与 Deployment 的一个重要区别------DaemonSet 的调度需求更强,经常需要容忍污点。

7.3 DaemonSet 更新策略

yaml 复制代码
spec:
  updateStrategy:
    type: RollingUpdate           # 默认:逐个节点滚动更新
    rollingUpdate:
      maxUnavailable: 1           # 最多1个Pod不可用
    # type: OnDelete              # 手动模式:删除旧Pod后才创建新Pod
策略 行为 适用场景
RollingUpdate(默认) 自动逐个替换 Pod 常规更新
OnDelete 只有手动删除旧 Pod 后才创建新的 精确控制更新节奏

八、面试实战:通过 Pod 反向查找控制器

这是一个经典面试题:"给你一台服务器,Pod 处于 Pending 状态,如何排查并修复?"

8.1 核心思路

Pod 的配置问题不能直接修改 Pod 本身(控制器会自动回滚),必须找到管理该 Pod 的控制器并修改控制器。

8.2 操作步骤

bash 复制代码
# 第1步:使用 describe 查看 Pod 的事件
kubectl describe pod <pod-name>

# 第2步:查看 "Controlled By" 字段,找到控制器
kubectl describe pod ds-qxww6
# ...
# Controlled By:  DaemonSet/ds     ← 被DaemonSet管理

8.3 三层控制器链路

复制代码
Pod (被 RS 管理)
  └── Controlled By: ReplicaSet/deploy-568cf47956
        └── Controlled By: Deployment/deploy     ← 最终需要修改这个

不同控制器的 Controlled By:

控制器 Pod 的 Controlled By 下一步操作
Deployment ReplicaSet/xxx describe rs 找到 Deployment
DaemonSet DaemonSet/xxx 直接 edit ds
Job Job/xxx 直接 edit job
CronJob Job/xxx 找到 Job 后编辑 CronJob
StatefulSet StatefulSet/xxx 直接 edit sts
bash 复制代码
# Deployment 需要两层查找
kubectl describe pod deploy-568cf47956-92chs
# Controlled By: ReplicaSet/deploy-568cf47956

kubectl describe rs deploy-568cf47956
# Controlled By: Deployment/deploy

# 最终修改 Deployment
kubectl edit deploy deploy

8.4 Pod Pending 的六种常见原因

原因 排查方法 修复方式
镜像拉取失败 Events: Failed to pull image 修改控制器的 image
节点资源不足 Events: Insufficient cpu/memory 添加节点或降低 requests
亲和性不满足 Events: didn't match Pod's node affinity 修改 nodeAffinity 配置
存储卷未就绪 Events: persistentvolumeclaim not found 创建 PVC 或绑定 PV
污点不容忍 Events: had taint that pod didn't tolerate 配置 tolerations
nodeName 不存在 Events: node not found 修改 nodeName 或确认节点存在

九、控制器对比总结

维度 Deployment DaemonSet Job CronJob
Pod 数量 可指定 replicas 每个节点 1 个 指定 completions 由 Job 决定
生命周期 持续运行 持续运行 完成后终止 周期性完成
更新方式 滚动更新/重建 滚动更新/OnDelete N/A N/A
回滚 支持 不支持 不支持 不支持
自愈 Pod 挂了重建 Pod 挂了重建 失败重试 失败重试
restartPolicy Always Always Never/OnFailure Never/OnFailure
典型场景 Web 服务 监控/日志/网络 备份/迁移 定时任务
相关推荐
成为你的宁宁2 小时前
【基于 K8S+NFS 动态存储实战部署 Redis-Cluster 集群(含三主三从配置与访问配置)】
redis·容器·kubernetes
步步为营DotNet3 小时前
深挖.NET 11:.NET Aspire 在云原生应用状态管理的创新与实践
云原生·.net·wpf
Cat_Rocky3 小时前
Kubernetes etcd备份恢复
容器·kubernetes·etcd
Apache RocketMQ3 小时前
Apache RocketMQ 5.0 架构解析:如何基于云原生架构支撑多元化场景
云原生·架构·apache·rocketmq·java-rocketmq
少司府4 小时前
C++基础入门:深挖list的那些事
开发语言·数据结构·c++·容器·list·类型转换·类和对象
东北甜妹4 小时前
K8s etdc备份恢复 和 集群升级 证书更新
云原生·容器·kubernetes
念恒123064 小时前
Docker基础--CGroups资源控制实战(包含部分指令)
运维·docker·容器
万里侯4 小时前
户外露营攻略:远离城市喧嚣的完美周末
微服务·容器·k8s
万里侯4 小时前
云原生安全最佳实践:守护容器化应用的安全防线
微服务·容器·k8s