解析kubernetes Aggregated API Servers

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 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

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
13天前
|
存储 JSON API
深入解析RESTful API设计原则与实践
【9月更文挑战第21天】在数字化时代,后端开发不仅仅是编写代码那么简单。它关乎于如何高效地连接不同的系统和服务。RESTful API作为一套广泛采用的设计准则,提供了一种优雅的解决方案来简化网络服务的开发。本文将带你深入了解RESTful API的核心设计原则,并通过实际代码示例展示如何将这些原则应用于日常的后端开发工作中。
|
13天前
|
缓存 API 网络架构
Nuxt Kit API :路径解析工具
【9月更文挑战第20天】在 Nuxt Kit API 中,路径解析工具如 `resolvePath()`、`joinPaths()` 和 `relativePath()` 帮助开发者高效处理应用路径,确保资源准确加载,并支持动态路由与组件导入。这些工具提升了应用的灵活性和可扩展性,同时需注意路径准确性、跨平台兼容性和性能优化,以提升用户体验。
26 12
|
1月前
|
XML JSON API
淘宝京东商品详情数据解析,API接口系列
淘宝商品详情数据包括多个方面,如商品标题、价格、图片、描述、属性、SKU(库存量单位)库存、视频等。这些数据对于买家了解商品详情以及卖家管理商品都至关重要。
|
2月前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
68 0
|
2月前
|
监控 测试技术 API
|
2月前
|
Java 缓存 数据库连接
揭秘!Struts 2性能翻倍的秘诀:不可思议的优化技巧大公开
【8月更文挑战第31天】《Struts 2性能优化技巧》介绍了提升Struts 2 Web应用响应速度的关键策略,包括减少配置开销、优化Action处理、合理使用拦截器、精简标签库使用、改进数据访问方式、利用缓存机制以及浏览器与网络层面的优化。通过实施这些技巧,如懒加载配置、异步请求处理、高效数据库连接管理和启用GZIP压缩等,可显著提高应用性能,为用户提供更快的体验。性能优化需根据实际场景持续调整。
49 0
|
2月前
|
开发者
告别繁琐代码,JSF标签库带你走进高效开发的新时代!
【8月更文挑战第31天】JSF(JavaServer Faces)标准标签库为页面开发提供了大量组件标签,如`<h:inputText>`、`<h:dataTable>`等,简化代码、提升效率并确保稳定性。本文通过示例展示如何使用这些标签实现常见功能,如创建登录表单和展示数据列表,帮助开发者更高效地进行Web应用开发。
32 0
|
2月前
|
Apache 开发者 Java
Apache Wicket揭秘:如何巧妙利用模型与表单机制,实现Web应用高效开发?
【8月更文挑战第31天】本文深入探讨了Apache Wicket的模型与表单处理机制。Wicket作为一个组件化的Java Web框架,提供了多种模型实现,如CompoundPropertyModel等,充当组件与数据间的桥梁。文章通过示例介绍了模型创建及使用方法,并详细讲解了表单组件、提交处理及验证机制,帮助开发者更好地理解如何利用Wicket构建高效、易维护的Web应用程序。
28 0
|
2月前
|
机器人 API Python
智能对话机器人(通义版)会话接口API使用Quick Start
本文主要演示了如何使用python脚本快速调用智能对话机器人API接口,在参数获取的部分给出了具体的获取位置截图,这部分容易出错,第一次使用务必仔细参考接入参数获取的位置。
121 1
|
12天前
|
安全 API 开发者
Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
在当前的Web开发中,Python因能构建高效简洁的RESTful API而备受青睐,大大提升了开发效率和用户体验。本文将介绍RESTful API的基本原则及其在Python中的实现方法。以Flask为例,演示了如何通过不同的HTTP方法(如GET、POST、PUT、DELETE)来创建、读取、更新和删除用户信息。此示例还包括了基本的路由设置及操作,为开发者提供了清晰的API交互指南。
55 6

推荐镜像

更多
下一篇
无影云桌面