第9章 Kubernetes开发指南
9.1 REST简述
9.2 Kubernetes API详解
9.2.1 Kubernetes API概述
9.2.2 Kubernetes API版本的演进策略
9.2.3 API Groups(API组)
9.2.4 API REST的方法说明
9.2.5 API Server响应说明
9.3 使用Java程序访问Kubernetes API
9.3.1 Jersey
9.3.2 Fabric8
9.3.3 使用说明
9.3.4 其他客户端库
9.4 Kubernetes API的扩展
9.4.1 使用CRD扩展API资源
9.4.2 使用API聚合机制扩展API资源
本章将引入REST的概念,详细说明Kubernetes API的概念和使用方法,并举例说明如何基于Jersey和Fabric8框架访问Kubernetes API,
深入分析基于这两个框架访问Kubernetes API的优缺点,最后对Kubernetes API的扩展进行详细说明。
下面从REST开始说起。
9.1 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规范,下面对其进行介绍。
9.2 Kubernetes API详解
9.2.1 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列表,如图9.1所示。
单击api/v1可以查看所有API的列表,如图9.2所示。
以创建一个Pod为例,找到Rest API的访问路径为“POST /api/v1/namespaces/{namespace}/pods”,如图9.3所示。
单击链接展开,即可查看详细的API接口说明,如图9.4所示。
单击Model链接,则可以查看文本格式显示的API接口描述,如图9.5所示。
我们看到,在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进行查询:
# curl http://<master-ip>: <master-port>/openapi/v2 | jq
# curl http://192.168.18.3: 8080/openapi/v2 | jq
9.2.2 Kubernetes API版本的演进策略
为了在兼容旧版本的同时不断升级新的API,Kubernetes提供了多版本API的支持能力,每个版本的API都通过一个版本号路径前缀进行区分,例如/api/v1beta3。
在通常情况下,新旧几个不同的API版本都能涵盖所有的Kubernetes资源对象,在不同的版本之间,这些API接口存在一些细微差别。
Kubernetes开发团队基于API级别选择版本而不是基于资源和域级别,
是为了确保API能够清晰、连续地描述一个系统资源和行为的视图,能够控制访问的整个过程和控制实验性API的访问。
API的版本号通常用于描述API的成熟阶段,例如:
v1表示GA稳定版本;
v1beta3表示Beta版本(预发布版本);
v1alpha1表示Alpha版本(实验性的版本)。
当某个API的实现达到一个新的GA稳定版本时(如v2),旧的GA版本(如v1)和Beta版本(例如v2beta1)将逐渐被废弃。
Kubernetes建议废弃的时间如下:
对于旧的GA版本(如v1),Kubernetes建议废弃的时间应不少于12个月或3个大版本Release的时间,选择最长的时间。
对旧的Beta版本(如v2beta1),Kubernetes建议废弃的时间应不少于9个月或3个大版本Release的时间,选择最长的时间。
对旧的Alpha版本,则无须等待,可以直接废弃。
完整的API更新和废弃策略请参考官方网站https://kubernetes.io/docs/reference/usingapi/deprecation-policy/的说明。
9.2.3 API Groups(API组)
为了更容易对API进行扩展,Kubernetes使用API Groups(API组)进行标识。
API Groups以REST URL中的路径进行定义。
当前支持两类API groups:
Core Groups(核心组),也可以称之为Legacy Groups,作为Kubernetes最核心的API,其特点是没有“组”的概念,例如“v1”,在资源对象的定义中表示为“apiVersion:v1”。
具有分组信息的API,以/apis/$GROUP_NAME/$VERSION URL路径进行标识,在资源对象的定义中表示为“apiVersion: $GROUP_NAME/$VERSION”,
例如:“apiVersion: batch/v1”“apiVersion: extensions:v1beta1”“apiVersion: apps/v1beta1”等,
详细的API列表请参见官网https://kubernetes.io/docs/reference,目前根据Kubernetes的不同版本有不同的API说明页面。
例如,Pod的API说明如图9.6所示,由于Pod属于核心资源对象,所以不存在某个扩展API Group,页面显示为Core,在Pod的定义中为“apiVersion: v1”。
StatefulSet则属于名为apps的API组,版本号为v1,在StatefulSet的定义中为“apiVersion: apps/v1”,如图9.7所示。
如果要启用或禁用特定的API组,则需要在API Server的启动参数中设置--runtime-config进行声明,
例如,--runtime-config=batch/v2alpha1表示启用API组“batch/v2alpha1”;也可以设置--runtime-config=batch/v1=false表示禁用API组“batch/v1”。
多个API组的设置以逗号分隔。
在当前的API Server服务中,DaemonSets、Deployments、HorizontalPodAutoscalers、Ingress、Jobs和ReplicaSets所属的API组是默认启用的。
9.2.4 API REST的方法说明
API资源使用REST模式,对资源对象的操作方法如下:
(1)GET /<资源名的复数格式>:获得某一类型的资源列表,例如GET /pods返回一个Pod资源列表。
(2)POST /<资源名的复数格式>:创建一个资源,该资源来自用户提供的JSON对象。
(3)GET /<资源名复数格式>/<名称>:通过给出的名称获得单个资源,例如GET/pods/first返回一个名为first的Pod。
(4)DELETE /<资源名复数格式>/<名称>:通过给出的名称删除单个资源,
在删除选项(DeleteOptions)中可以指定优雅删除(Grace Deletion)的时间(GracePeriodSeconds),该选项表明了从服务端接收到删除请求到资源被删除的时间间隔(单位为s)。
不同的类别(Kind)可能为优雅删除时间(Grace Period)声明默认值。用户提交的优雅删除时间将覆盖该默认值,包括值为0的优雅删除时间。
(5)PUT /<资源名复数格式>/<名称>:通过给出的资源名和客户端提供的JSON对象来更新或创建资源。
(6)PATCH /<资源名复数格式>/<名称>:选择修改资源详细指定的域。
对于PATCH操作,目前Kubernetes API通过相应的HTTP首部“Content-Type”对其进行识别。
目前支持以下三种类型的PATCH操作:
(1)JSON Patch, Content-Type: application/json-patch+json。
在RFC6902的定义中,JSON Patch是执行在资源对象上的一系列操作,例如 {"op": "add", "path": "/a/b/c", "value": ["foo","bar"]}。
详情请查看RFC6902说明,网址为https://tools.ietf.org/html/rfc6902。
(2)Merge Patch, Content-Type: application/merge-json-patch+json。
在RFC7386的定义中,Merge Patch必须包含对一个资源对象的部分描述,这个资源对象的部分描述就是一个JSON对象。
该JSON对象被提交到服务端,并和服务端的当前对象合并,从而创建一个新的对象。
详情请查看RFC73862说明,网址为https://tools.ietf.org/html/rfc7386。
(3)Strategic Merge Patch, Content-Type: application/strategic-merge-patch+json。
Strategic Merge Patch是一个定制化的Merge Patch实现。接下来将详细讲解Strategic Merge Patch。
在标准的JSON Merge Patch中,JSON对象总被合并(Merge),但是资源对象中的列表域总被替换,用户通常不希望如此。
例如,我们通过下列定义创建一个Pod资源对象:
spec:
containers:
- name: nginx
image: nginx-1.0
接着,我们希望添加一个容器到这个Pod中,代码和上传的JSON对象如下:
PATH /api/vi/namespaces/default/pods/pod-name
spec:
containers:
- name: log-tailer
image: log-tailer-1.0
如果我们使用标准的Merge Patch,则其中的整个容器列表将被单个“log-tailer”容器所替换,然而我们的目的是使两个容器列表合并。
为了解决这个问题,Strategic Merge Patch添加元数据到API对象中,并通过这些新元数据来决定哪个列表被合并,哪个列表不被合并。
当前这些元数据作为结构标签,对于API对象自身来说是合法的。
对于客户端来说,这些元数据作为Swagger annotations也是合法的。
在上述例子中向containers中添加了patchStrategy域,且它的值为merge,通过添加patchMergeKey,它的值为name。
也就是说,containers中的列表将会被合并而不是替换,合并的依据为name域的值。
此外,Kubernetes API添加了资源变动的观察者模式的API接口。
GET /watch/<资源名复数格式>:随时间变化,不断接收一连串的JSON对象,这些JSON对象记录了给定资源类别内所有资源对象的变化情况。
GET /watch/<资源名复数格式>/<name>:随时间变化,不断接收一连串的JSON对象,这些JSON对象记录了某个给定资源对象的变化情况。
上述接口改变了返回数据的基本类别,watch动词返回的是一连串JSON对象,而不是单个JSON对象。
并不是所有对象类别都支持观察者模式的API接口,在后续的章节中将会说明哪些资源对象支持这种接口。
另外,Kubernetes还增加了HTTP Redirect与HTTP Proxy这两种特殊的API接口,前者实现资源重定向访问,后者则实现HTTP请求的代理。
9.2.5 API Server响应说明
API Server在响应用户请求时附带一个状态码,该状态码符合HTTP规范。
表9.1列出了API Server可能返回的状态码。
状态码 编码 描述
200 OK 表明请求完全成功
201 Create 表明创建类的请求完全成功
204 NoContent 表明请求完全成功,同时HTTP响应不包含响应体。在响应OPTIONS方法的HTTP请求时返回。
307 TemporaryRedirect 表明请求资源的地址被改变,建议客户端使用Location首部给出的临时URL来定位资源
400 BadRequest 表明请求是非法的,建议用户不要重试,修改该请求
401 Unauthorized 表明请求能够到达服务端,且服务端能够理解用户请求,但是拒绝做更多的事情,因为客户端必须提供认证信息。
如果客户端提供了认证信息,则返回该状态码,表明服务端指出所提供的认证信息不合适或非法。
403 Forbidden 表明请求能够到达服务端,且服务端能够理解用户请求,但是拒绝做更多的事情,因为该请求被设置成拒绝访问。建议用户不要重试,修改该请求。
404 NotFound 表明所请求得资源不存在。建议用户不要重试,修改该请求。
405 MethodNotAllowed 表明所请求中带有该资源不支持的方法。建议用户不要重试,修改该请求。
409 Conflict 表明客户端尝试创建的资源已经存在,或者由于冲突,请求的更新操作不能被完成
422 UnprocessableEntity 表明由于所提供的作为请求部分的数据非法,创建或修改操作不能被完成。
429 TooManyRequests 表明超出了客户端访问频率的限制或者服务端接收到多于它能处理的请求。建议客户端读取相应的Retry-After首部,然后等待该首部指出的时间后再重试。
500 InternalServerError 表明服务端能被请求访问到,但是不能理解用户的请求;或者在服务端内产生非预期的一个错误,而且该错误无法被认知;
或者服务端不能在一个合理的时间内完成处理(这可能是服务器临时负载过重造成的,或和其他服务器通信时的一个临时通信故障造成的)
503 ServiceUnavailable 表明被请求的服务无效。建议用户不要重试,修改该请求。
504 ServiceTimeout 表明请求在给定的时间内无法完成。客户端仅在为请求指定超时(Timeout)参数时得到该响应。
在调用API接口发生错误时,Kubernetes将会返回一个状态类别(Status Kind)。
下面是两种常见的错误场景:
(1)当一个操作不成功时(例如,当服务端返回一个非2xx HTTP状态码时)。
(2)当一个HTTP DELETE方法调用失败时。
状态对象被编码成JSON格式,同时该JSON对象被作为请求的响应体。
该状态对象包含人和机器使用的域,在这些域中包含来自API的关于失败原因的详细信息。
状态对象中的信息补充了对HTTP状态码的说明。
例如:
# curl -v -k -H "Authorization: Bearer admin" https://10.240.122.184:443/api/v1/namespaces/default/pods/grafana
输出:
{
"apiVersion": "v1",
"kind": "Status",
"metadata": {},
"status": "Failure",
"message": "pods \"grafana \"not found",
"reason": "NotFound",
"details": {
"name": "grafana",
"kind": "pods"
},
"code": 404
}
其中:
status域包含两个可能的值:Success或Failure。
message域包含对错误的描述信息。
reason域包含说明该操作失败原因的描述。
details可能包含和reason域相关的扩展数据。每个reason域都可以定义它的扩展的details域。该域是可选的,返回数据的格式是不确定的,不同的reason类型返回的details域的内容不一样。
9.3 使用Java程序访问Kubernetes API
本节介绍如何使用Java程序访问Kubernetes API。
在Kubernetes官网上列出了多个访问Kubernetes API的开源项目,其中有两个是用Java语言开发的开源项目,一个是OSGI,另一个是Fabric8。
在本节所列的两个Java开发例子中,一个是基于Jersey的,另一个是基于Fabric8的。
9.3.1 Jersey
Jersey是一个RESTful请求服务Java框架。与Struts类似,它可以和Hibernate、Spring框架整合。
我们不仅能很方便地通过它开发RESTful Web Service,还可以将它作为客户端方便地访问RESTful Web Service服务端。
如果没有一个好的工具包,则很难开发一个能够用不同的媒介(Media)类型无缝地暴露你的数据,以及很好地抽象客户端、服务端通信的底层通信的RESTful Web Services。
为了能够简化使用Java开发RESTful Web Service及其客户端的流程,业界设计了JAX-RS API。
Jersey RESTful Web Services框架是一个开源的高质量的框架,它为用Java语言开发RESTful Web Service及其客户端而生,支持JAX-RS APIs。
Jersey不仅支持JAX-RS APIs,而且在此基础上扩展了API接口,这些扩展更加方便并简化了RESTful Web Services及其客户端的开发。
由于Kubernetes API Server是RESTful Web Service,因此此处选用Jersey框架开发RESTful Web Service客户端,用来访问Kubernetes API。
在本例中选用的Jersey框架的版本为1.19,所涉及的Jar包如图9.8所示。
对Kubernetes API的访问包含如下3个方面:
(1)指明访问资源的类型。
(2)访问时的一些选项(参数),比如命名空间、对象的名称、过滤方式(标签和域)、子目录、访问的目标是否是代理和是否用watch方式访问等。
(3)访问的方法,比如增、删、改、查。
在使用Jersey框架访问Kubernetes API之前,我们需要为这3个方面定义3个对象。
第1个定义的对象是ResourceType,它定义了访问资源的类型;
第2个定义的对象是Params,它定义了访问API时的一些选项,以及通过这些选项如何生成完整的URL;
第3个定义的对象是RestfulClient,它是一个接口,该接口定义了访问API的方法(Method)。
(1)ResourceType是一个ENUM类型的对象,定义了Kubernetes的各种资源对象类型,代码如下:
(2)Params定义访问API时的选项及通过这些选项如何生成完整的URL,代码如下:
Params对象包含的属性说明如表9.2所示。
(3)接口对象RestfulClient定义了访问API接口的所有方法,其代码如下:
其中,get和list方法对应Kubernetes API的GET方法;create方法对应API中的POST方法;
delete方法对应API中的DELETE方法;update方法对应API中的PATCH方法;
replace方法对应API中的PUT方法;options方法对应API中的OPTIONS方法;head方法对应API中的HEAD方法。
该接口基于Jersey框架的实现类如下:
在该对象中包含如下代码:
该段代码的作用是使Jersey客户端支持除标准REST方法外的方法,比如PATCH方法。
该段代码能访问除watcher外的所有Kubernetes API接口,在后续的章节中会举例说明如何访问Kubernetes API。
9.3.2 Fabric8
Fabric8包含多款工具包,Kubernetes Client只是其中之一,也是在Kubernetes官网中提到的Java Client API之一。
本例代码涉及的Jar包如图9.9所示。
因为该工具包已经对访问Kubernetes API客户端做了较好的封装,因此其访问代码比较简单,其具体的访问过程会在后续的章节举例说明。
Fabric 8的Kubernetes API客户端工具包只能访问Node、Service、Pod、Endpoints、Events、Namespace、PersistenetVolumeclaims、PersistenetVolume、
ReplicationController、ResourceQuota、Secret和ServiceAccount这几种资源类型,
不能使用OPTIONS和HEAD方法访问资源,且不能以代理方式访问资源,但其对以watcher方式访问资源做了很好的支持。
9.3.3 使用说明
首先,举例说明对API资源的基本访问,也就是对资源的增、删、改、查,以及替换资源的status。
其中会单独对Node和Pod的特殊接口做举例说明。
表9.3列出了各资源对象的基本接口。
首先,举例说明如何通过API接口来创建资源对象。
我们需要创建访问API Server的客户端,其中,http://192.168.1.128:8080为API Server的地址。
基于Jersey框架的代码如下:
RestfulClient_restfulClient = new JerseyRestfulClient("http://192.168.1.128:8080/api/v1");
基于Fabric8框架的代码如下:
Config_conf = new Config();
KubernetesClient_kube = new DefultKubernetesClient("http://192.168.1.128:8080");
分别通过上面的两个客户端创建Namespace资源对象,
基于Jersey框架的代码如下:
其中,“namespace.json”为创建Namespace资源对象的JSON定义,代码如下:
基于Fabric8框架的代码如下:
由于Fabric8框架对Kubernetes API对象做了很好的封装,对其中的大量对象都做了定义,
所以用户可以通过其提供的资源对象去定义Kubernetes API对象,例如上面例子中的Namespace对象。
Fabric8框架中的kubernetes-model工具包用于API对象的封装。
在上面的例子中,通过Fabric8框架提供的类创建了一个名为ns-fabric8的命名空间对象。
接下来会通过基于Jeysey框架的代码创建两个Pod资源对象。
在两个例子中,一个是在上面创建的“ns-sample”Namespace中创建Pod资源对象,另一个是为后续创建“cluster service”创建的Pod资源对象。
由于基于Fabric8框架创建Pod资源对象的方法很简单,因此不再用Fabric8框架对上述两个例子做说明。
通过基于Jersey框架创建这两个Pod资源对象的代码如下:
其中,podInNs.json和pod4ClusterService.json是创建两个Pod资源对象的定义。
podInNs.json文件的内容如下:
pod4ClusterService.json文件的内容如下:
下面的例子代码用于获取Pod资源列表,
其中,第1部分代码用于获取所有的Pod资源对象,第2、3部分代码主要用于说明如何使用标签选择Pod资源对象,
最后一部分代码用于举例说明如何使用field选择Pod资源对象。
代码如下:
接下来的例子代码用于替换一个Pod对象,在通过Kubernetes API替换一个Pod资源对象时需要注意如下两点:
(1)在替换该资源对象前,先从API中获取该资源对象的JSON对象,然后在该JSON对象的基础上修改需要替换的部分。
(2)在Kubernetes API提供的接口中,PUT方法(replace)只支持替换容器的image部分。
代码如下:
其中,pod4Replace.json的内容如下:
接下来的两个例子实现了在9.2.4节中提到的两种Merge方式:Merge Patch和Strategic Merge Patch。
Merge Patch的示例如下:
其中,pod4MergeJsonPatch.json的内容如下:
Strategic Merge Patch的示例如下:
其中,pod4StrategicMerge.json的内容如下:
接下来实现了修改Pod资源对象的状态,代码如下:
其中,pod4Status.json的内容如下:
接下来实现了查看Pod的log日志功能,代码如下:
下面通过API访问Node的多种接口,代码如下:
最后,举例说明如何通过API删除资源对象pod,代码如下:
通过API接口除了能够对资源对象实现前面列出的基本操作,还涉及两类特殊接口,一类是WATCH,一类是PROXY。
这两类特殊接口所包含的接口如表9.4所示。
下面基于Fabric8实现对资源对象的监听,代码如下:
接下来基于Jersey框架实现通过Proxy方式访问Pod。
由于API Server针对Pod资源提供了两种Proxy访问接口,所以下面分别用两段代码进行示例说明。代码如下:
9.3.4 其他客户端库
为了让开发人员更方便地访问Kubernetes的RESTful API,Kubernetes社区推出了针对Go、Python、Java、dotNet、JavaScript等编程语言的客户端库,
这些库由特别兴趣小组(SIG)API Machinary维护,其官方网站为https://github.com/kubernetes/community/tree/master/sig-api-machinery。
目前Kubernetes官方支持的客户端库如表9.5所示。
此外,Kubernetes社区也在开发和维护基于其他开发语言的客户端库,如9.6所示。
9.4 Kubernetes API的扩展
随着Kubernetes的发展,用户对Kubernetes的扩展性也提出了越来越高的要求。
从1.7版本开始,Kubernetes引入扩展API资源的能力,
使得开发人员在不修改Kubernetes核心代码的前提下可以对Kubernetes API进行扩展,仍然使用Kubernetes的语法对新增的API进行操作,
这非常适用于在Kubernetes上通过其API实现其他功能(例如第三方性能指标采集服务)或者测试实验性新特性(例如外部设备驱动)。
在Kubernetes中,所有对象都被抽象定义为某种资源对象,同时系统会为其设置一个API入口(API Endpoint),
对资源对象的操作(如新增、删除、修改、查看等)都需要通过Master的核心组件API Server调用资源对象的API来完成。
与API Server的交互可以通过kubectl命令行工具或访问其RESTful API进行。
每个API都可以设置多个版本,在不同的API URL路径下区分,例如“/api/v1”或“/apis/extensions/v1beta1”等。
使用这种机制后,用户可以很方便地定义这些API资源对象(YAML配置),并将其提交给Kubernetes(调用RESTful API),来完成对容器应用的各种管理工作。
Kubernetes系统内置的Pod、RC、Service、ConfigMap、Volume等资源对象已经能够满足常见的容器应用管理要求,
但如果用户希望将其自行开发的第三方系统纳入Kubernetes,并使用Kubernetes的API对其自定义的功能或配置进行管理,就需要对API进行扩展了。
目前Kubernetes提供了以下两种机制供用户扩展API:
(1)使用CRD机制:复用Kubernetes的API Server,无须编写额外的API Server。
用户只需要定义CRD,并且提供一个CRD控制器,就能通过Kubernetes的API管理自定义资源对象了,同时要求用户的CRD对象符合API Server的管理规范。
(2)使用API聚合机制:用户需要编写额外的API Server,可以对资源进行更细粒度的控制(例如,如何在各API版本之间切换),要求用户自行处理对多个API版本的支持。
本节主要对CRD和API聚合这两种API扩展机制的概念和用法进行详细说明。
9.4.1 使用CRD扩展API资源
CRD是Kubernetes从1.7版本开始引入的特性,在Kubernetes早期版本中被称为TPR(ThirdPartyResources,第三方资源)。
TPR从Kubernetes 1.8版本开始被停用,被CRD全面替换。
CRD本身只是一段声明,用于定义用户自定义的资源对象。
但仅有CRD的定义并没有实际作用,用户还需要提供管理CRD对象的CRD控制器(CRD Controller),才能实现对CRD对象的管理。
CRD控制器通常可以通过Go语言进行开发,并需要遵循Kubernetes的控制器开发规范,基于客户端库client-go进行开发,
需要实现Informer、ResourceEventHandler、Workqueue等组件具体的功能处理逻辑,
详细的开发过程请参考官方示例(https://github.com/kubernetes/sample-controller)
和client-go库(https://github.com/kubernetes/sample-controller/blob/master/docs/controller-client-go.md)的详细说明。
1.创建CRD的定义
与其他资源对象一样,对CRD的定义也使用YAML配置进行声明。
以Istio系统中的自定义资源VirtualService为例,配置文件crd-virtualservice.yaml的内容如下:
CRD定义中的关键字段如下:
(1)group:设置API所属的组,将其映射为API URL中“/apis/”的下一级目录,设置networking.istio.io生成的API URL路径为“/apis/networking.istio.io”。
(2)scope:该API的生效范围,可选项为Namespaced(由Namespace限定)和Cluster(在集群范围全局生效,不局限于任何Namespace),默认值为Namespaced。
(3)versions:设置此CRD支持的版本,可以设置多个版本,用列表形式表示。
目前还可以设置名为version的字段,只能设置一个版本,在将来的Kubernetes版本中会被弃用,建议使用versions进行设置。
如果该CRD支持多个版本,则每个版本都会在API URL“/apis/networking.istio.io”的下一级进行体现,例如“/apis/networking.istio.io/v1”或“/apis/networking.istio.io/v1alpha3”等。
每个版本都可以设置下列参数:
name:版本的名称,例如v1、v1alpha3等。
served:是否启用,在被设置为true时表示启用。
storage:是否进行存储,只能有一个版本被设置为true。
(4)names:CRD的名称,包括单数、复数、kind、所属组等名称的定义,可以设置如下参数。
kind:CRD的资源类型名称,要求以驼峰式命名规范进行命名(单词的首字母都大写),例如VirtualService。
listKind:CRD列表,默认被设置为<kind>List格式,例如VirtualServiceList。
singular:单数形式的名称,要求全部小写,例如virtualservice。
plural:复数形式的名称,要求全部小写,例如virtualservices。
shortNames:缩写形式的名称,要求全部小写,例如vs。
categories:CRD所属的资源组列表。例如,VirtualService属于istio-io组和networking-istio-io组,用户通过查询istio-io组和networking-istio-io组,也可以查询到该CRD实例。
使用kubectl create命令完成CRD的创建:
# kubectl create -f crd-virtualservice.yaml
在CRD创建成功后,由于本例的scope设置了Namespace限定,所以可以通过API Endpoint“/apis/networking.istio.io/v1alpha3/namespaces/<namespace>/virtualservices/”管理该CRD资源。
用户接下来就可以基于该CRD的定义创建相应的自定义资源对象了。
2.基于CRD的定义创建自定义资源对象
基于CRD的定义,用户可以像创建Kubernetes系统内置的资源对象(如Pod)一样创建CRD资源对象。
在下面的例子中,virtualservice-helloworld.yaml定义了一个类型为VirtualService的资源对象:
apiVersion: networking.istio.io/vlalpha3
king: VirtualService
metadata:
name: helloworld
spec:
...
除了需要设置该CRD资源对象的名称,还需要在spec段设置相应的参数。
在spec中可以设置的字段是由CRD开发者自定义的,需要根据CRD开发者提供的手册进行配置。
这些参数通常包含特定的业务含义,由CRD控制器进行处理。
使用kubectl create命令完成CRD资源对象的创建:
# kubectl create -f virtualservice-helloworld.yaml
然后,用户就可以像操作Kubernetes内置的资源对象(如Pod、RC、Service)一样去操作CRD资源对象了,包括查看、更新、删除和watch等操作。
查看CRD资源对象:
# kubectl get virtualservice
也可以通过CRD所属的categories进行查询:
# kubectl get istio-io
3.CRD的高级特性
随着Kubernetes的演进,CRD也在逐步添加一些高级特性和功能,包括subresources子资源、校验(Validation)机制、自定义查看CRD时需要显示的列,以及finalizer预删除钩子。
(1)CRD的subresources子资源
Kubernetes从1.11版本开始,在CRD的定义中引入了名为subresources的配置,可以设置的选项包括status和scale两类:
stcatus:启用/status路径,其值来自CRD的.status字段,要求CRD控制器能够设置和更新这个字段的值。
scale:启用/scale路径,支持通过其他Kubernetes控制器(如HorizontalPodAutoscaler控制器)与CRD资源对象实例进行交互。
用户通过kubectl scale命令也能对该CRD资源对象进行扩容或缩容操作,要求CRD本身支持以多个副本的形式运行。
下面是一个设置了subresources的CRD示例:
基于该CRD的定义,创建一个自定义资源对象my-crontab.yaml:
apiVersion: "stable.example.com/v1"
king: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
replicas: 3
之后就能通过API Endpoint查看该资源对象的状态了:
/apis/stable.example.com/v1/namespaces/<namespace>/crontabs/status
并查看该资源对象的扩缩容(scale)信息:
/apis/stable.example.com/v1/namespaces/<namespace>/crontabs/scale
用户还可以使用kubectl scale命令对Pod的副本数量进行调整,例如:
# kubectl scale --replicas=5 crontabs/my-new-cron-object
(2)CRD的校验(Validation)机制
Kubernetes从1.8版本开始引入了基于OpenAPI v3 schema或validatingadmissionwebhook的校验机制,用于校验用户提交的CRD资源对象配置是否符合预定义的校验规则。
该机制到Kubernetes 1.13版本时升级为Beta版。
要使用该功能,需要为kube-apiserver服务开启--feature-gates=CustomResourceValidation=true特性开关。
下面的例子为CRD定义中的两个字段(cronSpec和replicas)设置了校验规则:
校验规则如下:
spec.cronSpec:必须为字符串类型,并且满足正则表达式的格式。
spec.replicas:必须将其设置为1~10的整数。
对于不符合要求的CRD资源对象定义,系统将拒绝创建。
例如,下面的my-crontab.yaml示例违反了CRD中validation设置的校验规则,即cronSpec没有满足正则表达式的格式,replicas的值大于10:
apiVersion: "stable.example.com/v1"
king: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
replicas: 15
创建时,系统将报出validation失败的错误信息:
# kubectl create -f my-crontab.yaml
(3)自定义查看CRD时需要显示的列
从Kubernetes 1.11版本开始,通过kubectl get命令能够显示哪些字段由服务端(API Server)决定,
还支持在CRD中设置需要在查看(get)时显示的自定义列,在spec.additionalPrinterColumns字段设置即可。
在下面的例子中设置了3个需要显示的自定义列Spec、Replicas和Age,并在JSONPath字段设置了自定义列的数据来源:
通过kubectl get命令查看CronTab资源对象,会显示出这3个自定义的列:
# kubectl get crontab my-new-cron-object
(4)Finalizer(CRD资源对象的预删除钩子方法)
Finalizer设置的方法在删除CRD资源对象时进行调用,以实现CRD资源对象的清理工作。
在下面的例子中为CRD“CronTab”设置了一个finalizer(也可以设置多个),其值为URL“finalizer.stable.example.com”:
apiVersion: "stable.example.com/v1"
king: CronTab
metadata:
finalizers:
- finalizer.stable.example.com
在用户发起删除该资源对象的请求时,Kubernetes不会直接删除这个资源对象,而是在元数据部分设置时间戳“metadata.deletionTimestamp”的值,标记为开始删除该CRD对象。
然后控制器开始执行finalizer定义的钩子方法“finalizer.stable.example.com”进行清理工作。
对于耗时较长的清理操作,还可以设置metadata.deletionGracePeriodSeconds超时时间,在超过这个时间后由系统强制终止钩子方法的执行。
在控制器执行完钩子方法后,控制器应负责删除相应的finalizer。
当全部finalizer都触发控制器执行钩子方法并都被删除之后,Kubernetes才会最终删除该CRD资源对象。
4.小结
CRD极大扩展了Kubernetes的能力,使用户像操作Pod一样操作自定义的各种资源对象。
CRD已经在一些基于Kubernetes的第三方开源项目中得到广泛应用,
包括CSI存储插件、Device Plugin(GPU驱动程序)、Istio(Service Mesh管理)等,已经逐渐成为扩展Kubernetes能力的标准。
9.4.2 使用API聚合机制扩展API资源
API聚合机制是Kubernetes 1.7版本引入的特性,能够将用户扩展的API注册到kube-apiserver上,仍然通过API Server的HTTP URL对新的API进行访问和操作。
为了实现这个机制,Kubernetes在kube-apiserver服务中引入了一个API聚合层(API Aggregation Layer),用于将扩展API的访问请求转发到用户服务的功能。
设计API聚合机制的主要目标如下:
增加API的扩展性:使得开发人员可以编写自己的API Server来发布他们的API,而无须对Kubernetes核心代码进行任何修改。
无须等待Kubernetes核心团队的繁杂审查:允许开发人员将其API作为单独的API Server发布,使集群管理员不用对Kubernetes核心代码进行修改就能使用新的API,也就无须等待社区繁杂的审查了。
支持实验性新特性API开发:可以在独立的API聚合服务中开发新的API,不影响系统现有的功能。
确保新的API遵循Kubernetes的规范:如果没有API聚合机制,开发人员就可能会被迫推出自己的设计,可能不遵循Kubernetes规范。
总的来说,API聚合机制的目标是提供集中的API发现机制和安全的代理功能,将开发人员的新API动态地、无缝地注册到Kubernetes API Server中进行测试和使用。
下面对API聚合机制的使用方式进行详细说明。
1.在Master的API Server中启用API聚合功能
为了能够将用户自定义的API注册到Master的API Server中,首先需要配置kube-apiserver服务的以下启动参数来启用API聚合功能。
--requestheader-client-ca-file=/etc/kubernetes/ssl_keys/ca.crt:客户端CA证书。
--requestheader-allowed-names=:允许访问的客户端common names列表,通过header中--requestheader-username-headers参数指定的字段获取。
客户端common names的名称需要在client-ca-file中进行设置,将其设置为空值时,表示任意客户端都可访问。
--requestheader-extra-headers-prefix=X-Remote-Extra-:请求头中需要检查的前缀名。
--requestheader-group-headers=X-Remote-Group:请求头中需要检查的组名。
--requestheader-username-headers=X-Remote-User:请求头中需要检查的用户名。
--proxy-client-cert-file=/etc/kubernetes/ssl_keys/kubelet_client.crt:在请求期间验证Aggregator的客户端CA证书。
--proxy-client-key-file=/etc/kubernetes/ssl_keys/kubelet_client.key:在请求期间验证Aggregator的客户端私钥。
如果kube-apiserver所在的主机上没有运行kube-proxy,即无法通过服务的ClusterIP进行访问,那么还需要设置以下启动参数:
--enable-aggregator-routing=true
在设置完成重启kube-apiserver服务,就启用API聚合功能了。
2.注册自定义APIService资源
在启用了API Server的API聚合功能之后,用户就能将自定义API资源注册到Kubernetes Master的API Server中了。
用户只需配置一个APIService资源对象,就能进行注册了。
APIService示例的YAML配置文件如下:
apiVersion: apiregistration.k8s.io/v1beta1
king: APIService
metadata:
name: v1beta1.custom.metrics.k8s.io
spec:
...
在这个APIService中设置的API组名为custom.metrics.k8s.io,版本号为v1beta1,这两个字段将作为API路径的子目录注册到API路径“/apis/”下。
注册成功后,就能通过Master API路径“/apis/custom.metrics.k8s.io/v1beta1”访问自定义的API Server了。
在service段中通过name和namespace设置了后端的自定义API Server,本例中的服务名为custom-metrics-server,命名空间为custom-metrics。
通过kubectl create命令将这个APIService定义发送给Master,就完成了注册操作。
之后,通过Master API Server对“/apis/custom.metrics.k8s.io/v1beta1”路径的访问都会被API聚合层代理转发到后端服务custom-metrics-server.custom-metrics.svc上了。
3.实现和部署自定义API Server
仅仅注册APIService资源还是不够的,用户对“/apis/custom.metrics.k8s.io/v1beta1”路径的访问实际上都被转发给了custom-metrics-server.custom-metrics.svc服务。
这个服务通常能以普通Pod的形式在Kubernetes集群中运行。
当然,这个服务需要由自定义API的开发者提供,并且需要遵循Kubernetes的开发规范,
详细的开发示例可以参考官方给出的示例(https://github.com/kubernetes/sample-apiserver)。
下面是部署自定义API Server的常规操作步骤:
(1)确保APIService API已启用,这需要通过kube-apiserver的启动参数--runtime-config进行设置,默认是启用的。
(2)建议创建一个RBAC规则,允许添加APIService资源对象,因为API扩展对整个Kubernetes集群都生效,所以不推荐在生产环境中对API扩展进行开发或测试。
(3)创建一个新的Namespace用于运行扩展的API Server。
(4)创建一个CA证书用于对自定义API Server的HTTPS安全访问进行签名。
(5)创建服务端证书和秘钥用于自定义API Server的HTTPS安全访问。服务端证书应该由上面提及的CA证书进行签名,也应该包含含有DNS域名格式的CN名称。
(6)在新的Namespace中使用服务端证书和秘钥创建Kubernetes Secret对象。
(7)部署自定义API Server实例,通常可以以Deployment形式进行部署,并且将之前创建的Secret挂载到容器内部。该Deployment也应被部署在新的Namespace中。
(8)确保自定义的API Server通过Volume加载了Secret中的证书,这将用于后续的HTTPS握手校验。
(9)在新的Namespace中创建一个Service Account对象。
(10)创建一个ClusterRole用于对自定义API资源进行操作。
(11)使用之前创建的ServiceAccount为刚刚创建的ClusterRole创建一个ClusterRolebinding。
(12)使用之前创建的ServiceAccount为系统ClusterRole“system:auth-delegator”创建一个ClusterRolebinding,以使其可以将认证决策代理转发给Kubernetes核心API Server。
(13)使用之前创建的ServiceAccount为系统Role“extension-apiserver-authenticationreader”创建一个Rolebinding,以允许自定义API Server访问名为“extension-apiserverauthentication”的系统ConfigMap。
(14)创建APIService资源对象。
(15)访问APIService提供的API URL路径,验证对资源的访问能否成功。
下面以部署Metrics Server为例,说明一个聚合API的实现方式。
随着API聚合机制的出现,Heapster也进入弃用阶段,逐渐被Metrics Server替代。
Metrics Server通过聚合API提供Pod和Node的资源使用数据,供HPA控制器、VPA控制器及kubectl top命令使用。
Metrics Server的源码可以在GitHub代码库(https://github.com/kubernetes-incubator/metrics-server)找到,
在部署完成后,Metrics Server将通过Kubernetes核心API Server的“/apis/metrics.k8s.io/v1beta1”路径提供Pod和Node的监控数据。
首先,部署Metrics Server实例,在下面的YAML配置中包含一个ServiceAccount、一个Deployment和一个Service的定义:
然后,创建Metrics Server所需的RBAC权限配置:
最后,定义APIService资源,主要设置自定义API的组(group)、版本号(version)及对应的服务(metrics-server.kube-system):
在所有资源都成功创建之后,在命名空间kube-system中会看到新建的metrics-server Pod。
通过Kubernetes Master API Server的URL“/apis/metrics.k8s.io/v1beta1”就能查询到Metrics Server提供的Pod和Node的性能数据了:
# curl http://192.168.18.3:8080/apis/metrics.k8s.io/v1beta1/nodes