《深入剖析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
的“污点”
- 一个节点在没进入Ready时,会被加上各类taint(污点)标记,例如若某节点未安装网络插件,则会被加上名为
-
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 对象中,负责并行控制的参数有两个:
- spec.parallelism,定义一个 Job 在同一时刻最多可以启动多少个 Pod 同时运行;
- spec.completions,定义 Job 至少要完成的 Pod 数目,即 Job 的最小完成数。
-
定时任务CronJob
- CronJob 与 Job 的关系,正如同 Deployment 与 Pod 的关系一样。CronJob 是一个专门用来管理 Job 对象的控制器。
- 它创建和删除 Job 的依据,是 spec.schedule 字段定义的、一个标准的Unix Cron格式的表达式。