《深入剖析kubernetes》学习笔记(3)——各类控制器

16. 控制器模式

  • kube-controller-manager组件,位于kubernetes架构下的master节点中,是一系列控制器的集合,在kubernetes源码的pkg/controller目录下,该目录下定义了一系列控制器

  • k8s所有控制器,都遵循相同的编排模式,即控制循环(control loop),伪代码为:

    for {
        实际状态 := 获取集群中对象 X 的实际状态(Actual State)
        期望状态 := 获取集群中对象 X 的期望状态(Desired State)
        if 实际状态 == 期望状态{
            什么都不做
        } else {
            执行编排动作,将实际状态调整为期望状态
        }
    }
    
  • 调谐(Reconcile)

    • 是指实际状态与期望状态相比较,并对实际状态进行调整以达到期望状态的过程。
    • 调谐的过程,则被称作“Reconcile Loop”(调谐循环)或者“Sync Loop”(同步循环)
  • 补充理解,“控制器模式”和“事件驱动”的差别

    • 可以类比select和epoll

17. 作业副本与水平扩展——deployment

  • 滚动更新是指将一个集群中正在运行的多个 Pod 版本,交替地逐一升级的过程

  • 牢记Deployment 的两层控制关系

    • Deployment 控制 ReplicaSet,一个ReplicaSet对应一个版本,
    • ReplicaSet根据replicas的值来控制 Pod的副本数
  • deployment可根据spec.RollingUpdateStrategy字段定义滚动更新策略 ,设置同一时刻扩展/收缩的数量

  • deployment定义中spec.revisionHistoryLimit,可以设置保留历史版本的数量,若为0,则无法进行滚动更新

  • deployment滚动更新常用命令

    • kubectl create -f <deployment-name>.yaml --record //record表示记录操作历史
      kubectl get deployments //查看deployment状态
      kubectl rollout status deployment/<deployment-name> //查看deployment状态变化
      kubectl get rs //查看deployment控制的ReplicaSet
      kubectl edit deployment/<deployment-name> //编辑ETCD中的API对象
      kubectl describe deployment <deployment-name> //查看deployment详情,event记录了滚动更新流程
      kubectl set image deployment/<deployment-name> <container-name>=<image-name>:<image-tag> //直接修改deployment所用镜像
      kubectl rollout undo deployment/<deployment-name> //回滚deployment到上一个版本
      kubectl rollout history deployment/<deployment-name> //查看历史版本操作记录
      kubectl rollout pause deployment/<deployment-name> //暂停deployment,此时操作不会新增replicaSet
      kubectl rollout resume deploy/<deployment-name> //恢复deployment
      
  • 两种应用发布的方式

    • 金丝雀发布(Canary Deployment),优先发布一台或少量机器升级,等验证无误后再更新其他机器。优点是用户影响范围小,不足之处是要额外控制如何做自动更新
    • 蓝绿发布(Blue-Green Deployment),2组机器,蓝代表当前的V1版本,绿代表已经升级完成的V2版本。通过LB将流量全部导入V2完成升级部署。优点是切换快速,缺点是影响全部用户。
  • deployment假设了其下的所有pod都是相同、平等的,无所谓顺序、无所谓运行的宿主机,这是deployment的缺陷,很多场景不能覆盖

18. 理解StatefulSet(1)

  • Deployment控制器模式所能控制的Pod默认是需要保持无状态的,故需要StatefulSet来管理“有状态应用实例”,kubernetes将状态分为两种:

    • 拓扑状态,即某些服务实例需要按照特定的顺序来启动,它们的拓扑结构上产生的依赖和状态
    • 存储状态,即不同的服务实例需要不同的存储数据,比如数据库的主从关系等
  • 拓扑状态,主要是为了实现Pod的创建、重启都按照固定的顺序进行,因此需要

    • (1)为Pod进行编号,来保证Pod操作顺序
    • (2)既然Pod之间是有拓扑关系的,那么各Pod提供的服务或是有差异的,因此有必要为每个Pod创建唯一的稳定的"网络标识"(DNS记录),作为它的访问入口
  • StatefulSet可以为Pod生成带编号的,例如web-0, web-1,并严格按照标号顺序创建(滚动更新时,按编号相反顺序更新)。

  • Headless Service(即在定义Service时,指定ClusterIP=none)

    • 直接用lable选择器就可以定位到对应的Pod实例
    • 为其所代理的所有 Pod 的 IP 地址绑定上固定格式的DNS记录...svc.cluster.local,服务方即可根据该DNS名字解析得到对应的Pod IP进行访问
    • 即使运行中某个Pod重启导致IP变化,新IP也能重新绑定到该DNS上(sevice的能力),从而不会对应用产生影响
  • 定义StatefulSet的yaml时,比deployment多一个servicename=<service-name>的字段,用来告诉StatefulSet控制器,用对应的Headless Service为Pod生成唯一DNS记录

19. 理解StatefulSet(2)

  • 为了实现StatefulSet对存储状态的管理,kubernetes提供了以下两个设计
    • Persistent Volume Claim(PVC)用于指定持久化卷访问声明,这是一个关于访问需求的描述对象
    • Persistent Volume(PV)持久化卷用于提供具体的持久化访问能力
  • PV和PVC的概念非常类似于接口和实现:PV是具体的实现,而PVC则充当接口。
  • StatefulSet管理存储状态时,需额外添加volumeCliameTemplates字段
    • 内部定义与一般的PVC定义一致
    • 表示该StatefulSet管理的所有Pod,都会声明一个PVC,该PVC的定义来自于volumeCliameTemplates字段
    • 每个Pod的PVC都会被分配一个编号<PVC-name>-<Pod-name>
  • 当某个Pod被删除后重启,仍能访问到原先PVC里的内容,原因是:
    • Pod对应的PVC所对应的PV里的内容不会被删除,而是持久化保存着
    • Pod被删除后,StatefulSet会留意到对应Pod停止,便会重启创建对应编号的Pod
    • Pod重启后,便会尝试重新关联相同编号的PVC,进而找到与该PVC绑定的PV
  • 理解StatefulSet核心思路
    • StatefulSet可以看作一种特殊的Deployment
    • 为了区分各Pod,以保证Pod创建、重启的顺序,在创建Pod时,为每一个Pod打上了一个独特的编号(StatefulSet名-序号)
    • 为了保证每个Pod的访问入口的唯一稳定,利用Headless Service,为每一个Pod分配唯一并且稳定的“网络标识”(DNS名字)
    • 为了确保每个Pod对应的存储内容不丢失,利用PV和PVC,为每一个Pod分配唯一并且稳定的”存储空间标识“(PVC名字)

21. 守护进程DaemonSet

  • 基本概念

    • DaemonSet也是一种特殊的Controller,类似于操作系统中的守护进程,作用是在kubernetes集群上运行一些Daemon Pod,并确保在集群中的每一个节点上都有且只有一个这样的Daemon Pod
    • 当有新的节点加入 Kubernetes 集群后,该 Pod 会自动地在新节点上被创建出来;而当旧节点被删除后,它上面的 Pod 也相应地会被回收掉。
    • 应用场景包括网络插件、存储插件的Agent组件,以及各种监控、日志组件等。
  • DaemonSet是如何保证在每个节点上有且唯一的?

    • 采用控制器模式,遍历Etcd中的所有Node,检查每个Node中是否有对应的Pod,如果没有就新建一个,有多余的删除掉。
  • 在指定Node上新创建Pod的方法?

    • 在Pod定义中加上NodeSelector字段或者NodeAffinity字段(推荐nodeAffinity,因nodeSelector已接近废弃)
    • DaemonSet Controller会在创建 Pod 的时候,自动在这个 Pod 的 API 对象里,加上 nodeAffinity 定义
  • 如何在还没有完全进入Ready状态的kubernetes集群上部署DaemonSet?

    • 一个节点在没进入Ready时,会被加上各类taint(污点)标记,例如若某节点未安装网络插件,则会被加上名为node.kubernetes.io/network-unavailable,效果为NoSchedule的“污点”
    • DaemonSet依靠sepc.toleration的声明,可以允许对某个带有unschedulable的taint的节点进行调度。
    • 补充:master节点上默认会有node.kubernetes.io/network-unavailable的“污点”
  • DaemonSet的版本管理依靠ControllerRevision实现。(ControllerRevision作为k8s中的通用版本管理对象,StatefulSet也使用它进行版本管理)

22. 离线业务:Job和CronJob

  • 在线业务和离线业务

    • Deployment、StatefulSet,以及 DaemonSet都属于“在线业务”,或者叫长作业(Long running task)
    • 一次性执行的任务,叫“离线业务”,或者叫计算作业(Batch job)
  • Job对象管理的Pod,其spec.restartPolicy只能被设置为Never或者OnFailure,(在Deployment中只能被设置为Always),从而确保pod计算完成后不会被重启。

  • job对象的spec.backoffLimit 字段里定义了重试次数上限,避免失败后无限重启

  • 在 Job 对象中,负责并行控制的参数有两个

    1. spec.parallelism,定义一个 Job 在同一时刻最多可以启动多少个 Pod 同时运行;
    2. spec.completions,定义 Job 至少要完成的 Pod 数目,即 Job 的最小完成数。
  • 定时任务CronJob

    • CronJob 与 Job 的关系,正如同 Deployment 与 Pod 的关系一样。CronJob 是一个专门用来管理 Job 对象的控制器。
    • 它创建和删除 Job 的依据,是 spec.schedule 字段定义的、一个标准的Unix Cron格式的表达式。
posted @ 2021-02-02 13:57  lwjj  阅读(258)  评论(0编辑  收藏  举报