作者

张鹏,腾讯云容器产品工程师,拥有多年云原生项目开发落地经验。目前主要负责腾讯云 TKE 云原生 AI 产品的开发工作。

谢远东,腾讯高级工程师,Kubeflow Member、Fluid(CNCF Sandbox) 核心开发者,负责腾讯云 TKE 在 AI 场景的研发和支持工作。

概述

随着 Kubernetes 的日趋成熟,越来越多的公司、企业开始使用 K8s 来构建自己的云原生平台,基于 kubernetes 良好的扩展性以及成熟稳定的架构,你可以快速部署并管理自己的云原生应用。

目前我们也在基于 kubernetes 打造一个云原生 AI 平台(我们称它为:SKAI),该平台具备极致弹性多云兼容性高易用可观测性可复现性的特点,旨在利用云原生的思想和技术,为 AI 场景的数据处理、模型训练、模型上线推理等需求构建弹性可扩展的系统架构,从而提升资源利用率。

为了使我们的平台更加的云原生,我们没有选择常用的 web 框架来构建 API 服务,而是使用 kubernetes 扩展来构建整个平台,这样使我们的平台能更好的和 kubernetes 融合,可以无缝适配任何基于 k8s 的多云混合云环境。

为什么选择 Aggregated APIServer?

选择独立 API 还是 Aggregated APIServer ?

尽管使用 gin、go-restful 等 go 语言 web 框架可以轻易地构建出一个稳定的 API 接口服务,但以 kubernetes 原生的方式构建 API 接口服务还是有很多优势,例如:

  • 能利用 kubernetes 原生的认证、授权、准入等机制,有更高的开发效率;
  • 能更好的和 K8s 系统融合,借助 K8s 生态更快的推广自己的产品,方便用户上手;
  • 借助于 K8s 成熟的 API 工具及规范,构建出的 API 接口更加规范整齐;

但是在很多场景下,我们还是不能确定到底使用聚合 API(Aggregated APIServer)还是独立 API 来构建我们的服务,官方为我们提供了两种选择的对比;如果你不能确定使用聚合 API 还是独立 API,下面的表格或许对你有帮助:

考虑 API 聚合的情况 优选独立 API 的情况
你在开发新的 API 你已经有一个提供 API 服务的程序并且工作良好
你希望可以是使用 kubectl 来读写你的新资源类别 不要求 kubectl 支持
你希望在 Kubernetes UI (如仪表板)中和其他内置类别一起查看你的新资源类别 不需要 Kubernetes UI 支持
你希望复用 Kubernetes API 支持特性 你不需要这类特性
你有意愿取接受 Kubernetes 对 REST 资源路径所作的格式限制,例如 API 组和名字空间。(参阅 API 概述 你需要使用一些特殊的 REST 路径以便与已经定义的 REST API 保持兼容
你的 API 是声明式的 你的 API 不符合声明式模型
你的资源可以自然地界定为集群作用域或集群中某个名字空间作用域 集群作用域或名字空间作用域这种二分法很不合适;你需要对资源路径的细节进行控制

首先我们希望我们的 SKAI 平台能更好的和 k8s 结合,并且它是一个声明式的 API,尽可能的复用 Kubernets API 的特性,显然聚合 API 对我们来说更加适合。

选择 CRDs 还是 Aggregated APIServer?

除了聚合 API,官方还提供了另一种方式以实现对标准 kubernetes API 接口的扩展:CRD(Custom Resource Definition ),能达到与聚合 API 基本一样的功能,而且更加易用,开发成本更小,但相较而言聚合 API 则更为灵活。针对这两种扩展方式如何选择,官方也提供了相应的参考。

通常,如果存在以下情况,CRD 可能更合适:

  • 定制资源的字段不多;
  • 你在组织内部使用该资源或者在一个小规模的开源项目中使用该资源,而不是在商业产品中使用;
    聚合 API 可提供更多的高级 API 特性,也可对其他特性进行定制;例如,对存储层进行定制、对 protobuf 协议支持、对 logs、patch 等操作支持。

两种方式的核心区别是定义 api-resource 的方式不同。在 Aggregated APIServer 方式中,api-resource 是通过代码向 API 注册资源类型,而 Custom Resource 是直接通过 yaml 文件向 API 注册资源类型。

简单来说就是 CRD 是让 kube-apiserver 认识更多的对象类别(Kind),Aggregated APIServer 是构建自己的 APIServer 服务。虽然 CRD 更简单,但是缺少更多的灵活性,更详细的 CRDs 与 Aggregated API 的对比可参考官方文档

对于我们而言,我们希望使用更多的高级 API 特性,例如 "logs" 或 "exec",而不仅仅局限于 CRUD ,所以我们最终选择了 Aggregated APIServer 。

APIServer 扩展的基本原理

kube-apiserver 作为整个 Kubernetes 集群操作 etcd 的唯一入口,负责 Kubernetes 各资源的认证&鉴权,校验以及 CRUD 等操作,提供 RESTful APIs,供其它组件调用:

kube-apiserver 其实包含三种 APIServer:

  • AggregatorServer:负责处理 apiregistration.k8s.io 组下的 APIService 资源请求,同时将来自用户的请求拦截转发给 Aggregated APIServer(AA);
  • KubeAPIServer:负责对请求的一些通用处理,包括:认证、鉴权以及各个内建资源(pod, deployment,service)的 REST 服务等;
  • ApiExtensionsServer:负责 CustomResourceDefinition(CRD)apiResources 以及 apiVersions 的注册,同时处理 CRD 以及相应 CustomResource(CR)的REST请求(如果对应 CR 不能被处理的话则会返回404),也是 apiserver Delegation 的最后一环;

三个 APIServer 通过 delegation 的关系关联,在 kube-apiserver 初始化创建的过程中,首先创建的是 APIExtensionsServer,它的 delegationTarget 是一个空的 Delegate,即什么都不做,继而将 APIExtensionsServer 的 GenericAPIServer,作为 delegationTarget 传给了 KubeAPIServer,创建出了 KubeAPIServer,再然后,将 kubeAPIServer 的 GenericAPIServer 作为 delegationTarget 传给了 AggregatorServer,创建出了 AggregatorServer,所以他们之间 delegation 的关系为: Aggregator → KubeAPIServer → APIExtensions,如下图所示:

如何快速构建 Aggregated APIServer?

虽然官方提供了一个 sample-apiserver,我们可以参考实现自己的 Aggregated APIServer。但完全手工编写太过复杂,也不便于后期维护,我们最终选择了官方推荐的工具 apiserver-builder,apiserver-builder 可以帮助我们快速创建项目骨架,并且使用 apiserver-builder 构建的项目目录结构比较清晰,更利于后期维护。

安装 apiserver-builder 工具

通过 Go Get 安装

$ GO111MODULE=on go get sigs.k8s.io/apiserver-builder-alpha/cmd/apiserver-boot

通过安装包安装

  • 下载最新版本
  • 解压到 /usr/local/apiserver-builder/
  • 如果此目录不存在,则创建此目录
  • 添加/usr/local/apiserver-builder/bin到您的路径 export PATH=$PATH:/usr/local/apiserver-builder/bin
  • 运行apiserver-boot -h

初始化项目

完成 apiserver-boot 安装后,可通过如下命令来初始化一个 Aggregated APIServer 项目:

$ mkdir skai-demo
$ cd skai-demo
$ apiserver-boot init repo --domain skai.io

执行后会生成如下目录:

.
├── BUILD.bazel
├── Dockerfile
├── Makefile
├── PROJECT
├── WORKSPACE
├── bin
├── cmd
│ ├── apiserver
│ │ └── main.go
│ └── manager
│ └── main.go -> ../../main.go
├── go.mod
├── hack
│ └── boilerplate.go.txt
├── main.go
└── pkg
└── apis
└── doc.go
  • hack 目录存放自动脚本
  • cmd/apiserver 是 aggregated server的启动入口
  • cmd/manager 是 controller 的启动入口
  • pkg/apis 存放 CR 相关的结构体定义,会在下一步自动生成

生成自定义资源

$ apiserver-boot create group version resource --group animal --version v1alpha1 --kind Cat --non-namespaced=false
Create Resource [y/n]
y
Create Controller [y/n]
n

可根据自己的需求选择是否生成 Controller,我们这里暂时选择不生成, 对于需要通过 namespace 隔离的 resource 需要增加 --non-namespaced=false 的参数,默认都是 true。

执行完成后代码结构如下:

└── pkg
└── apis
├── animal
│ ├── doc.go
│ └── v1alpha1
│ ├── cat_types.go
│ ├── doc.go
│ └── register.go
└── doc.go

可以看到在 pkg/apis 下生成了 animal 的 group 并在 v1alpha1 版本下新增了 cat_types.go 文件,此文件包含了我们资源的基础定义,我们在 spec 中增加字段定义,并在已经实现的 Validate 方法中完成基础字段的校验。

// Cat
// +k8s:openapi-gen=true
type Cat struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec CatSpec `json:"spec,omitempty"`
Status CatStatus `json:"status,omitempty"`
}
// CatSpec defines the desired state of Cat
type CatSpec struct {
Name string `json:"name"`
}
func (in *Cat) Validate(ctx context.Context) field.ErrorList {
allErrs := field.ErrorList{}
if len(in.Spec.Name) == 0 {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "name"), in.Spec.Name, "must be specify"))
}
return allErrs
}

部署运行

完成以上步骤,你其实已经拥有一个完整的 Aggregated APIServer,接下来我们试着将它运行起来;apiserver-boot 本身提供了两种运行模式:in-cluster、local; local 模式下只作为单独的 API 服务部署在本地方便做调试,过于简单这里不做过多介绍,主要关注一下 in-cluster 模式;in-cluster 可以将你的 Aggregated APIServer 部署在任何 K8s 集群中,例如:minikube,腾讯 TKE,EKS 等,我们这里使用 EKS 集群作为演示。

创建EKS集群&配置好本地kubeconfig

执行部署命令 ;

$ apiserver-boot run in-cluster --image=xxx/skai.io/skai-demo:0.0.1 --name=skai-demo --namespace=default

在执行部署命令过程中,apiserver-boot 主要帮我们做了如下几件事情:

  • 自动生成 APIServer Dockerfile 文件;
  • 通过 APIServer Dockerfile 构建服务镜像,并将镜像推送到指定仓库;
  • 在config目录下生成 CA 及其他 APIServer 部署需要的证书文件;
  • 在config目录下生成 APIServer 部署需要的 Deployment、Service、APIService、ServiceAccount 等 yaml 文件;
  • 将上一步生成的 yaml 文件部署到集群中;

功能验证

确认 Resource 注册成功

$ kubectl api-versions |grep animal
animal.skai.io/v1alpha1

确认 Aggregated APIServer 能正常工作

$ kubectl get apiservice v1alpha1.animal.skai.io
NAME SERVICE AVAILABLE AGE
v1alpha1.animal.skai.io default/skai-demo True 19h

创建并查看新增的 Resource

创建

$ cat lucky.yaml
apiVersion: animal.skai.io/v1alpha1
kind: Cat
metadata:
name: mycat
namespace: default
spec:
name: lucky
# 创建自定义 resource
$ kubectl apply -f lucky.yaml

查找

# 查找自定义 resource 列表
$ kubectl get cat
NAME CREATED AT
mycat 2021-11-17T09:08:10Z
# 查找自定义资源详情
$ kubectl get cat mycat -oyaml
apiVersion: animal.skai.io/v1alpha1
kind: Cat
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"animal.skai.io/v1alpha1","kind":"Cat","metadata":{"annotations":{},"name":"mycat"},"spec":{"name":"lucky"}}
creationTimestamp: "2021-11-17T09:08:10Z"
name: mycat
resourceVersion: "17"
uid: 98af0905-f01d-4042-bad3-71b96c0919f4
spec:
name: lucky
status: {}

总结

本文从实战角度出发介绍我们开发 SKAI 平台过程中选择 Aggregated API 的原因,以及 kube-apisever 的扩展原理,最后介绍了 apiserver-builder 工具,并演示如何一步一步构建起自己的 Aggregated API,并将它部署到 EKS 集群中。希望该篇 Aggregated APIServer 最佳实践可以帮助即将使用 K8s API 扩展来构建云原生应用的开发者。

关于我们

更多关于云原生的案例和知识,可关注同名【腾讯云原生】公众号~

福利:

①公众号后台回复【手册】,可获得《腾讯云原生路线图手册》&《腾讯云原生最佳实践》~

②公众号后台回复【系列】,可获得《15个系列100+篇超实用云原生原创干货合集》,包含Kubernetes 降本增效、K8s 性能优化实践、最佳实践等系列。

【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

Aggregated APIServer 构建云原生应用最佳实践的更多相关文章

  1. 公有云上构建云原生 AI 平台的探索与实践 - GOTC 技术论坛分享回顾

    7 月 9 日,GOTC 2021 全球开源技术峰会上海站与 WAIC 世界人工智能大会共同举办,峰会聚焦 AI 与云原生两大以开源驱动的前沿技术领域,邀请国家级研究机构与顶级互联网公司的一线技术专家 ...

  2. Docker Data Center系列(一)- 快速搭建云原生架构的实践环境

    本系列文章演示如何快速搭建一个简单的云原生架构的实践环境. 基于这个基础架构,可以持续部署微服务架构的应用栈,演练敏捷开发过程,提升DevOps实践能力. 1 整体规划 1.1 拓扑架构 1.2 基础 ...

  3. 腾讯 Techo 开发者大会首发来袭!云原生中间件技术实践等你来!

    腾讯 Techo 开发者大会是由腾讯云发起的面向全球开发者和技术爱好者的年度盛会,2019 年 11 月 6 日 - 7 日将在北京嘉里大酒店首次召开. 作为一个专注于前沿技术研讨的非商业大会,Tec ...

  4. 从 Spark 到 Kubernetes — MaxCompute 的云原生开源生态实践之路

    2019年5月14日,喜提浙江省科学技术进步一等奖的 MaxCompute 是阿里巴巴自研的 EB 级大数据计算平台.该平台依托阿里云飞天基础架构,是阿里巴巴在10年前做飞天系统的三大件之分布式计算部 ...

  5. 百胜中国使用Rainbond实现云原生落地的实践

    百胜中国使用Rainbond实现云原生落地的实践 关于百胜中国 自从1987年第一家餐厅开业以来,截至2021年第二季度,百胜中国在中国大陆的足迹遍布所有省市自治区,在1500多座城镇经营着11023 ...

  6. 基于AWS的云服务架构最佳实践

    ZZ from: http://blog.csdn.net/wireless_com/article/details/43305701 近年来,对于打造高度可扩展的应用程序,软件架构师们挖掘了若干相关 ...

  7. 干货 | 京东云原生容器—SpringCloud实践(一)

    "云原生"成为近年热词并不是一种偶然,它不是一个软件,也不是一种框架,而是一堆理念集合,以及围绕这些理念所产生的一些最佳实践的工具.云原生天然就是作用于服务架构的,可以视作一个服务 ...

  8. 容器服务 TKE 存储插件与云硬盘 CBS 最佳实践应用

    引言 随着自研上云的深入,越来越多的有状态服务对于在 TKE 集群中使用云上存储能力的需求也越来越强烈. 目前腾讯云容器服务 TKE(Tencent Kubernetes Engine已支持在 TKE ...

  9. 藏书馆App基于Rainbond实现云原生DevOps的实践

    我们需要的不是精通Kubernetes的工程师,我们需要一款小白都能用好的管理工具. -- 厦门正观易知科技有限公司运维负责人 郭传壕 大家好,我是厦门正观易知科技有限公司运维负责人郭传壕. 藏书馆是 ...

随机推荐

  1. 国内首篇云厂商 Serverless 论文入选全球顶会:突发流量下,如何加速容器启动?

    作者 | 王骜 来源 | Serverless 公众号 导读 ​ USENIX ATC (USENIX Annual Technical Conference) 学术会议是计算机系统领域的顶级会议,入 ...

  2. 从零入门 Serverless | 架构的演进

    作者 | 许晓斌 阿里云高级技术专家 本文整理自<Serverless 技术公开课>,关注"Serverless"公众号,回复 入门 ,即可获取 Serverless ...

  3. CI/CD-企业级DevOps

    CI/CD-企业级DevOps 什么是DevOps? DevOps是一种思想或方法论,它涵盖开发.测试.运维的整个过程! DevOps强调软件开发人员与软件测试.软件运维.质量保障(QA) 部门之间有 ...

  4. pta天梯训练赛补题

    7-1谁先倒 划拳是古老中国酒文化的一个有趣的组成部分.酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字.如果谁比划出的数字正好等于两人喊出的数字之和,谁就输了,输家罚一杯酒.两人 ...

  5. git 更新与图形界面

    git 软件更新:git update-git-for-windows 或者 git update gitk 是一个历史记录的图形化查看器. 使用:只需 cd 到一个 Git 仓库,然后键入:gitk ...

  6. 锚点布局anchorlayout在kv中的引用

    from kivy.app import App from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.button import ...

  7. OO前三次作业思考(第一次OO——Blog)

    OO前三次作业总结 基于度量分析程序结构 由于三次作业较多,决定分析内容.功能最为复杂的第三次作业. 上图为第三次作业的类图.我使用了一个抽象类Factor,写了五个因子继承Factor,然后又单独开 ...

  8. 自定义注解结合切面和spel表达式

    在我们的实际开发中可能存在这么一种情况,当方法参数中的某些条件成立的时候,需要执行一些逻辑处理,比如输出日志.而这些代码可能都是差不多的,那么这个时候就可以结合自定义注解加上切面加上spel表达式进行 ...

  9. Noip模拟36 2021.8.11

    刚题的习惯还是改不了,怎么办??? T1 Dove打扑克 考场上打的动态开点线段树+并查集,考后发现自己像一个傻子,并查集就行.. 这几天恶补数据结构疯了 用树状数组维护后缀和,$siz_i$表示编号 ...

  10. 常用Java API:Math类

    求最值 最小值 Math.min(int a, int b) Math.min(float a, float b) Math.min(double a, doubleb) Math.min(long ...