本章将引入REST的概念,详细说明Kubernetes API的概念和使用方法,并举例说明如何基于Jersey和Fabric8框架访问Kubernetes API,深入分析基于这两个框架访问Kubernetes API的优缺点,最后对Kubernetes API的扩展进行详细说明。下面从REST开始说起。
REST简述
REST(Representational State Transfer,表述性状态传递)是由Roy Thomas Fielding博士在他的论文Architectural Styles and the Design of Network-based Software Architectures中提出的一个术语。REST本身只是为分布式超媒体系统设计的一种架构风格,而不是标准。
基于Web的架构实际上就是各种规范的集合,比如HTTP是一种规范,客户端服务器模式是另一种规范。每当我们在原有规范的基础上增加新的规范时,就会形成新的架构。而REST正是这样一种架构,它结合了一系列规范,形成了一种新的基于Web的架构风格。
传统的Web应用大多是B/S架构,涉及如下规范。
(1)客户端-服务器:这种规范的提出,改善了用户接口跨多个平台的可移植性,并且通过简化服务器组件,改善了系统的可伸缩性。最为关键的是通过分离用户接口和数据存储,使得不同的用户终端共享相同的数据成为可能。
(2)无状态性:无状态性是在客户端-服务器规范的基础上添加的又一层规范,它要求通信必须在本质上是无状态的,即从客户端到服务器的每个request都必须包含理解该request必需的所有信息。这个规范改善了系统的可见性(无状态性使得客户端和服务器端不必保存对方的详细信息,服务器只需要处理当前的request,而不必了解所有request的历史)、可靠性(无状态性减少了服务器从局部错误中恢复的任务量)、可伸缩性(无状态性使得服务器端可以很容易释放资源,因为服务器端不必在多个request中保存状态)。同时,这种规范的缺点也是显而易见的,不能将状态数据保存在服务器上,导致增加了在一系列request中发送重复数据的开销,严重降低了效率。
(3)缓存:为了改善无状态性带来的网络的低效性,客户端缓存规范出现。缓存规范允许隐式或显式地标记一个response中的数据,赋予了客户端缓存response数据的功能,这样就可以为以后的request共用缓存的数据消除部分或全部交互,提高了网络效率。但是客户端缓存了信息,所以客户端数据与服务器数据不一致的可能性增加,从而降低了可靠性。
B/S架构的优点是部署非常方便,在用户体验方面却不很理想。为了改善这种状况,REST规范出现。REST规范在原有B/S架构的基础上增加了三个新规范:统一接口、分层系统和按需代码。
(1)统一接口:REST架构风格的核心特征就是强调组件之间有一个统一的接口,表现为在REST世界里,网络上的所有事物都被抽象为资源,REST通过通用的链接器接口对资源进行操作。这样设计的好处是保证系统提供的服务都是解耦的,可极大简化系统,改善系统的交互性和可重用性。
(2)分层系统:分层系统规则的加入提高了各种层次之间的独立性,为整个系统的复杂性设置了边界,通过封装遗留的服务,使新的服务器免受遗留客户端的影响,也提高了系统的可伸缩性。
(3)按需代码:REST允许对客户端的功能进行扩展。比如,通过下载并执行applet或脚本形式的代码来扩展客户端的功能。但这在改善系统可扩展性的同时降低了可见性,所以它只是REST的一个可选约束。
REST架构是针对Web应用而设计的,其目的是为了降低开发的复杂性,提高系统的可伸缩性。REST提出了如下设计准则。
(1)网络上的所有事物都被抽象为资源(Resource)。
(2)每个资源都对应唯一的资源标识符(Resource Identifier)。
(3)通过通用的连接器接口(Generic Connector Interface)对资源进行操作。
(4)对资源的各种操作都不会改变资源标识符。
(5)所有操作都是无状态的(Stateless)。
REST中的资源指的不是数据,而是数据和表现形式的组合,比如“最新访问的10位会员”和“最活跃的10位会员”在数据上可能有重叠或者完全相同,而它们由于表现形式不同,被归为不同的资源,这也就是为什么REST的全名是Representational State Transfer。资源标识符就是URI(Uniform Resource Identifier),不管是图片、Word还是视频文件,甚至只是一种虚拟的服务,也不管是XML、TXT还是其他文件格式,全部通过URI对资源进行唯一标识。
REST是基于HTTP的,任何对资源的操作行为都通过HTTP来实现。以往的Web开发大多数用的是HTTP中的GET和POST方法,很少使用其他方法,这实际上是对HTTP的片面理解造成的。HTTP不仅仅是一个简单的运载数据的协议,还是一个具有丰富内涵的网络软件的协议,它不仅能对互联网资源进行唯一定位,还能告诉我们如何对该资源进行操作。HTTP把对一个资源的操作限制在4种方法(GET、POST、PUT和DELETE)中,这正是对资源CRUD操作的实现。由于资源和URI是一一对应的,在执行这些操作时URI没有变化,和以往的Web开发有很大的区别,所以极大地简化了Web开发,也使得URI可以被设计成能更直观地反映资源的结构。这种URI的设计被称作RESTful的URI,为开发人员引入了一种新的思维方式:通过URL来设计系统结构。当然,这种设计方式对于一些特定情况也是不适用的,也就是说不是所有URI都适用于RESTful。
REST之所以可以提高系统的可伸缩性,就是因为它要求所有操作都是无状态的。没有了上下文(Context)的约束,做分布式和集群时就更为简单,也可以让系统更为有效地利用缓冲池(Pool),并且由于服务器端不需要记录客户端的一系列访问,也就减少了服务器端的性能损耗。
Kubernetes API也符合RESTful规范,下面对其进行介绍。
Kubernetes API详解
Kubernetes API 概述
Kubernetes API是集群系统中的重要组成部分,Kubernetes中各种资源(对象)的数据都通过该API接口被提交到后端的持久化存储(etcd)中,Kubernetes集群中的各部件之间通过该API接口实现解耦合,同时Kubernetes集群中一个重要且便捷的管理工具kubectl也是通过访问该API接口实现其强大的管理功能的。Kubernetes API中的资源对象都拥有通用的元数据,资源对象也可能存在嵌套现象,比如在一个Pod里面嵌套多个Container。创建一个API对象是指通过API调用创建一条有意义的记录,该记录一旦被创建,Kubernetes就将确保对应的资源对象会被自动创建并托管维护。
在Kubernetes系统中,在大多数情况下,API定义和实现都符合标准的HTTP REST格式,比如通过标准的HTTP动词(POST、PUT、GET、DELETE)来完成对相关资源对象的查询、创建、修改、删除等操作。但同时,Kubernetes也为某些非标准的REST行为实现了附加的API接口,例如Watch某个资源的变化、进入容器执行某个操作等。另外,某些API接口可能违背严格的REST模式,因为接口返回的不是单一的JSON对象,而是其他类型的数据,比如JSON对象流或非结构化的文本日志数据等。
Kubernetes开发人员认为,任何成功的系统都会经历一个不断成长和不断适应各种变更的过程。因此,他们期望Kubernetes API是不断变更和增长的。同时,他们在设计和开发时,有意识地兼容了已存在的客户需求。通常,我们不希望将新的API资源和新的资源域频繁地加入系统,资源或域的删除需要一个严格的审核流程。
Kubernetes API文档官网为https://kubernetes.io/docs/reference,可以通过相关链接查看不同版本的API文档,例如Kubernetes 1.14版本的链接为https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.14。
在Kubernetes 1.13版本及之前的版本中,Master的API Server服务提供了Swagger格式的API网页。Swagger UI是一款REST API文档在线自动生成和功能测试软件,关于Swagger的内容请访问官网http://swagger.io。我们通过设置kube-apiserver服务的启动参数–enable-swagger-ui=true来启用Swagger UI页面,其访问地址为http://<master-ip>:<master-port>/swagger-ui/。假设API Server启动了192.168.18.3服务器上的8080端口,则可以通过访问http://192.168.18.3:8080/swagger-ui/来查看API列表,如下图:
单击api/v1可以查看所有API的列表,以创建一个Pod为例,找到Rest API的访问路径为“/api/v1/namespaces/{namespace}/pods”,单击链接展开,即可查看详细的API接口说明,单击Model链接,则可以查看文本格式显示的API接口描述
我们看到,在Kubernetes API中,一个API的顶层(Top Level)元素由kind、apiVersion、metadata、spec和status这5部分组成,接下来分别对这5部分进行说明。
1.kind
kind表明对象有以下三大类别。
(1)对象(objects):代表系统中的一个永久资源(实体),例如Pod、RC、Service、Namespace及Node等。通过操作这些资源的属性,客户端可以对该对象进行创建、修改、删除和获取操作。
(2)列表(list):一个或多个资源类别的集合。所有列表都通过items域获得对象数组,例如PodLists、ServiceLists、NodeLists。大部分被定义在系统中的对象都有一个返回所有资源集合的端点,以及零到多个返回所有资源集合的子集的端点。某些对象有可能是单例对象(singletons),例如当前用户、系统默认用户等,这些对象没有列表。
(3)简单类别(simple):该类别包含作用在对象上的特殊行为和非持久实体。该类别限制了使用范围,它有一个通用元数据的有限集合,例如Binding、Status。
2.apiVersion
apiVersion表明API的版本号,当前版本默认只支持v1。
3.Metadata
Metadata是资源对象的元数据定义,是集合类的元素类型,包含一组由不同名称定义的属性。在Kubernetes中每个资源对象都必须包含以下3种Metadata。
(1)namespace:对象所属的命名空间,如果不指定,系统则会将对象置于名为default的系统命名空间中。
(2)name:对象的名称,在一个命名空间中名称应具备唯一性。
(3)uid:系统为每个对象都生成的唯一ID,符合RFC 4122规范的定义。
此外,每种对象都还应该包含以下几个重要元数据。
1)labels:用户可定义的“标签”,键和值都为字符串的map,是对象进行组织和分类的一种手段,通常用于标签选择器,用来匹配目标对象。
(2)annotations:用户可定义的“注解”,键和值都为字符串的map,被Kubernetes内部进程或者某些外部工具使用,用于存储和获取关于该对象的特定元数据。
(3)resourceVersion:用于识别该资源内部版本号的字符串,在用于Watch操作时,可以避免在GET操作和下一次Watch操作之间造成的信息不一致,客户端可以用它来判断资源是否改变。该值应该被客户端看作不透明,且不做任何修改就返回给服务端。客户端不应该假定版本信息具有跨命名空间、跨不同资源类别、跨不同服务器的含义。
(4)creationTimestamp:系统记录创建对象时的时间戳,符合RFC 3339规范。
(5)deletionTimestamp:系统记录删除对象时的时间戳,符合RFC 3339规范。
(6)selfLink:通过API访问资自身的URL,例如一个Pod的link可能是“/api/v1/namespaces/ default/pods/frontend-o8bg4”。
4.spec
spec是集合类的元素类型,用户对需要管理的对象进行详细描述的主体部分都在spec里给出,它会被Kubernetes持久化到etcd中保存,系统通过spec的描述来创建或更新对象,以达到用户期望的对象运行状态。spec的内容既包括用户提供的配置设置、默认值、属性的初始化值,也包括在对象创建过程中由其他相关组件(例如schedulers、auto-scalers)创建或修改的对象属性,比如Pod的Service IP地址。如果spec被删除,那么该对象将会从系统中删除。
5.Status
Status用于记录对象在系统中的当前状态信息,它也是集合类元素类型,status在一个自动处理的进程中被持久化,可以在流转的过程中生成。如果观察到一个资源丢失了它的状态(Status),则该丢失的状态可能被重新构造。以Pod为例,Pod的status信息主要包括conditions、containerStatuses、hostIP、phase、podIP、startTime等,其中比较重要的两个状态属性如下。
(1)phase:描述对象所处的生命周期阶段,phase的典型值是Pending(创建中)、Running、Active(正在运行中)或Terminated(已终结),这几种状态对于不同的对象可能有轻微的差别,此外,关于当前phase附加的详细说明可能包含在其他域中。
(2)condition:表示条件,由条件类型和状态值组成,目前仅有一种条件类型:Ready,对应的状态值可以为True、False或Unknown。一个对象可以具备多种condition,而condition的状态值也可能不断发生变化,condition可能附带一些信息,例如最后的探测时间或最后的转变时间。
Kubernetes从1.14版本开始,使用OpenAPI(https://www.openapis.org)的格式对API进行查询,其访问地址为http://<master-ip>: <master-port>/openapi/v2。例如,使用命令行工具curl进行查询:
1
2 1curl http://192.168.18.3;8080/openapi/v2 | jq
2
小结:
本节内容到此为止,如果大家是做运维的话,那么大家可以简单了解。
了解其中的原理即可。