一. 简介
Kubernetes 的能力都是通过各种 API 对象来提供,API 对象正是我们使用 Kubernetes 的接口,我们正是通过操作这些提供的 API 对象来使用 Kubernetes 能力的。最常见的就是 kubectl apply
命令。
二. 声明式
对于我们使用 Kubernetes API 对象的方式,一般会编写对应 API 对象的 YAML 文件交给 Kubernetes(而不是使用一些命令来直接操作 API)。所谓“声明式”,指的就是只需要提交一个定义好的 API 对象来“声明”(这个 YAML 文件其实就是一种“声明”),表示所期望的最终状态是什么样子就可以了。而如果提交的是一个个命令,去指导怎么一步一步达到期望状态,这就是“命令式”了。
这意味着 kube-apiserver
在响应命令式请求(比如,kubectl replace
)的时候,一次只能处理一个写请求,否则会有产生冲突的可能。而对于声明式请求(比如,kubectl apply
),一次能处理多个写操作,并且具备 Merge 能力。
三. “声明式”与“命令式”区别
- 在“声明式API“中,通常具有如下特点:
- API包含相对少量的相对较小的对象(资源)
- 这些对象定义应用程序或基础结构的配置
- 对象相对不频繁地更新
- 通常需要读取和写入对象
- 对象的主要操作是 CRUD-y (creating, reading, updating and deleting)
- 不需要跨对象进行事务处理:API 代表期望的状态,而不是当前的状态
- “命令式API”中,通常具有如下特点:
- 客户端说“执行此操作”,然后在完成后返回一个同步响应
- 客户端说“执行此操作”,然后取回操作ID,并且必须检查单独的 Operation 对象以确定请求是否完成
- 使用远程过程调用(RPCs)
- 直接存储大量数据,例如,每个对象大于几kB,或者大于1000个对象。
- 需要高带宽访问(持续每秒10s的请求)
- 存储最终用户数据(例如图像,PII 等)或应用程序处理的其他大规模数据
- 对象上的操作不是 CRUD-y 操作
- 该 API 很难建模为对象
- 选择了用“操作ID”或“操作对象”表示待处理的操作
四. API 对象
4.1 组成结构
一个 API 对象在 Etcd 里的完整资源路径,是由:Group(API组)、Version(API版本)和 Resource(API资源类型)
三个部分组成的。
具体案例如下图:
可以看出,Kubernetes 里 API 对象的组织方式,其实是层层递进的。
4.2 YAML结构
借助之前的yaml文件,参考如下的一个结构:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: demo-statefulset
spec:
serviceName: "demo-service"
replicas: 3
selector:
matchLabels:
app: demo-nginx
template:
........
在这个 YAML 文件中,StatefulSet
就是这个 API 对象的资源类型(Resource),apps
就是它的组(Group),v1
就是它的版本(Version)。
4.3 API 检索流程
对 Resource、Group 和 Version 进行检索,最终定位到API对象的流程如下:
- 匹配 Group
在陪陪Group时,一般分俩类。
- 核心 API 对象
对于 Kubernetes 里的核心 API 对象,比如:Pod、Node 等,是不需要 Group 的,因为它们的 Group 是“”。对于这些 API 对象来说,Kubernetes 会直接在/api
这个层级进行下一步的匹配过程。 - 非核心 API 对象
对于StatefulSet
等非核心 API 对象来说,Kubernetes 就必须在/apis
这个层级里查找它对应的Group
,进而根据“apps”
这个 Group 的名字,找到/apis/apps
。
这些 API Group 的分类是以对象功能为依据的,比如Deployment
,StatefulSet
就都属于“apps”
这个 Group。
具体可查看如下这张图:
匹配 Version
对于StatefulSet
这个 API 对象来说,Kubernetes
在apps
这个Group
下,匹配到的版本号就是v1
。在 Kubernetes 中,同一种 API 对象可以有多个版本,这正是 Kubernetes 进行 API 版本化管理的重要手段。这样,比如在StatefulSet
的开发过程中,对于会影响到用户的变更就可以通过升级新版本来处理,从而保证了向后兼容。匹配 Resource
在前面匹配到正确的版本之后,Kubernetes 就知道,要创建的原来是一个/apis/apps/v1
下的StatefulSet
对象。
五. 概念拓展
5.1 CRD
CRD 的全称是 Custom Resource Definition
。它指的就是,允许用户在 Kubernetes 中添加一个跟 Pod、Node 类似的、新的 API 资源类型,即:自定义 API 资源。
5.2 ListAndWatch
在 ListAndWatch 机制下,一旦 APIServer 端有新的实例被创建、删除或者更新,Reflector 都会收到“事件通知”。
ListAndWatch 方法的含义是:
- 首先,通过 APIServer 的 LIST API“获取”所有最新版本的 API 对象。
- 然后,再通过 WATCH API 来“监听”所有这些 API 对象的变化。
六. 总结
综上,Kubernetes“声明式 API”的独特之处:
- 首先,所谓“声明式”,指的就是只需要提交一个定义好的 API 对象来“声明”所期望的状态。
- 其次,“声明式 API”允许有多个 API 写端,以 PATCH 的方式对 API 对象进行修改,而无需关心本地原始 YAML 文件的内容。
- 最后,基于上面俩种能力,Kubernetes 才可以基于对 API 对象的增、删、改、查,在完全无需外界干预的情况下,完成对“实际状态”和“期望状态”的调谐(Reconcile)过程。
所以“声明式 API“ 才是 Kubernetes 项目编排能力“赖以生存”的核心所在,PaaS平台与这完全没有可比性。