Pod 这个看似复杂的 API 对象,实际上就是对容器的进一步抽象和封装而已。 说得更形象些,“容器”镜像虽然好用,但是容器这样一个“沙盒”的概念,对于描述应用来说, 还是太过简单了。

这就好比,集装箱固然好用,但是如果它四面都光秃秃的,吊车还怎么把这个集 装箱吊起来并摆放好呢? 所以,Pod 对象,其实就是容器的升级版。它对容器进行了组合,添加了更多的属性和字段。这就 好比给集装箱四面安装了吊环,使得 Kubernetes 这架“吊车”,可以更轻松地操作它。 而 Kubernetes 操作这些“集装箱”的逻辑,都由控制器(Controller)完成。我们曾经使用过 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

  

这个 Deployment 定义的编排动作非常简单,即:确保携带了 app=nginx 标签的 Pod 的个数,永 远等于 spec.replicas 指定的个数,即 2 个。

这就意味着,如果在这个集群中,携带 app=nginx 标签的 Pod 的个数大于 2 的时候,就会有旧的 Pod 被删除;反之,就会有新的 Pod 被创建。 这时,你也许就会好奇:究竟是 Kubernetes 项目中的哪个组件,在执行这些操作呢?

我在前面介绍 Kubernetes 架构的时候,曾经提到过一个叫作 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/
...

  

这个目录下面的每一个控制器,都以独有的方式负责某种编排功能。而我们的 Deployment,正是 这些控制器中的一种。 实际上,这些控制器之所以被统一放在 pkg/controller 目录下,就是因为它们都遵循 Kubernetes 项目中的一个通用编排模式,即:控制循环(control loop)。 比如,现在有一种待编排的对象 X,它有一个对应的控制器。那么,我就可以用一段 Go 语言风格 的伪代码,为你描述这个控制循环:

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

  

在具体实现中,实际状态往往来自于 Kubernetes 集群本身。 比如,kubelet 通过心跳汇报的容器状态和节点状态,或者监控系统中保存的应用监控数据,或者控 制器主动收集的它自己感兴趣的信息,这些都是常见的实际状态的来源。 而期望状态,一般来自于用户提交的 YAML 文件。

比如,Deployment 对象中 Replicas 字段的值。很明显,这些信息往往都保存在 Etcd 中。 接下来,以 Deployment 为例,我和你简单描述一下它对控制器模型的实现:

  • 1. Deployment 控制器从 Etcd 中获取到所有携带了“app: nginx”标签的 Pod,然后统计它们的 数量,这就是实际状态;
  • 2. Deployment 对象的 Replicas 字段的值就是期望状态;
  • 3. Deployment 控制器将两个状态做比较,然后根据比较结果,确定是创建 Pod,还是删除已有的 Pod(具体如何操作 Pod 对象,我会在下一篇文章详细介绍)。

可以看到,一个 Kubernetes 对象的主要编排逻辑,实际上是在第三步的“对比”阶段完成的。 这个操作,通常被叫作调谐(Reconcile)。这个调谐的过程,则被称作“Reconcile Loop”(调谐 循环)或者“Sync Loop”(同步循环)。 所以,如果你以后在文档或者社区中碰到这些词,都不要担心,它们其实指的都是同一个东西:控 制循环。 而调谐的最终结果,往往都是对被控制对象的某种写操作。

比如,增加 Pod,删除已有的 Pod,或者更新 Pod 的某个字段。这也是 Kubernetes 项目“面向 API 对象编程”的一个直观体现。 其实,像 Deployment 这种控制器的设计原理,就是我们前面提到过的,“用一种对象管理另一种 对象”的“艺术”。 其中,这个控制器对象本身,负责定义被管理对象的期望状态。比如,Deployment 里的 replicas=2 这个字段。

而被控制对象的定义,则来自于一个“模板”。比如,Deployment 里的 template 字段。 可以看到,Deployment 这个 template 字段里的内容,跟一个标准的 Pod 对象的 API 定义,丝毫 不差。而所有被这个 Deployment 管理的 Pod 实例,其实都是根据这个 template 字段的内容创建 出来的。

像 Deployment 定义的 template 字段,在 Kubernetes 项目中有一个专有的名字,叫作 PodTemplate(Pod 模板)。 这个概念非常重要,因为后面我要讲解到的大多数控制器,都会使用 PodTemplate 来统一定义它 所要管理的 Pod。更有意思的是,我们还会看到其他类型的对象模板,比如 Volume 的模板。 至此,我们就可以对 Deployment 以及其他类似的控制器,做一个简单总结了:

如上图所示,类似 Deployment 这样的一个控制器,实际上都是由上半部分的控制器定义(包括期 望状态),加上下半部分的被控制对象的模板组成的。

这就是为什么,在所有 API 对象的 Metadata 里,都有一个字段叫作 ownerReference,用于保存 当前这个 API 对象的拥有者(Owner)的信息。 那么,对于我们这个 nginx-deployment 来说,它创建出来的 Pod 的 ownerReference 就是 nginx-deployment 吗?或者说,nginx-deployment 所直接控制的,就是 Pod 对象么? 这个问题的答案,我就留到下一篇文章时再做详细解释吧。

总结

很多不同类型的容器编排功能,比如 StatefulSet、DaemonSet 等 等,它们无一例外地都有这样一个甚至多个控制器的存在,并遵循控制循环(control loop)的流 程,完成各自的编排逻辑。 实际上,跟 Deployment 相似,这些控制循环最后的执行结果,要么就是创建、更新一些 Pod(或 者其他的 API 对象、资源),要么就是删除一些已经存在的 Pod(或者其他的 API 对象、资源)。 但也正是在这个统一的编排框架下,不同的控制器可以在具体执行过程中,设计不同的业务逻辑, 从而达到不同的编排效果。 这个实现思路,正是 Kubernetes 项目进行容器编排的核心原理。在此后讲解 Kubernetes 编排功 能的文章中,我都会遵循这个逻辑展开,并且带你逐步领悟控制器模式在不同的容器化作业中的实 现方式。

Kubernetes — 控制器的更多相关文章

  1. Kubernetes 控制器

    在实际使用的时候并不会直接使用 Pod,而是会使用各种控制器来满足我们的需求,Kubernetes 中运行了一系列控制器来确保集群的当前状态与期望状态保持一致,它们就是 Kubernetes 的大脑. ...

  2. kubernetes 控制器详解【持续完善中】

    目录 资源创建详解 一:Pod及常用参数 1.简介 2.模板 3.删除pod 4.设置Pod主机名 5.镜像拉取策略(ImagePullPolicy) 二:RC 1.简介 2.模板 三:Deploym ...

  3. 图解kubernetes控制器StatefulSet核心实现原理

    StatefulSet是k8s中有状态应用管理的标准实现,今天就一起来了解下其背后设计的场景与原理,从而了解其适用范围与场景 1. 基础概念 首先介绍有状态应用里面的需要考虑的一些基础的事情,然后在下 ...

  4. 如何将云原生工作负载映射到 Kubernetes 中的控制器

    作者:Janakiram MSV 译者:殷龙飞 原文地址:https://thenewstack.io/how-to-map-cloud-native-workloads-to-kubernetes- ...

  5. (六)Kubernetes Pod控制器-ReplicaSet和Deployment和DaemonSet

    Pod控制器相关知识 控制器的必要性 自主式Pod对象由调度器调度到目标工作节点后即由相应节点上的kubelet负责监控其容器的存活状态,容器主进程崩溃后,kubelet能够自动重启相应的容器.但对出 ...

  6. Kubernetes的DaemonSet(上篇)

    背景 静儿作为美团容器化团队HULK的一员,经常需要和Kubernetes(k8s)打交道.第一次登陆node(宿主机)的时候,发现连续登陆几台都看到了Prometheus-Node-Exporter ...

  7. [转帖]Kubernetes及容器编排的总体介绍【译】

    Kubernetes及容器编排的总体介绍[译] 翻译自The New Stack<Kubernetes 生态环境>作者:JANAKIRAM MSV和 KRISHNAN SUBRAMANIA ...

  8. kubernetes 1.6 RBAC访问控制

    一.简介 之前,Kubernetes中的授权策略主要是ABAC(Attribute-Based Access Control).对于ABAC,Kubernetes在实现上是比较难用的,而且需要Mast ...

  9. 不吹不黑,今天我们来聊一聊 Kubernetes 落地的三种方式

    作者 | 王国梁  Kubernetes 社区成员与项目维护者原文标题<Kubernetes 应用之道:让 Kubernetes落地的"三板斧">,首发于知乎专栏:进击 ...

随机推荐

  1. [C# 设计模式] Adapter - 适配器模式(两种)

    Adapter - 适配器模式 序 现实生活中,我们常用到适配器. 你当前打开我这篇文章的笔记本电脑,电源的另一边不正连着一块适配器吗? 你平时想将三口插座插进二口插座里面,不也需要一个适配器吗? 整 ...

  2. Maven(十四)Maven 继承

    以Junit为例 由于junit的依赖的范围为test,所以在每一个项目中都必须配置一个junit. 为了统一管理方便,可以单独创建一个项目用来进行**统一管理**junit的版本 即在子项目中不设置 ...

  3. PHP 中的Trait

    概述 在PHP中有一种代码复用的技术, 因为单继承的问题, 有些公共方法无法在父类中写出, 而 Trait可以应对这种情况, 它可以定义一些复用的方法, 然后在你需要使用的类中将其引入即可. 刚开始的 ...

  4. Vue移动端项目模板

    一个集成移动端开发插件的Vue移动端模板包含1.css: 使用stylus开发css 集成reset样式文件 修改UI组件文件 统一样式处理(如主题色等)2.UI组件 使用热门的vant与mint-u ...

  5. 使用代码检查Dynamics 365中的备用键状态

    摘要: 微软动态CRM专家罗勇 ,回复304或者20190213可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 备用键(Al ...

  6. 关于ipv6被拒的问题

    遇到ipv6被拒,你首先要搭建一个ipv6的环境,进行测试一下,如果在ipv6环境下没有问题,那你就可以再次直接提交,或者重新打包提交.再次提交的时候,你可以录制一段在ipv6环境下运行的一段视频 上 ...

  7. WPF:在DataTemplate中使用DataType

    DataTemplate中的DataType的功能实际上和Style中的TargetType很类似. 在Style中,使用了TargetType之后,如果不定义Style的Key,那么这个Style将 ...

  8. Linux Logwatch的学习总结

    Logwatch功能介绍 Logwatch是一款Perl脚本编写的.开源的日志分析工具.它能对原始的日志文件进行解析并转换成结构化格式的文档,也能根据您的使用情况和需求来定制报告.Logwatch的特 ...

  9. 使用Spring.Net

    一:在Asp.net MVC中应该怎样使用Spring.Net? 1:先导入dll文件. 2:将案例中的Config文件夹拷贝到项目中. 3:修改Config文件夹中的相关的配置信息. 4:修改Web ...

  10. SQLServer之创建显式事务

    显式事务定义 显式事务以 BEGIN TRANSACTION 语句开始,并以 COMMIT 或 ROLLBACK 语句结束. 备注 BEGIN TRANSACTION 使 @@TRANCOUNT 按 ...