解析kubernetes Aggregated API Servers

简介: kubernetes的 Aggregated API是什么呢?它是允许k8s的开发人员编写一个自己的服务,可以把这个服务注册到k8s的api里面,这样,就像k8s自己的api一样,你的服务只要运行在k8s集群里面,k8s 的Aggregate通过service名称就可以转发到你写的service里面去了。

kubernetes的 Aggregated API是什么呢?它是允许k8s的开发人员编写一个自己的服务,可以把这个服务注册到k8s的api里面,这样,就像k8s自己的api一样,你的服务只要运行在k8s集群里面,k8s 的Aggregate通过service名称就可以转发到你写的service里面去了。

这个设计理念:

第一是增加了api的扩展性,这样k8s的开发人员就可以编写自己的API服务器来公开他们想要的API。集群 管理员应该能够使用这些服务,而不需要对核心库存储库进行任何更改。

第二是丰富了APIs,核心kubernetes团队阻止了很多新的API提案。通过允许开发人员将他们的API作为单独的服务器公开,并使集群管理员能够在不对核心库存储库进行任何更改的情况下使用它们,这样就无须社区繁杂的审查了

第三是开发分阶段实验性API的地方,新的API可以在单独的聚集服务器中开发,当它稳定之后,那么把它们封装起来安装到其他集群就很容易了。

第四是确保新API遵循kubernetes约定:如果没有这里提出的机制,社区成员可能会被迫推出自己的东西,这可能会或可能不遵循kubernetes约定。

一句话阐述就是:

Aggregator for Kubernetes-style API servers: dynamic registration, discovery summarization, secure proxy

动态注册、发现汇总、和安全代理。好了基本概念说清楚了,下面就说说实现。

如果你已经已经阅读我上一篇blog就知道,proxy的巨大作用。下面看看这个聚合api的神奇之处。

先看怎么使用,然后再看源代码

apiVersion: apiregistration.k8s.io/v1beta1

kind: APIService

metadata:

name: v1alpha1.custom-metrics.metrics.k8s.io

spec:

insecureSkipTLSVerify: true

group: custom-metrics.metrics.k8s.io

groupPriorityMinimum: 1000

versionPriority: 15

service:

name: api

namespace: custom-metrics

version: v1alpha1

上面定义了资源类型为APIService,service名称为api,空间为custom-metrics的一个资源聚合接口。

下面带大家从源代码的角度来看你

pkg/apiserver/apiservice_controller.go

和k8s其它controller一样,watch变化分发到add、update和delete方法这套原理在此就不赘述了,如果有兴趣可以看我之前写的blog。

apiServiceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{

AddFunc: c.addAPIService,

UpdateFunc: c.updateAPIService,

DeleteFunc: c.deleteAPIService,

})


serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{

AddFunc: c.addService,

UpdateFunc: c.updateService,

DeleteFunc: c.deleteService,

})

主要监听两种资源apiService和service,分别看看

func (s *APIAggregator) AddAPIService(apiService *apiregistration.APIService) error {

// if the proxyHandler already exists, it needs to be updated. The aggregation bits do not

// since they are wired against listers because they require multiple resources to respond

if proxyHandler, exists := s.proxyHandlers[apiService.Name]; exists {

proxyHandler.updateAPIService(apiService)

if s.openAPIAggregationController != nil {

s.openAPIAggregationController.UpdateAPIService(proxyHandler, apiService)

}

return nil

}


proxyPath := "/apis/" + apiService.Spec.Group + "/" + apiService.Spec.Version

// v1. is a special case for the legacy API. It proxies to a wider set of endpoints.

if apiService.Name == legacyAPIServiceName {

proxyPath = "/api"

}


// register the proxy handler

proxyHandler := &proxyHandler{

contextMapper: s.contextMapper,

localDelegate: s.delegateHandler,

proxyClientCert: s.proxyClientCert,

proxyClientKey: s.proxyClientKey,

proxyTransport: s.proxyTransport,

serviceResolver: s.serviceResolver,

}

proxyHandler.updateAPIService(apiService)

if s.openAPIAggregationController != nil {

s.openAPIAggregationController.AddAPIService(proxyHandler, apiService)

}

s.proxyHandlers[apiService.Name] = proxyHandler

s.GenericAPIServer.Handler.NonGoRestfulMux.Handle(proxyPath, proxyHandler)

s.GenericAPIServer.Handler.NonGoRestfulMux.UnlistedHandlePrefix(proxyPath+"/", proxyHandler)


// if we're dealing with the legacy group, we're done here

if apiService.Name == legacyAPIServiceName {

return nil

}


// if we've already registered the path with the handler, we don't want to do it again.

if s.handledGroups.Has(apiService.Spec.Group) {

return nil

}


// it's time to register the group aggregation endpoint

groupPath := "/apis/" + apiService.Spec.Group

groupDiscoveryHandler := &apiGroupHandler{

codecs: Codecs,

groupName: apiService.Spec.Group,

lister: s.lister,

delegate: s.delegateHandler,

contextMapper: s.contextMapper,

}

// aggregation is protected

s.GenericAPIServer.Handler.NonGoRestfulMux.Handle(groupPath, groupDiscoveryHandler)

s.GenericAPIServer.Handler.NonGoRestfulMux.UnlistedHandle(groupPath+"/", groupDiscoveryHandler)

s.handledGroups.Insert(apiService.Spec.Group)

return nil

}

上面path是

proxyPath := "/apis/" + apiService.Spec.Group + "/" + apiService.Spec.Version

1

结合上面的例子就是/apis/custom-metrics.metrics.k8s.io/v1alpha1.

而处理方法请求的handle就是

proxyHandler := &proxyHandler{

contextMapper: s.contextMapper,

localDelegate: s.delegateHandler,

proxyClientCert: s.proxyClientCert,

proxyClientKey: s.proxyClientKey,

proxyTransport: s.proxyTransport,

serviceResolver: s.serviceResolver,

}

proxyHandler.updateAPIService(apiService)

上面的updateAPIService就是更新这个proxy的后端service

func (r *proxyHandler) updateAPIService(apiService *apiregistrationapi.APIService) {

if apiService.Spec.Service == nil {

r.handlingInfo.Store(proxyHandlingInfo{local: true})

return

}


newInfo := proxyHandlingInfo{

restConfig: &restclient.Config{

TLSClientConfig: restclient.TLSClientConfig{

Insecure: apiService.Spec.InsecureSkipTLSVerify,

ServerName: apiService.Spec.Service.Name + "." + apiService.Spec.Service.Namespace + ".svc",

CertData: r.proxyClientCert,

KeyData: r.proxyClientKey,

CAData: apiService.Spec.CABundle,

},

},

serviceName: apiService.Spec.Service.Name,

serviceNamespace: apiService.Spec.Service.Namespace,

}

newInfo.proxyRoundTripper, newInfo.transportBuildingError = restclient.TransportFor(newInfo.restConfig)

if newInfo.transportBuildingError == nil && r.proxyTransport.Dial != nil {

switch transport := newInfo.proxyRoundTripper.(type) {

case *http.Transport:

transport.Dial = r.proxyTransport.Dial

default:

newInfo.transportBuildingError = fmt.Errorf("unable to set dialer for %s/%s as rest transport is of type %T", apiService.Spec.Service.Namespace, apiService.Spec.Service.Name, newInfo.proxyRoundTripper)

glog.Warning(newInfo.transportBuildingError.Error())

}

}

r.handlingInfo.Store(newInfo)
}

这个restConfig就是调用service的客户端参数,其中

ServerName: apiService.Spec.Service.Name + "." + apiService.Spec.Service.Namespace + ".svc",

就是具体的service。

而上面watch service的变化就是为了动态更新这个apiservice后端handler所用的service。

本文转自CSDN-解析kubernetes Aggregated API Servers

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
12天前
|
Java 程序员 API
Java并发基础:concurrent Flow API全面解析
java.util.concurrent.Flow定义了响应式编程的核心接口,促进了Java在异步数据处理和背压机制方面的标准化,这使得第三方库如Reactor和RxJava能够基于这些接口提供丰富的实现和功能,同时简化了响应式编程在Java中的使用,Flow API增强了Java在并发编程领域的灵活性,使得处理异步数据流变得更加自然和高效。
Java并发基础:concurrent Flow API全面解析
|
2月前
|
消息中间件 分布式计算 Java
探究Kafka原理-3.生产者消费者API原理解析(上)
探究Kafka原理-3.生产者消费者API原理解析
28 0
|
4天前
|
存储 Oracle Java
Java 包和 API 深度解析:组织代码,避免命名冲突
Java 中的包 用于将相关的类分组在一起。可以将其视为文件目录中的一个文件夹。我们使用包来避免名称冲突,并编写更易于维护的代码。 包分为两类: 内置包(来自 Java API 的包) 用户定义的包(创建自己的包)
178 2
|
5天前
|
数据挖掘 API 数据处理
获取商品详情信息API接口:1688开放平台功能解析
首先,要获取商品详情信息,开发者需要向1688开放平台申请相应的权限,并遵循其调用规则。在调用商品详情信息API接口时,需要传入相应的请求参数,如商品ID、调用时间戳、密钥等。这些参数对于确保接口的正常运行至关重要。
|
6天前
|
数据采集 安全 API
如何实时获取小红书笔记详情的API使用与解析
小红书是一个以分享消费经验、生活方式为主的社交平台,拥有大量的用户和内容。为了更好地了解用户在小红书上的行为和内容,许多开发者选择使用小红书开放平台提供的API接口。本文将介绍如何通过小红书笔记详情API实现实时数据获取,并给出相应的代码示例。
|
2月前
|
消息中间件 缓存 Kafka
探究Kafka原理-3.生产者消费者API原理解析(下)
探究Kafka原理-3.生产者消费者API原理解析
125 0
|
2月前
|
SQL 数据可视化 API
数据工程实践:从网络抓取到API调用,解析共享单车所需要的数据
在本篇文章中,将解释网络抓取和APIs如何协同工作,从百科上抓取城市数据,利用APIs获取天气数据,从而推断出与共享单车相关的信息。
22 0
数据工程实践:从网络抓取到API调用,解析共享单车所需要的数据
|
3月前
|
JSON API 数据格式
实时获取小红书笔记详情的API使用与解析
小红书是一个以分享消费经验、生活方式为主的社交平台,拥有大量的用户和内容。为了更好地了解用户在小红书上的行为和内容,许多开发者选择使用小红书开放平台提供的API接口。本文将介绍如何通过小红书笔记详情API实现实时数据获取,并给出相应的代码示例。
|
3月前
|
API 开发工具 开发者
全面的开发者文档和用户目标解析:API 文档指南和开发者旅程
开发者文档,也称为 API 文档,是一种专门针对软件开发人员的技术写作形式。这种类型的文档通常包括 API 的技术规范、代码注释、软件设计和架构以及软件开发中涉及的其他详细技术描述。开发者文档是开发人员的重要工具,因为它提供了使用和集成特定软件、库或 API 的必要指南、标准和示例。开发者文档的结构和内容的全面性会根据它所描述的软件的复杂性而大不相同,但主要目的是帮助开发人员理解、使用和高效地为软件做出贡献。
54 2
|
3月前
|
API 开发工具 开发者
通过解析封装关键词搜索速卖通商品列表数据接口,速卖通API接口
通过解析封装关键词搜索速卖通商品列表数据接口,速卖通API接口
25 0

推荐镜像

更多