一. 什么是控制器

官方文档:

https://v1-30.docs.kubernetes.io/zh-cn/docs/concepts/workloads/controllers/

控制器也是管理pod的一种手段

  • 自主式pod:pod退出或意外关闭后不会被重新创建
  • 控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目

Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod,当建立控制器后,会把期望值写入etcd,k8s中的apiserver检索etcd中我们保存的期望状态,并对比pod的当前状态,如果出现差异代码自驱动立即恢复


  控制器相当于包工头 / 管理员。你只告诉包工头你的期望状态(我要运行几个什么样程序),控制器持续对比「期望状态」和「集群当前真实状态」,不一样就自动修复。
逻辑:你写 yaml 定义期望 → 存入 etcd → 控制器不断巡检,现实达不到预期就调整。


举生活例子:
你开奶茶店,你给包工头说:店里必须保持 3 个店员在岗。

  • 如果 1 个人请假走了,包工头立刻再招 1 个人补齐;
  • 如果一下子来了 5 个人,包工头就辞退多余 2 个人。
  • 这个包工头,就是 K8s 控制器。

K8s 有不同类型包工头,擅长的工作不一样。

二. 控制器常用类型

控制器名称 控制器用途
Replication Controller 比较原始的 pod 控制器,已经被废弃,由 ReplicaSet 替代
ReplicaSet ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行
Deployment 一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力
DaemonSet DaemonSet 确保全指定节点上运行一个 Pod 的副本
StatefulSet StatefulSet 是用来管理有状态应用的工作负载 API 对象。
Job 执行批处理任务,仅执行一次任务,保证任务的一个或多个 Pod 成功结束
CronJob Cron Job 创建基于时间调度的 Jobs。
HPA 全称 Horizontal Pod Autoscaler 根据资源利用率自动调整 service 中 Pod 数量,实现 Pod 水平自动缩放

三 replicaset控制器

replicaset功能

ReplicaSet(副本控制器):只管保证 N 个 Pod 活着
职责:维持指定数量 Pod 副本持续运行,靠标签匹配管控 Pod。
现在生产几乎不直接用 ReplicaSet,Deployment 底层在调用它。
生活举例:
奶茶店规定,店里固定要有 3 名店员在岗。
• 有店员辞职,立刻新招一人补上;
• 如果一下子来了 5 个店员,开除多余 2 个;
• 识别员工不靠名字,靠工牌标签app:shop。

  • ReplicaSet 是下一代的 Replication Controller,官方推荐使用ReplicaSet

  • ReplicaSet和Replication Controller的唯一区别是选择器的支持,ReplicaSet支持新的基于集合的选择器需求

  • ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行

  • 虽然 ReplicaSets 可以独立使用,但今天它主要被Deployments 用作协调 Pod 创建、删除和更新的机制

#如果你手动把其中一个 Pod 的标签改掉,ReplicaSet 发现这个 Pod 不再属于自己管理,就会新建一个 Pod 补齐副本数;改标签的那个 Pod 就变成 “流浪 Pod”,不再被管控。

缺点:ReplicaSet 只会保证数量,不支持滚动更新、版本回滚。直接用它很不方便,所以交给 Deployment 封装调用。

replicaset参数说明

参数名称 字段类型 参数说明
spec Object 详细定义对象,固定值就写 Spec
spec.replicas integer 指定维护 pod 数量
spec.selector Object Selector 是对 pod 的标签查询,与 pod 数量匹配
spec.selector.matchLabels string 指定 Selector 查询标签的名称和值,以 key: value 方式指定
spec.template Object 指定对 pod 的描述信息,比如 label 标签,运行容器的信息等
spec.template.metadata Object 指定 pod 属性
spec.template.metadata.labels string 指定 pod 标签
spec.template.spec Object 详细定义对象
spec.template.spec.containers list Spec 对象的容器列表定义
spec.template.spec.containers.name string 指定容器名称
spec.template.spec.containers.image string 指定容器镜像

通俗理解:
spec = 期望配置;
selector = 找哪些 Pod 归我管(筛选);
template = 新建 Pod 时用什么模板去创建 Pod。

建立控制器

[root@master controler]# kubectl create deployment webcluster --image myapp:v1  --dry-run=client -o yaml  > replica.yml

[root@master controler]# vim  replica.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  labels:
    app: webcluster
  name: webcluster
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webcluster
  template:
    metadata:
      labels:
        app: webcluster
    spec:
      containers:
      - image: myapp:v1
        name: myapp
[root@master controler]# kubectl apply -f replica.yml

#eplicaSet 是 Deployment 的子资源。
Deployment 控制器会不停做调谐(reconcile):

  • 你 scale 把 RS 改成 4;
  • Deployment 一看:我自己 spec.replicas=2,和底层 RS 不一致;
  • 测试功能立刻强制把 RS 的 DESIRED 重新改回 2。

测试功能

[root@master ~]# vim relica.yml
spec:
  replicas: 4
[root@master ~]# kubectl apply -f replica.yml

四.Deployment(会版本升级的包工头)


  • Deployment控制器并不直接管理pod,而是通过管理ReplicaSet来间接管理Pod
  • Deployment管理ReplicaSet,ReplicaSet管理Pod
  • Deployment 为 Pod 和 ReplicaSet 提供了一个申明式的定义方法
  • 在Deployment中ReplicaSet相当于一个版本

举例:奶茶店店员分批更换工作服。

  • 支持:滚动更新、版本回滚、扩容缩容、更新暂停。
  • 更新逻辑:新建新版本 RS,逐步启动新 Pod、销毁旧 Pod,业务不中断。
  • 链路关系:Deployment → ReplicaSet → Pod

常用命令

kubectl rollout history deploy xxx
kubectl rollout undo deploy xxx

监控

[root@master ~]# watch -n 1 " kubectl get pods   --show-labels;echo ====;kubectl get replicasets.apps"

建立deployment控制器

[root@master controler]# kubectl create deployment webcluster --image myapp:v1  --dry-run=client -o yaml  > dep.yml
[root@master controler]# vim dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: webcluster
  name: webcluster
spec:
  minReadySeconds: 5
  replicas: 2
  selector:
    matchLabels:
      app: webcluster
  template:
    metadata:
      labels:
        app: webcluster
    spec:
      containers:
      - image: myapp:v1
        name: myapp

[root@master controler]# kubectl apply -f dep.yml

#发布服务
[root@master ~]#  kubectl expose deployment webcluster --port 80 --target-port 80
service/webcluster exposed
[root@master ~]# kubectl describe  services webcluster
Name:                     webcluster
Namespace:                default
Labels:                   app=webcluster
Annotations:              <none>
Selector:                 app=webcluster
Type:                     ClusterIP
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.109.193.88
IPs:                      10.109.193.88
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
Endpoints:                10.244.2.115:80,10.244.1.171:80
Session Affinity:         None
Internal Traffic Policy:  Cluster
Events:                   <none>
[root@master ~]# curl 10.109.193.88
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

升级和回滚

#注意这里面用的是我自己的镜像,想要实验可以从我资源下载

#升级
[root@master ~]# vim dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: webcluster
  name: webcluster
spec:
  minReadySeconds: 5
  replicas: 2
  selector:
    matchLabels:
      app: webcluster
  template:
    metadata:
      labels:
        app: webcluster
    spec:
      containers:
      - image: myapp:v2  #升级版本
        name: myapp
[root@master ~]#  kubectl apply -f dep.yml
deployment.apps/webcluster configured
[root@master ~]# curl 10.109.193.88
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

#回滚
[root@master controler]# vim dep.yml
。。。。
spec:
  minReadySeconds: 5
  replicas: 2
  selector:
    matchLabels:
      app: webcluster
#  strategy: {}
  template:
    metadata:
      labels:
        app: webcluster
    spec:
      containers:
      - image: myapp:v1			#回滚为版本1
        name: myapp
。。。。
[root@master ~]# kubectl apply -f dep.yml
[root@master ~]# curl  10.109.193.88
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

版本更新管理及优化

[root@master ~]# vim dep.yml
spec:
  minReadySeconds: 5
  replicas: 6				#把pod数量设定为6方便观察
  selector:

[root@master ~]# kubectl apply -f dep.yml
deployment.apps/webcluster configured

查看更新策略信息

[root@master ~]# kubectl describe deployments.apps webcluster
RollingUpdateStrategy:  25% max unavailable, 25% max surge
[root@master ~]# vim dep.yml
,,,,,,,
spec:
  minReadySeconds: 5
  replicas: 6
  selector:
    matchLabels:
      app: webcluster
  strategy:
    rollingUpdate:
      maxSurge: 1					#更新时pod数量最多比期望值多一个
      maxUnavailable: 0				#不能使用pod数量比期望值数量多0
  template:
    metadata:
      labels:
        app: webcluster
    spec:
      containers:
      - image: myapp:v1
        name: myapp


[root@master ~]# kubectl apply -f dep.yml

更新暂停和恢复

[root@master ~]# kubectl rollout history deployment webcluster
deployment.apps/webcluster
REVISION  CHANGE-CAUSE
1        <none>
2        <none>

[root@master ~]# kubectl rollout pause deployment webcluster  #暂停更新
deployment.apps/webcluster paused
[root@master ~]# vim dep.yml

      containers:
      - image: myapp:v2
        name: myapp

[root@master ~# kubectl apply -f dep.yml		#执行成功。但更新过程在监控中没出现
deployment.apps/webcluster configured


[root@master ~# kubectl rollout history deployment webcluster
deployment.apps/webcluster
REVISION  CHANGE-CAUSE
1         <none>
2       <none>

[root@master ~]# kubectl rollout resume deployment webcluster			#开启更新
deployment.apps/webcluster resumed

[root@master ~r]# kubectl rollout history deployment webcluster
deployment.apps/webcluster
REVISION  CHANGE-CAUSE
2      <none>
3        <none>

#适用场景:web 网站、微服务,无状态业务,90% 业务都是用 Deployment。

关系记忆:Deployment → ReplicaSet → Pod

五.DaemonSet(每台机器都要跑一个 Pod)

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, 也会为他们新增一个 Pod ,当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod

DaemonSet 的典型用法:

  • 在每个节点上运行集群存储 DaemonSet,例如 glusterd、ceph。

  • 在每个节点上运行日志收集 DaemonSet,例如 fluentd、logstash。

  • 在每个节点上运行监控 DaemonSet,例如 Prometheus Node Exporter、zabbix agent等

  • 一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使用

  • 一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求

举例:写字楼每一间办公室配备一名保洁。

  • 新增节点,自动创建 Pod;节点删除,自动回收 Pod。
  • 每个节点最多运行 1 个 Pod,不需要写 replicas 副本数。

典型业务:

  • 节点监控 node‑exporter、日志收集 fluentd、存储客户端。

如果要调度到 master 节点,需要配置容忍污点tolerations。

[root@master ~]# kubectl create deployment daemonset --image myapp:v1 --dry-run=client -o yaml  > daemonset.yml
[root@master controler]# vim daemonset.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: daemonset
  name: daemonset
spec:
  selector:
    matchLabels:
      app: daemonset
  template:
    metadata:
      labels:
        app: daemonset
    spec:
      containers:
      - image: myapp:v1
        name: myapp

另外开启一个主机node3,并设定在初始化集群时的所有设定确保所有服务的开启
#在master中重新生成集群主机注册时需要的token

[root@master ~]# kubeadm  token create --print-join-command
kubeadm join 172.25.254.100:6443 --token 8s1czw.0l8yqaby2nh25sfz --discovery-token-ca-cert-hash sha256:4933cf96a92b2d06102614ffa2421b2ec4ab4071bc1bfd68cfdaf99a8754f84d


#在node3上面
[root@node3 ~]#  kubeadm join 172.25.254.100:6443 --token 8s1czw.0l8yqaby2nh25sfz --discovery-token-ca-cert-hash sha256:4933cf96a92b2d06102614ffa2421b2ec4ab4071bc1bfd68cfdaf99a8754f84d--cri-socket  unix:///var/run/cri-dockerd.sock




#查看集群
[root@master ~]# kubectl  get nodes
NAME     STATUS   ROLES           AGE    VERSION
master   Ready    control-plane   8h   v1.35.7
node1    Ready    <none>          8h   v1.35.7
node2    Ready    <none>          8h   v1.35.7
node3    Ready    <none>          45s  v1.35.8

#不要设置 replicas 副本数,DaemonSet 副本数由集群节点数量决定。

六.Job控制器(一次性批处理任务,干完就下班)

Job 用来跑一次性任务,Pod 执行完成退出,Job 标记任务完成;失败会重启 / 重建 Pod 重试,不适合 7×24 小时常驻的 web 服务。

举例:财务年底一次性核算全年账单,任务跑完就下班,不需要常驻运行。
参数:

  • completions:需要成功完成任务数量
  • parallelism:最大并发 Pod 数量
  • backoffLimit:失败最大重试次数

Job 的 restartPolicy 只能写Never / OnFailure,禁止Always。

#需要上传镜像
[root@master ~]# wget -c -O perl-5.34.tar.gz https://www.cpan.org/src/5.0/perl-5.34.0.tar.gz
[root@master ~]# docker load -i perl-5.34.tar.gz
[root@master ~]# docker tag perl:5.34.0 reg.timinglee.org/library/perl:5.34.0
[root@master ~]# docker push reg.timinglee.org/library/perl:5.34.0

[root@master controler]# kubectl create job job --image perl:5.34.0 --dry-run=client -o yaml > job.yml
[root@master controler]# vim job.yml
apiVersion: batch/v1
kind: Job
metadata:
  name: testjob
spec:
  completions: 6
  parallelism: 2
  backoffLimit: 4
  template:
    spec:
      containers:
      - image: busybox
        name: testjob
        command: ["/bin/sh", "-c"]
        args:
        - |
          echo this is testjob message
          sleep 10
      restartPolicy: Never


[root@master controler]# kubectl apply -f job.yml
job.batch/job created

[root@k8s-master controller]# kubectl logs pods/testjob-4cdlr
this is testjob message

restartPolicy 重点:
Never:Pod 失败,直接新建 Pod 重试,旧失败 Pod 保留;
OnFailure:容器失败,在同一个 Pod 内部重启容器,不新建 Pod;
禁止Always,Job 是一次性任务,不能永远重启。

七.Cronjob控制器(定时任务,定时触发 Job)

  • Cron Job 创建基于时间调度的 Jobs。
  • CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,
  • CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。
  • CronJob可以在特定的时间点(反复的)去运行job任务。

举例:每天凌晨 3 点自动执行数据库备份。

  • CronJob=Linux crontab + Job。
  • 到定时时间,自动创建 Job 对象,Job 拉起 Pod 执行任务。

schedule 格式:分 时 日 月 周

[root@master ~]# kubectl create cronjob cronjob --image busybox  --schedule "* * * * *" --dry-run=client -o yaml > cronjob.yml
[root@master ~]# vim cronjob.yml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob
spec:
  jobTemplate:
    metadata:
      name: cronjob
    spec:
      template:
        spec:
          containers:
          - image: busybox
            name: cronjob
            command:
              - /bin/sh
              - -c
              - echo "Glad you've read this article. Keep it up!"
          restartPolicy: OnFailure
  schedule: '* * * * *'


[root@master ~]# kubectl apply -f cronjob.yml		

总结

控制器 核心比喻 核心用途
ReplicaSet 店员数量管理员 保证 N 个 Pod 运行,底层组件,不直接使用
Deployment 支持换装升级的店长 无状态 web 业务,滚动更新、版本回滚(最常用)
DaemonSet 每间办公室的保洁 每个节点跑 1 个 Pod,日志、监控、存储代理
Job 一次性财务算账 一次性批处理任务,任务跑完结束
CronJob 闹钟定时触发财务 定时执行批处理,定时备份、定时统计

Deployment 管更新,DaemonSet 节点个个蹲;Job 干完就下班,CronJob 到点才开工。

补充小思考题(面试常问)

Q:Deployment 底层是 RS,为什么不直接用 RS?
A:RS 只保证 Pod 数量,没有版本滚动更新、回滚功能。Deployment 封装 RS,把版本管理做了。
Q:DaemonSet 能不能写 replicas?
A:不能,副本数量等于匹配成功的节点数目。
Q:Job 的 restartPolicy 能不能写 Always?
A:不能,Job 是一次性任务,Always 会导致任务无限重启。

感谢各位耐心看完这篇博客。写作过程也是自我梳理复盘的过程,难免会有考虑不周的地方,欢迎大家批评指正。希望这篇内容能够对你有所帮助,我们下篇博文再会。

更多推荐