声明式API vs 命令时API

计算机系统是分层的,也就是下层做一些支持的工作,暴露接口给上层用。注意:语言的本质是一种接口。

计算机的最下层是CPU指令,其本质就是用“变量定义+顺序执行+分支判断+循环”所表达的逻辑过程。计算机应用的最上层是实现人类社会的某种功能。所以所有计算机编码的过程,就是用逻辑表达现实的过程。层与层之间定义的借口,越接近现实的表达就叫越“声明式”(declarative),越接近计算机的执行过程就叫越“命令式”(imperative)。注意这不是绝对的概念,而是相对的概念。

当接口越是在表达“要什么”,就是越声明式;越是在表达“要怎样”,就是越命令式。SQL就是在表达要什么(数据),而不是表达怎么弄出我要的数据,所以它就很“声明式”。C++就比C更声明式,因为面向对象本身就是一种声明式的体现。HTML也很声明式,它只描述我要一张什么样的表,并不表达怎么弄出一张表。

越是声明式,意味着下层要做更多的东西,或者说能力越强。也意味着效率的损失。越是命令式,意味着上层对下层有更多的操作空间,可以按照自己特定的需求要求下层按照某种方式来处理。

Kubernetes声明式API

想要使用Kubernetes 的 API 对象,需要编写一个对应的 YAML 文件交给 Kubernetes,而声明式API,则为kubectl apply 命令。而先 kubectl create,再 replace 的操作,称为命令式配置文件操作,并不是声明式API。

kube-apiserver 在响应命令式请求(如kubectl replace)的时候, 一次只能处理一个写请求,否则会有产生冲突的可能;而对于声明式请求(如kubectl apply),一次能处理多个写操作,并且具备 Merge 能力。

声明式 API是 Kubernetes 项目编排能力“赖以生存”的核心所在:

  • 首先,“声明式”就是提交一个定义好的API对象来声明所期望的状态是什么

  • 其次,声明式API允许有多个API写端,以PATCH的方式对API对象进行修改,而无需关心本地原始YAML文件的内容

    RESTful 使用POST来创建一个资源,使用PUT或者PATCH来更新一个资源
    
    区别是:
    – PUT用来整体更新一个资源,所以请求中必须包含完整的资源信息。如果缺少部分信息,会导致这部分数据被更新为NULL。
    – PATCH则是部分更新。仅更新提供的字段,请求中缺少的字段仍保持不变
  • 最后,也是最重要的,有了上述两个能力,Kubernetees项目才可以基于对API对象的增、删、改、查在完全无需外界干预的情况下,完成对“实际状态”和“期望状态”的调谐(Reconcile)过程。

工作原理

首先知道一下一个 API 对象在 Etcd 里的完整资源路径,是由:Group(API 组)、 Version(API 版本)和 Resource(API 资源类型)三个部分组成的,可以用如下图的树形结构表示出来:

API对象的组织方式是层层递进的,Kubernetes会对Group、Version和Resource进行解析,也就是层层匹配,得到相应的对象定义,如Cronjob(Pod、Node 等核心API对象不需要Group,直接匹配Version)。

把YAML 文件提交给 Kubernetes 之后,创建出 API 对象的流程:以创建 CronJob为例

  1. 发起创建CronJob的POST请求后,编写的YAML的信息就被提交给api-server

  2. Api-server过滤这个请求,完成一些前置性的工作,比如授权、超时处理、审计等

  3. 请求进入mux和routes流程,mux和routees是api-server完成url和handler绑定的场所,api-server的Handler要做的事情就是按照层层匹配的过程,找到对应的CronJob类型定义

  4. Api-server根据crontJob类型定义,使用用户提交的YAML文件里的字段,创建一个CrontJob对象

    Api-server会进行一个convert工作,即把用户提交的YAML文件转换成一个叫做Super Version的对象,它正是该API资源类型所有版本的字段全集,这样用户提交的不同版本的YAML就都可以用这个Super Version对象来进行处理了

  5. 先后进行admission()和validation()操作

    Admission Controller和Initializer都属于Admission的内容,Validation负责验证这个对象里的各个字段是否合法,这个被验证过的API对象,都保存在来api-server里一个叫做Registry的数据结构中,也就是说只要一个API对象的定义能在Registry里查到,他就是一个有效的Kubernetes API对象

  6. 把验证过的API对象转换成用户最初提交的版本,进行序列化操作,并调用Etcd的API把它保存起来

自定义API对象

如果想要添加自定义API资源类型,建议使用CRD( Custom Resource Definition),它允许用户在 Kubernetes 中添加一个跟 Pod、Node 类似的、新的 API 资源类型,即:自定义 API 资源。

使用CRD创建出自定义API对象后,就是为这个 API 对象编写一个自定义控制器(Custom Controller),这样, Kubernetes 才能根据 自定义 API 对象的“增、删、改”操作,在真实环境中做出相应的响应。

编写自定义控制器分为三个过程:编写 main 函数、编写自定义控制器的定义,以编写控制器里的业务逻辑。

自定义控制器工作流程

  1. 首先从 Kubernetes 的 APIServer 里获取它所关心的对象,也就是自定义的控制器对象。这个操作,依靠的是一个叫作 Informer(通知器)的代码库完成的;Informer 与 API 对象是一一对应的,所以需要传递给自定义控制器一个Informer;

    Informer是一个带有本地缓存和索引机制的、可以注册EventHandler 的 client。它是自定义控制器跟 APIServer 进行数据同步的重要组件。

    创建Informer的时候需要传一个Client,Informer 正是使用Client,跟 APIServer 建立了连接;真正负责维护这个连接的是 Informer 所使用的 Reflector 包。

    Reflector 使用的是一种叫作ListAndWatch的方法,来“获取”并“监听”这些API对象实例的变化(Informer通过 ListAndWatch,把 APIServer 中的 API 对象缓存在了本地,并负责更新和维护这个缓存。)在 ListAndWatch 机制下,一旦 APIServer 端有新的API对象实例被创建、删除或者更新, Reflector 都会收到“事件通知”;这时,该事件及它对应的 API 对象这个组合,就被称为增量 (Delta),它会被放进一个 Delta FIFO Queue(即:增量先进先出队列)中;Informe 会不断地从 Delta FIFO Queue 里读取(Pop)增量。每拿到一个增量,Informer 就会判断这个增量里的事件类型,然后创建或者更新本地对象的缓存;这个缓存,在 Kubernetes 里一般被叫作 Store

    Informer 的第二个职责,则是根据这些事件的类型,触发事先注册好的 ResourceEventHandler;

    这些 Handler,需要在创建控制器的时候注册给它对应的 Informer。

  2. Informer 与要编写的控制循环之间,则使用了一个工作队列来进行协同,防止控制循环执行过慢把Informer拖死。

  3. 接下来就是熟悉的控制循环的逻辑了

参考链接:

https://www.zhihu.com/question/22285830/answer/469177185

https://www.pianshen.com/article/40791568713/

Kubernetes声明式API与编程范式的更多相关文章

  1. 【Kubernetes】声明式API与Kubernetes编程范式

    什么是声明式API呢? 答案是,kubectl apply命令. 举个栗子 在本地编写一个Deployment的YAML文件: apiVersion: apps/v1 kind: Deployment ...

  2. 【Kubernetes】深入解析声明式API

    在Kubernetes中,一个API对象在Etcd里的完整资源路径,是由:Group(API组).Version(API版本)和Resource(API资源类型)三个部分组成的. 通过这样的结构,整个 ...

  3. 声明式API replica controller vs replica set 对比

    1.在命令式API中,你可以直接发出服务器要执行的命令,例如: “运行容器”.“停止容器”等. 在声明性API中,你声明系统要执行的操作,系统将不断向该状态驱动. 可以想象成手动驾驶和自动驾驶系统.( ...

  4. SpringCloud学习笔记:声明式调用Feign(4)

    1. Feign简介 Feign采用声明式API接口的风格,将Java HTTP客户端绑定到它的内部. Feign的首要目标是简化Java HTTP客户端调用过程. 2.Feign客户端示例 Feig ...

  5. spring boot 2.0.3+spring cloud (Finchley)3、声明式调用Feign

    Feign受Retrofix.JAXRS-2.0和WebSocket影响,采用了声明式API接口的风格,将Java Http客户端绑定到他的内部.Feign的首要目标是将Java Http客户端调用过 ...

  6. spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign

    基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...

  7. SpringCloud 源码系列(6)—— 声明式服务调用 Feign

    SpringCloud 源码系列(1)-- 注册中心 Eureka(上) SpringCloud 源码系列(2)-- 注册中心 Eureka(中) SpringCloud 源码系列(3)-- 注册中心 ...

  8. 第23 章 : Kubernetes API 编程范式

    Kubernetes API 编程范式 需求来源 首先我们先来看一下 API 编程范式的需求来源. 在 Kubernetes 里面, API 编程范式也就是 Custom Resources Defi ...

  9. C#并行编程-PLINQ:声明式数据并行

    目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-PLINQ:声明式数据并行 背景 通过LINQ可 ...

随机推荐

  1. npm & package.json & directories & files

    npm & package.json & directories & files package.json https://docs.npmjs.com/files/packa ...

  2. macOS & Xnip

    macOS & Xnip close finished notation cancel checked xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许 ...

  3. how to get selected option text in javascript

    how to get selected option text in javascript refs https://developer.mozilla.org/en-US/docs/Web/API/ ...

  4. Flutter: 监听App显示,隐藏

    关键代码 class _MyAppState extends State<MyApp> with WidgetsBindingObserver { @override void initS ...

  5. 数据序列化工具——flatbuffer

    flatbuffer是一款类似于protobuf的数据序列化工具.所有数据序列化,简单来说,就是将某程数据结构按照一定的格式进行编码与解码,以方便在不同的进程间传递后,能够正确的还原成之前的数据结构. ...

  6. 利用 Java 操作 Jenkins API 实现对 Jenkins 的控制详解

    本文转载自利用 Java 操作 Jenkins API 实现对 Jenkins 的控制详解 导语 由于最近工作需要利用 Jenkins 远程 API 操作 Jenkins 来完成一些列操作,就抽空研究 ...

  7. TERSUS无代码开发(笔记07)-简单实例手机端后台逻辑开发

    提交申请逻辑开发 1.添加父级对象引用(从父级对象中获取前端输入框的值) 1.设计数据库表(表名和字段名称不能用中文) 2.设计置数据库主键(可设联合主键) 3.传值形成数据实列处理 4.服务器端处理 ...

  8. 基于μcOS-II实时操作系统源码实现RMS和EDF调度(共享资源)

    μcOS-II多任务实验报告(RMS.EDF调度) 目录 μcOS-II多任务实验报告(RMS.EDF调度) 一.实验概述 二.环境搭建 三.代码分析 四.实验步骤 1 给TCB块添加扩展 2 创建并 ...

  9. SpringBoot(二): SpringBoot属性配置文件 SpringBoot多环境配置文件 SpringBoot自定义配置文件

    1.属性配置文件 一共分为两种,一种是键值对的properties属性配置文件,一种是yaml格式的配置文件 properties配置: 2.多环境配置文件 当我们的项目中有多套配置文件 比如开发的配 ...

  10. C++类的静态成员笔记

    下面是C++类的静态成员笔记. 静态数据成员特征 用关键字static声明 为该类的所有对象共享,静态数据成员具有静态生存期 必须在类外定义和初始化,用(::)来指明所属的类 举例说明-具有静态数据成 ...