-
指令式命令方式
创建 deployment 对象:
kubectlcreatedeploymentnginx-deployment--imagenginx-ntest
更改副本数:
kubectlscaledeploymentnginx-deployment--replicas5-ntest
-
指令式对象配置方式
首先创建配置文件定义,定义如图1-1所示:
图1-1 ngin.yaml配置
创建 deployment 对象:
kubectlcreate-fnginx.yaml
将配置文件中的replicas由2改成5,执行命令更改副本数:
kubectlreplace-fnginx.yaml
-
声明式对象配置方式
使用图1-1的配置,创建deployment对象:
kubectlapply-fnginx.yaml
将配置文件中的replicas由2改成5,执行命令更改副本数:
kubectlapply-fnginx.yaml
后两者对象配置的方式提供了用于创建新对象的模板,并且能够提供与更改关联的审核跟踪,命令除了实时内容外,不能提供记录源。所以在生产项目的情况下,我们使用 K8s 对象的方式往往是通过编写对应的
.yaml
文件交给 K8s(声明式API的形式),而不是直接使用指令式命令。
我们配置文件只是声明了想要创建的K8s对象的信息以及想要它们达到的期望状态,这是一种声明式API的交互方式。不同于吃饭、睡觉等明确的指令(这种方式也称为:命令式API),使用配置创建的对象的交互感觉类似顾客与实施方的交流模式,因为顾客跟实施方相比,往往不清楚为了达到目标而需要进行的操作,比如说:给我搭建一个标准的篮球场。
那么K8s对象在K8s API中是如何表示的,我们怎么用
.yaml
文件描述它们,当把一个
.yaml
文件提交给 K8s后,它究竟又是如何创建出一个K8s对象的呢?
1、K8s对象
K8s对象指的是K8s系统中持久化后的实体,K8s用这些实体去表示整个集群的运行状态。它们特别描述了以下信息:
-
哪些容器化应用在运行,以及运行在哪些节点上 -
可以被应用使用的资源 -
应用运行时的表现策略,如重启策略、升级策略以及容错策略。
2、K8s是如何描述和管理API对象的
大多数情况下,我们都以
.yaml
文件的形式提供这些信息。kubectl 在发起API请求时,再将这些信息转换成 JSON 格式。以
图1-1
举例,图中展示了使用
.yaml
来描述K8s对象的必需字段和对象规约,以下是其中必需字段的简要说明:
-
apiVersion - 创建该对象所使用的K8s API版本 -
kind - 想要创建的对象类别 -
metadata – 帮助表示对象的一些数据,包括一个name字符串、UID和可选的namespace -
spec – 你期望该对象所达到的状态
其中 spec 的精确格式对于不同类别的 K8s 对象来说往往是不同的,它是对管理对象详细描述的主体,会被 K8s 持久化到 etcd 中保存。如果
spec
被删除,那么该对象也会从系统中被删除。
图1-2 K8s的API结构
假定现在我们要创建一个
CronJob
对象,且它的 yaml 文件开头部分如下所示:
apiVersion:batch/v2alpha1kind:CronJob...
其中,
batch
就表示它的 API 组(Group),
v2alpha1
就是它的API版本(Version),
CronJob
即是它所属 API 资源类型(Resource)
conjobs
下的一个具体类别。而其整体创建流程下图1-3所示:
图1-3 持久化流程
➤ 提交阶段
➤ 过滤和前置处理阶段
➤ 路由查找阶段
-
匹配Group。对于 CronJob 这类非核心 API 对象,K8s 会在如图1-2所示的 /apis
层级内查找它的所属组(核心对象,如 Pod、Node,隶属于 /api 层级且它们的组为""),根据yaml
的开头信息,查找到/apis/batch
。 -
匹配版本号。接着,根据 v2alpha1
这个版本号进一步匹配到/apis/batch/ v2alpha1
这个路径,在 K8s 中,同种 API 对象可以有多个版本,这是 K8s 给予用户管理共存多版本 API 的手段。 -
匹配资源类型。最后匹配资源类型cronjobs,这时 K8s 便可明确知道自己所需要创建的具体资源类型为CronJob。
➤ 创建资源阶段
在获取到 CornJob 的类型定义后,API Server 会进行一个 Convert 工作:把用户提交的 yaml 转换成一个 Super Version 的对象,它是该 API 资源类型所有版本的字段全集,之后用户提交其他版本的 yaml,也都可以用这个 Super Version 对象来处理。
接着,再进行 Admit 处理,主要是在对象创建完成后,注入一些公共处理逻辑,例如加入一些标签 Label。最后,对这个对象里各个字段的合法性进行校验。
➤ 定义存储阶段
若通过了 Validate,会被 API Server 保存在名为 Registry 的结构中。它包含了对一个有效 K8s API 对象的定义。
3、控制器模式实现声明式API的sepc
图1-4控制循环
-
比较spec和status,若相同,不进行操作,继续进行1,否则输出不同点,进入2; -
控制器(Controller)根据不同点,对系统发出调控操作,系统执行操作,进入3; -
系统上报当前系统状态给传感器(Sensor)或者传感器主动拉取状态,输出当前状态status,返回1。
Reflector
、
Informer
、
Indexer
三个组件构成。
图1-5 Sensor组件
-
Reflector通过List和Watch操作从API Server 获取各个资源对象的状态。其中,List用来描述返回多个资源的集合,主要用于系统资源的全量更新;Watch用于客户端获取当前状态,然后订阅后续更改,主要用于系统资源的增量更新;
-
Reflector在获取新的资源数据后,会往Delta队列中推入一个Delta记录,这个记录包含了资源对象本身的信息以及资源对象事件的类型。Delta队列可以保证同一个对象在队列中仅有一条记录,从而避免Reflector重新List和Watch的时候产生重复的记录。
-
Informer组件不断地从Delta队列中弹出delta记录,然后把资源对象交给indexer。indexer把资源记录在一个默认使用命名空间做索引的缓存中,记录操作是线程安全的并且缓存是可以在Controller Manager或多个Controller间共享的。之后,informer再把这个事件交给事件回调函数。
Controller的主要流程如图1-6所示:
图1-6 controller组件
-
创建或者更新资源对象
-
调用其他的外部服务
-
worker处理失败,把资源的名字重新加入到工作队列中进行重试
现在假如我们需要将图1-1所配置的nginx副本由2扩容为3个进行举例说明,方便读者理解,整体流程如图1-7所示:
图1-7副本扩展整体流程图
总结
-
由于声明式API具有天然的记录初始和最终状态等特性,K8s采用了其作为最关键部分的API交互方式。
-
在生产环境中,对于K8s的管理往往是通过管理器API对象,而API对象又是通过yaml进行描述的,其中的spec和status是最为关键的信息,K8s会通过定位和路由把一个yaml描述的信息持久化到etcd中成为实体。
-
K8s所采用的控制器模式,是由声明式API驱动的。它是实现K8s声明式API的关键,资源对应的控制器结合感应器通过控制循环,异步地将控制系统向设置的终态趋近。
-
因为控制器是自主运行的,使得整体系统的自动化和无人值守成为可能。