Kubernetes项目最核心的功能---编排。
Pod这个看似复杂的API对象,其实就是对容器的进一步抽象和封装。Pod对象就是容器的升级版,它对容器进行了组合,添加了更多的属性和字段。
Kubernetes操作Pod的逻辑都是由控制器(controller)完成的。
创建一个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
这个Deployment定义的编排动作:确保携带了app=nginx标签的Pod的个数,永远等于spec.replicas指定的个数,即2个。
如果集群中携带app=nignx标签的Pod的个数大于2,就会有旧的Pod被删除,反之,就会有新的Pod被创建。
这个组件是一些列控制器的集合,查看kubernetes项目中pkg/controller目录:
$ cd kubernetes/pkg/controller/
$ ls -d */
deployment/ job/ pod
scaler/
cloud/ disruption/ namespace/
replicaset/ serviceaccount/ volume/
cronjob/ garbagecollector/ nodelifecycle/
replication/ statefulset/ daemon/
...
这个目录下的每一个控制器,都以独有的方式负责某种编排功能。
这些控制器之所以都被统一放在pkg/controller目录下,是因为它们都遵循kubernetes项目中的一个通用编排模式,即:控制循环(controller loop)。
比如,现在有一种待编排的对象X,它有一个对应的控制器,那么就可以使用一段Go语言风格的伪代码,来描述这个控制循环:
for {
实际状态 := 获取集群中对象 X 的实际状态(Actual State)
期望状态 := 获取集群中对象 X 的期望状态(Desired State)
if 实际状态 == 期望状态{
什么都不做
} else {
执行编排动作,将实际状态调整为期望状态
}
}
比如:
这些都是常见的实际状态的来源。
比如:
以Deployment为例:
一个Kubernetes对象的主要编排逻辑,实际上是在第三步的比对阶段完成的。
这个操作,通常被叫作调谐(Reconcile),调谐的过程被称作“Reconcile Loop”(调谐循环)或者“Sync Loop”(同步循环)。
调谐的结果往往是对被控制对象的某种写操作,如增加Pod或者删除已有Pod,或者增加Pod的某个字段。这是Kubernetes项目“面向API对象编程”的一个直观体现。
Deployment这个template字段里的内容,跟一个标准的Pod对象的API定义完全一样。所有被整个Deployment管理的Pod实例,都是根据这个template字段的内容创建的。
Deployment定义的template字段,在kubernetes项目中称为PodTemplate(Pod模板)。
大多数控制器,都会使用PodTemplate来统一定义它所要管理的Pod。也有其他类型的对象模板,比如Volume模板。
类似Deployment的控制器,实际上由上半部分的控制器定义(包括期望状态)和下半部分的被控制对象的模板组成:
在所有的API对象的Metadata里,都要有一个字段叫作ownerReference,用于保存这个API对象的拥有者的信息。
Kubernetes使用的“控制器模式”与“事件驱动模式”的区别与联系:(控制器视角)
控制器模式 | 事件驱动模式 |
---|---|
主动 | 被动 |
循环不断的尝试,最终达到申明一致 | 一次性的操作,失败后难以处理 |