04-控制器模型

Kubernetes项目最核心的功能---编排

Pod这个看似复杂的API对象,其实就是对容器的进一步抽象和封装。Pod对象就是容器的升级版,它对容器进行了组合,添加了更多的属性和字段。

Kubernetes操作Pod的逻辑都是由控制器(controller)完成的。

0.1. 举个例子

创建一个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被创建。

0.2. kube-controller-manager

这个组件是一些列控制器的集合,查看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)。

0.2.1. 例子又来了

比如,现在有一种待编排的对象X,它有一个对应的控制器,那么就可以使用一段Go语言风格的伪代码,来描述这个控制循环

for {
  实际状态 := 获取集群中对象 X 的实际状态(Actual State)
  期望状态 := 获取集群中对象 X 的期望状态(Desired State)
  if 实际状态 == 期望状态{
    什么都不做
  } else {
    执行编排动作,将实际状态调整为期望状态
  }
}
  • 在具体实现中,实际状态往往来自Kubernetes集群本身。

比如:

  1. kubelet通过心跳汇报的容器状态和节点状态,
  2. 监控系统中保存的应用监控数据,
  3. 控制器主动收集的它感兴趣的信息,

这些都是常见的实际状态的来源。

  • 期望状态,一般来自于用户提交的YAML文件。

比如:

  1. Deployment对象中Replicas字段的值,这些信息都保存在Etcd中。

0.3. 控制器模型

以Deployment为例:

  1. Deployment控制器从Etcd中获取所有携带“app:nginx”标签的Pod,然后统计它们的数量,这就是实际状态
  2. Deployment对象的Replicas字段的值就是期望状态。
  3. Deployment控制器将两个状态做比较,然后根据比较结果,确定是创建Pod,还是删除已有的Pod。

一个Kubernetes对象的主要编排逻辑,实际上是在第三步的比对阶段完成的。

这个操作,通常被叫作调谐(Reconcile),调谐的过程被称作“Reconcile Loop”(调谐循环)或者“Sync Loop”(同步循环)。

调谐的结果往往是对被控制对象的某种写操作,如增加Pod或者删除已有Pod,或者增加Pod的某个字段。这是Kubernetes项目“面向API对象编程”的一个直观体现。

  • 控制器对象本身负责定义被管理对象的期望状态,比如Deployment里面replicas=2。
  • 被控制对象的定义,来自于一个模板,比如Deployment里面的template字段。

Deployment这个template字段里的内容,跟一个标准的Pod对象的API定义完全一样。所有被整个Deployment管理的Pod实例,都是根据这个template字段的内容创建的。

Deployment定义的template字段,在kubernetes项目中称为PodTemplate(Pod模板)。

大多数控制器,都会使用PodTemplate来统一定义它所要管理的Pod。也有其他类型的对象模板,比如Volume模板。

类似Deployment的控制器,实际上由上半部分的控制器定义(包括期望状态)和下半部分的被控制对象的模板组成:

image

在所有的API对象的Metadata里,都要有一个字段叫作ownerReference,用于保存这个API对象的拥有者的信息。


Kubernetes使用的“控制器模式”与“事件驱动模式”的区别与联系:(控制器视角

控制器模式事件驱动模式
主动被动
循环不断的尝试,最终达到申明一致一次性的操作,失败后难以处理
上次修改: 14 April 2020