4. Kubernetes API扩展

  • 1. 概述
    • 1.1. 背景需求
    • 1.2. API机制
    • 1.3. 两种API扩展机制
  • 2. 使用CRD扩展API资源
    • 2.1. 创建CRD的定义
    • 2.2. 基于CRD的定义创建自定义资源对象
    • 2.3. CRD的高级特性
    • 2.4. 小结
  • 3. 使用API聚合机制扩展API资源
    • 3.1. 在Master的API Server中启用API聚合功能

1. 概述

1.1. 背景需求

随着Kubernetes的发展,用户对Kubernetes的扩展性也提出了越来越高的要求。

1.7版本开始,Kubernetes引入扩展API资源的能力,使得开发人员在不修改Kubernetes核心代码的前提下可以对Kubernetes API进行扩展,仍然使用Kubernetes的语法对新增的API进行操作,这非常适用于在Kubernetes上通过其API实现其他功能(例如第三方性能指标采集服务)或者测试实验性新特性(例如外部设备驱动)。

1.2. API机制

  • 资源对象的抽象和访问入口: 在Kubernetes中,所有对象都被抽象定义为某种资源对象,同时系统会为其设置一个API入口(API Endpoint),对资源对象的操作(如新增、删除、修改、查看等)都需要通过Master核心组件API Server调用资源对象的API来完成。

  • 交互方式: 与API Server的交互可以通过kubectl命令行工具访问其RESTful API进行。

  • API的不同版本: 每个API都可以设置多个版本,在不同的API URL路径下区分,例如“/api/v1”或“/apis/extensions/v1beta1”等。

使用这种机制后,用户可以很方便地定义这些API资源对象(YAML配置),并将其提交给Kubernetes(调用RESTful API),来完成对容器应用的各种管理工作。

1.3. 两种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扩展机制的概念和用法进行详细说明。

2. 使用CRD扩展API资源

CRD是Kubernetes从1.7版本开始引入的特性,在Kubernetes早期版本中被称为TPRThirdPartyResources,第三方资源)。TPR从Kubernetes 1.8版本开始被停用,被CRD全面替换。

CRD本身只是一段声明,用于定义用户自定义的资源对象!!!

仅有CRD的定义并没有实际作用,用户还需要提供管理CRD对象的CRD控制器!!!(CRD Controller),才能实现对CRD对象的管理

CRD控制器通常可以通过Go语言进行开发,并需要遵循Kubernetes的控制器开发规范,基于客户端库client-go进行开发,需要实现InformerResourceEventHandlerWorkqueue等组件具体的功能处理逻辑.

详细的开发过程请参考官方示例( https://github.com/kubernetes/sample-controller )和client-go库( https://github.com/kubernetes/sample-controller/blob/master/docs/controller-client-go.md )的详细说明。

2.1. 创建CRD的定义

与其他资源对象一样,对CRD的定义也使用YAML配置进行声明。

Istio系统中的自定义资源VirtualService为例,配置文件crd-virtualservice.yaml的内容如下:

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: virtualservices.networking.istio.io # 关键
  annotations:
    "helm.sh/hook": crd-install
  labels:
    app: istio-pilot
spec:
  group: networking.istio.io        # 关键 往下 ↓
  scope: Namespaced                 
  versions:                         
  - name: v1alpha3
    served: true
    storage: true
  names:
    kind: VirtualService
    listKind: VirtualServiceList
    singular: virtualservice
    plural: virtualservices
    categories:
    - istio-io
    - networking-istio-io           # 关键 往上 ↑     

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列表,默认被设置为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
customresourcedefinition.apiextensions.k8s.io/virtualservices.networking.istio.io created

在CRD创建成功后,由于本例的scope设置了Namespace限定,所以可以通过API Endpoint“/apis/networking.istio.io/v1alpha3/namespaces//virtualservices/”管理该CRD资源

用户接下来就可以基于该CRD的定义创建相应的自定义资源对象了。

2.2. 基于CRD的定义创建自定义资源对象

基于CRD的定义,用户可以像创建Kubernetes系统内置的资源对象(如Pod)一样创建CRD资源对象。在下面的例子中,virtualservice-helloworld.yaml定义了一个类型为VirtualService的资源对象:

---
apiVersion: networking.istio.io/v1alpha3    # 重点
kind: VirtualService                        # 重点
metadata:
  name: helloworld                          # 重点
spec:                                       # 重点
  hosts:
  - "*"
  gateways:
  - helloworld-gateway
  http:
  - match:
    - uri:
        exact: /hello
    route:
    - destination:
        host: helloworld
        port:
          number: 5000

除了需要设置该CRD资源对象的名称,还需要在spec段设置相应的参数。在spec中可以设置的字段是由CRD开发者自定义的,需要根据CRD开发者提供的手册进行配置。这些参数通常包含特定的业务含义,由CRD控制器!!!进行处理

使用kubectl create命令完成CRD资源对象的创建:

# kubectl create -f virtualservice-helloworld.yaml
virtualservices.networking.istio.io/hello created

然后,用户就可以像操作Kubernetes内置的资源对象(如Pod、RC、Service)一样去操作CRD资源对象了,包括查看、更新、删除和watch等操作。

查看CRD资源对象:

# kubectl get virtualservice
NAME            AGE
helloworld      1m

也可以通过CRD所属的categories进行查询:

# kubectl get istio-io
NAME            AGE
helloworld      1m

# kubectl get networking-istio-io
NAME            AGE
helloworld      1m

2.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 subresources
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
  - name: v1
    served: true
    storage: true
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct
  subresources:     # 重点 往下 ↓
    status: {}
    scale:
      # 定义从CRD元数据获取用户期望的副本数量的JSON路径
      specReplicasPath: .spec.replicas
      # 定义从CRD元数据获取当前运行的副本数量的JSON路径
      statusReplicasPath: .status.replicas
      # 定义从CRD元数据获取Label Selector(标签选择器)的JSON路径
      labelSelectorPath: .status.labelSelector

基于该CRD的定义,创建一个自定义资源对象my-crontab.yaml:

---
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
  replicas: 3

之后就能通过API Endpoint查看该资源对象的状态了:

......

2.4. 小结

CRD极大扩展了Kubernetes的能力,使用户像操作Pod一样操作自定义的各种资源对象。

CRD已经在一些基于Kubernetes的第三方开源项目中得到广泛应用,包括CSI存储插件Device Plugin(GPU驱动程序)、Istio(Service Mesh管理)等,已经逐渐成为扩展Kubernetes能力的标准

3. 使用API聚合机制扩展API资源

API聚合机制是Kubernetes 1.7版本引入的特性,能够将用户扩展的API注册到kube-apiserver上,仍然通过API ServerHTTP 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聚合机制的使用方式进行详细说明。

3.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聚合功能了。

.......

你可能感兴趣的:(4. Kubernetes API扩展)