我们讲解了Pod这个API对象的各个字段,接下来就是Kuberenetes的编排功能
Pod这个复杂的API对象,其实是对容器的进一步抽象和封装而已
而且,比起原本的容器的一个简单的镜像,容器这个沙盒的概念,对于描述应用来说,太过于简单,就好比一个光滑的球,没法去抓
所以Pod,就是在这个球上面加了好多的抓取垫,方便人去搬运使用
而Kubernetes操作这些集装箱的逻辑,都由控制器完成,在之前,我们曾经说过Deployment这个基本的控制器对象
接下来,我们回顾一下这个名为nginx-deployment的例子
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
– name: nginx
image: nginx:1.7.9
ports:
– containerPort: 80
这个Deployement定义的编排很简单,就是确保app=nginx标签的pod的个数,等于spec.replicas指定的个数,就是2个
这就意味着,如果这个集群,携带的app=nginx标签的pod个数大于2个时候,就会有旧的Pod删除,不然就会有新的Pod创建
这就是Kube-controller-manager,这就是一系列控制器的集合
在kubernetes项目的pkg/controller目录
$ cd kubernetes/pkg/controller/
$ ls -d */
deployment/ job/ podautoscaler/
cloud/ disruption/ namespace/
replicaset/ serviceaccount/ volume/
cronjob/ garbagecollector/ nodelifecycle/ replication/ statefulset/ daemon/
…
在这个目录下面的每一个控制,都以独有的方式负责某种编排功能,Deployement就是其中一种
这些控制器统一放在pkg/controller目录下,就是一个通用的编排模式,控制循环
control loop
现在有一种需要编排的对象X,有一个对应的控制器,那么简单来说的编排流程如下
for {
实际状态 := 获取集群中对象X的实际状态(Actual State)
期望状态 := 获取集群中对象X的期望状态(Desired State)
if 实际状态 == 期望状态{
什么都不做
} else {
执行编排动作,将实际状态调整为期望状态
}
}
利用一个无限的for循环,来进行整个控制循环
而实际的容器装填,来自于K8s的集群本身,比如K8S根据心跳汇报的容器状态和节点状态,以及一些自定义的信息,来进行判断实际状态
而期望的状态,来自于用户自定义的YAML文件,Deployment对象在Replicas字段的值,这些值放在Etcd中
在Deployment为例,看下对控制器模型的实现
首先是从Etcd中获取了所有带有app:nginx的标签的Pod,然后统计数量
然后获取到了replicas的值,就是期望状态
然后进行判断,是创建Pod还是删除Pod
整个过程,一般叫做调谐 Reconcile,或者叫做 Reconcile Loop(调谐循环)或者Sync Loop(同步循环)
调谐的最终目的,就是对被控制对象的写操作,无论是追加还是删除Pod,或者是更新Pod的某个字段,都是K8S中面向API对象编程的一个体现
而被控制的对象,来自于一个模板,比如Deployment的template字段,可以看出,Deployment这个template字段中的内容,和一个标准的Pod对象的API定义,丝毫不差,这个Deployment管理处的Pod,都是根据这个template字段内容创建出来的
那么我们总结一下Deployment的模板
类似Deployment这样的一个控制器,实际上都是上半部分控制器定义,也就是期望状态
和下半部分的模板定义构成的
这就是为何,在所有API对象的metedata中,都有一个字段ownerReference,保存这个API对象的拥有者
对于,我们这个nginx-deployment来说,这个Pod的ownerReference是哪位呢?
在本篇文章中,我们以Deployment为例,分享了Kubernetes项目如何通过一个称为控制器模式的设计方式,统一的实现对不同的对象或者资源进行编排的操作
在K8s中,还有很多不同类型的容器编排功能,比如StatefulSet DaemonSet等,都是具有一个或者多个控制器的存在,并遵循这个控制循环的流程完成各自的编排控制
但是本质上,和Deployment相似,都是控制循环的最后执行结果,创建,更新一些Pod,要么就是删除一些已经存在的Pod
但是在这个统一的实现下,不同的控制器的实现思路,实现逻辑是不同的,从而达到不同的编排效果
控制器模式和事件驱动有什么区别吗?
控制器模式是一个无限循环的模型,而事件是单一的,每一次控制器的触发都对应着是一次事件
其次,有人说是select 和 epoll 的区别
或者说
事件驱动,对于控制器来说,是一种被动触发,只要触发了事件就行,至于成功与否,并不在意
控制器模式,对于控制器来说,是主动的,本身在不断的获取信息,知道是否能够生效
而且对于整个K8S系统来说,只有一个Deployment-Controller来管理这个系统的所有Deployment