都2023了!我不允许你还不了解AIGC!立即报名 了解详情
写点什么

Kubernetes 状态管理与扩展

  • 2018-05-07
  • 本文字数:7751 字

    阅读完需:约 25 分钟

本文通过一个具体实例介绍 Kubernetes 扩展开发,分析了 API Server 的兼容性设计;基于部分源码介绍了 Kubernetes API 聚合层原理和实现;最后还分析了 Kubernetes 提供的工具链和客户端抽象,希望为 Kubernetes 扩展开发提供一些启发 。

状态管理并非新鲜话题,它为中心化系统分发一致的状态,确保分布式系统总是朝预期的状态收敛,是中心化系统的基石之一 。

以 Pod(如下图)为例,它抽象了可以独立部署的最小容器单位,Pod 描述的变化需要反映到对应的容器上,比如修改了 Pod 的 image,它对应的容器就会使用指定的 image 来重建 。

Kubernetes 从 v1.0 开始逐渐形成了完善的 API 框架和工具链,并以此为基础实现了容器管理平台。时至今日(2018 上半年),这套 API 框架和工具链已经演变为 Go 生态圈中的通用状态管理解决方案,大大降低了建立分布式系统的难度。

可惜的是,社区尚未出现对 Kubernetes 状态管理和扩展的详细介绍,官方文档中的只言片语难以支撑复杂的扩展开发需求,本文通过一个具体实例介绍 Kubernetes 扩展开发,分析了 API Server 的兼容性设计;基于部分源码介绍了 Kubernetes API 聚合层原理和实现;最后还分析了 Kubernetes 提供的工具链和客户端抽象,希望为 Kubernetes 扩展开发提供一些启发 。

扩展开发实例

本节介绍一个简单的扩展开发项目来介绍 Kubernetes 扩展的开发模式(代码生成基于 https://github.com/kubernetes-incubator/apiserver-builder ),这是典型的 C/S 架构,分为 APIServer 和客户端两部分,APIServer 提供了高可用的状态存储,而客户端提供了资源的 CRUD 和可靠的状态分发接口。

先来初始化整个项目框架(这个工具的实现目前还不稳定,不同版本的 apiserver-boot 生成的代码可能存在差异)。

后续章节将介绍详细介绍扩展开发的过程。

API Server

项目初始化完成之后就可以定义状态了,为了让例子更具一般性,本文将定义多个版本的状态并在后续章节介绍 APIServer 的兼容性设计。

执行如下命令生成第一个版本的状态定义模板:v1alpha1.Bee。

$ apiserver-boot create resource --group alpha --version v1alpha1 --kind Bee然后为生成的 v1alpha1.Bee 添加自定义的信息(如图 1.1.1)。

运行以下命令将修改后的状态定义变化应用到整个项目中去。

$ apiserver-boot build generated生成代码时会把所有的子命令打印出来(如图 1.1.2),随后可以利用局部代码生成来对生成代码进行微调。

然后将这个自定义的API Server 部署到一个Kubernetes 集群中,注意这里部署的API Server 是一个实现了Kubernetes API 规范的独立的Web 服务,与集群Master 是完全独立的,仅仅是集群中的一个普通的Pod 而已,可以有完全独立于Master API Server 的ETCD 存储。

由于此处的APIServer 实现了Kubernetes API 规范,可以通过kubectl 来直接写入一个v1alpha1.Bee,然后再用kubectl 读取刚刚写入的v1alpha1.Bee(如图1.1.3),也可以用kubectl 来修改图1.1.3 中写入的Bee 的location 信息(如图1.1.4)。

有了基本的存储之后就需要考虑状态修改时的校验,可以为状态描述实现任意形式的扩展逻辑,图1.1.5 中为v1alpha1.Bee 添加自定义校验,限定location 必须以China 结尾。

添加了图1.1.5 中的校验之后,图1.1.3 中给出的Bee 描述已经不再合法,这时如果尝试再次写入该数据就会出现校验失败(如图1.1.6)。

图1.1.7 将location 更正为China 结尾后就可以正常写入v1alpha1.Bee 了。

以上是定义一个v1alpha1.Bee 状态描述的基本过程。

细心的读者可能已经发现,在写入一个Bee 之后,如果修改了Bee 的校验规则,那么前面已经写入的Bee 可能已经不合法了,就会出现脏数据,这个问题怎么解决呢?工程上我们应该规避这种情况,RESTful API 中一个基本设计原则就是“不可变资源”,这里所谓的“不可变”指的是资源涉及的各种上下文,包括Schema、校验、安全、SLA 等等,如果出现上下文改变,应该为资源提供新的版本。

为了介绍状态定义的兼容性设计,图1.1.8 为Bee 这个状态增加一个新版本v1alpha2.Bee,Spec 还需要增加一个额外的字段Gender(作者按:虽然蜜蜂分男女有点扯,这里仅仅是为了表达在一个新版本的Bee 中添加字段,后文不再解释)。

图1.1.9 中使用kubectl 同时写入v1alpha1.Bee 和v1alpha2.Bee。

客户端

扩展客户端连接到前文实现的API Server 来监听Bee 的变化,进而在客户端实现自定义扩展逻辑,图1.2.1 中为Bee 实现的客户端扩展的基本工作流。

前文自动生成的代码中为Bee 生成了默认的BeeController,如图1.2.2 所示。

当监听到创建或更新Bee 状态的时候,可以通过实现Reconcile 中的逻辑来处理对Bee 的额外扩展,现在来把Controller 部署到集群中去。

将前面写入的Bee 全部删除后重新写入,可以看到Controller 打印了两条日志分别为写入的Bee.Name,如图1.2.3 所示。

此处提到的Reconcile 接口只能响应存在状态修改的场景,是一种无状态的扩展模式,如果需要响应删除,可以利用后文介绍的Informer 接口来实现,此处不赘述,只给一个简单例子(如图1.2.4)。有趣的是,BeeController 部署到集群里面,没有进行额外配置就可以连接到对应的APIServer 正常运转了,它是如何自动与前文部署的API Server 建立连接呢?这在后文“API 聚合层”中会具体介绍,此处亦不赘述。

注意删除了前面写入的v1alpha1.Bee 和v1alpha2.Bee 两个版本的Bee,但实际上BeeController 是利用v1alpha1 客户端监听Bee 的删除事件,显然v1alpha1 的Informer 也可以感知到所有版本Bee 的变化,这其实就是兼容性设计的美妙之处了,不赘述。

小结

复杂系统中,客户端的维护周期是随机的,设想一个没有兼容性的系统,在运营一段时间后,客户端扩展由于升级维护周期的差异使用了不同版本的客户端实现,这样的系统任何一个点的变化对系统中其他模块可能都存在强依赖,这种耦合可能导致系统不得不部分重启,最终这个系统将陷入举步维艰的泥潭。可以说兼容性设计是Kubernetes 高度可扩展性的基础之一,图1.3.1 为多版本Bee 的兼容性设计模型。

图1.3.1 中写入和存储Bee 的时候支持全部版本,而API Server 为每个版本的Bee 的读取接口实现了兼容性适配。当写入原始状态为v1alpha1.Bee,所有客户端都可以感知到这个状态,同理写入状态v1alpha2.Bee 时,所有客户端也都可以感知到这个状态变化。

先往API Server 写入v1alpha1.Bee 和 v1alpha2.Bee 两个Bee 状态描述,如图1.3.2 所示 。

进入etcd 中看实际写入的v1alpha1.Bee 和v1alpha2.Bee 数据(如图1.3.3),可见状态存储和写入时的输入是一致的。

特别提一下,在Kubernetes API 设计规范中,{Group, Namespace, metadata.name} 这个三元组是全局唯一的,尽管此处写入的两个Bee 分别为不同的版本,还是可以从所有版本的读取接口拿到这些状态(如图1.3.4,1.3.5),这就是为什么图1.2.4 中只需使用v1alpha1 客户端就可以接受到删除 v1alpha1.Bee 和v1alpha2.Bee 的事件。

图1.3.4 和1.3.5 直接使用curl 命令分别从v1alpha1 和v1alpha2 的API 来获取Bee 列表,这进一步佐证了兼容性设计是在API Server 实现的。

在不同版本的Bee 之间互相转换如果少了字段,比如图1.3.5 中通过v1alpha2 客户端读取v1alpha1.Bee,gender 字段为空,这可能是有问题的,v1alpha2 客户端拿到这样的数据可能会出现不预期的行为,应该保证客户端取到的数据满足相应版本的约束。

这就需要APIServer 提供默认值的支持了,下面来为v1alpha2 添加默认值支持,将gender 默认设置为Unknown ,如图1.3.6 所示。

兼容性设计是困扰很多复杂系统设计者的问题,Kubernetes 中的兼容性设计模式不仅是RESTful 设计模式的成功应用,也为复杂系统设计提供了一种通用解决方案。

API 聚合层

前面的实例中,Controller 部署到集群中就能直接访问 Bee 资源,实际上在部署 API Server 时还为其配置了 API 聚合层,将这个独立的 API Server 整合到集群的 API Server 中去了,就好像是 Kubernetes API 提供了 Bee 这个 Resource 一样。

API 聚合层是 Kubernetes API 扩展性的基础,将自定义资源整合到 Kubernetes API 中,为容器管理平台或相关插件提供状态存储(源码分析基于:f7aafaeb404563cda07b182ad9679f54afd227fe)。

API Service

Kubernetes 在早期版本中就提供了 API Service 支持,最初是为了支持将庞大的 API Server 分散在多个独立的 API Server 中去。它定义了一组灵活的反向代理接口,只要接入的 API Server 的设计满足 Kubernetes 的 API 设计,就可以整合到 Kubernetes 的 API 中去,集群已有的组件可以直接与新加入的 API Server 来做集成,图 2.1.1 为 API Service(v1) 的定义。

图2.1.2 中将自定义的API Server(evangelist-apiserver) 整合到Kubernetes API 中去。

这样就可以直接通过kubectl 来管理该API 扩展的状态了,图2.1.3 中使用kubectl 来管理Bees。

API Service 定义中如果指定了 Service,API Aggregator 会为该 Service 添加一个反向代理配置,图 2.1.4 是 API Service 资源改动后生成反向代理的实现。

每个API Service 对都对应了独立的proxyHandler,是针对特定URL 的反向代理。

Custom Resource Definition

Custom Resource Definition(CRD) 的前身是 Third Party Resource(TPR),是 API Service 的一种扩展接口,其中 TPR 已经在 v1.7 之后被废弃,v1.8 之后彻底从代码中移除,因此这里只介绍 CRD 的基本实现原理。CRD 为状态管理扩展定义了以下三种能力:

  • 定义任意类型的资源
  • 定义基于 Open API Schema 的校验
  • 定义资源(Resource)生命周期中钩子(Hook)

向集群中写入该CRD,就在该APIServer 中注册了一个名为Bee 的资源,并且对资源加入和校验支持,接下来就可以用kubectl 直接管理图2.2.1 中定义的Bee 资源了(如图2.2.2)。

CRD 是基于 API Service 实现的,Kubernetes 为 CRD 自动保持一个针对 Kube API 的 API Service 配置(如图 2.2.3)。

值得一提的是,CRD 的两个特点:

  • 由 Kube API 提供服务
  • 代码里面写死了优先级(如图 2.2.4),即 versionPriority(100) 和 groupPriorityMinimum(1000)

小结

Kubernetes APIServer 的基本功能之一是反向代理,APIService 提供了动态配置接口,可以为相同的转发条件定义多个优先级不同的 APIService,这样的设计很重要,保证了 Kubernetes APIServer 在切换转发配置对客户端完全透明(Zero Downtime)。

在前文“扩展开发实例”中没有采用 CRD 来实现 APIServer 扩展,这是因为 CRD 存在两方面的局限性:

  • 没有 sub-resource 支持:因此 status 和 spec 一样都是可以被 kubectl 修改的,这其实打破了 Kubernetes API 设计的基本假设
  • 缺少兼容性支持:多版本 Schema 之间互相转化通常需要自定义代码逻辑来实现,这在未来 CRD 中也是不可能支持的

CRD 提供了一种有限的、轻量级的 APIServer 扩展,在技术选型中需要考察是否存在下面的需求来决定是否选择 CRD:

  • 避免 status 被 kubectl 篡改:在多个客户端共享状态,如果 status 被 kubectl 人为篡改可能导致系统出现不预期的行为
  • 零宕机(Zero Downtime)升级:客户端和 APIServer 需要在升级维护的任意时间点保证兼容性和正确可预期的行为

CRD 会自动保持相应的 APIService 设置,即使该 APIService 被篡改,CRD Controller 也能够自动恢复正确的 API Service 配置,这也意味着如果要用自定义 APIServer 来替换已有的 CRD 服务,需要先将 CRD 删除再写入新的 APIService 配置,否则该配置会被 CRD 自动覆盖。

代码生成

Kubernetes 提供了丰富的代码生成工具用来管理 RESTful 状态的定义和客户端代码,维护状态定义的过程就是为各模块之间状态流转定义 Service Contract。

客户端生成

本节介绍客户端代码生成工具,文中提到了 Tag 的“作用域”,在 Go 语言中没有具体的定义,这里给出一种泛泛的描述:

  • Local Tag:Struct/Field/Function 定义之前,用来约束局部代码生成规则
  • Global Tag:Package 下 doc.go 的 package 关键字前,作为整个 Package 下的默认生成规则,可以被 Local Tag 覆盖

先看 deepcopy-gen,它提供了“深复制”接口生成能力,在执行一些可能会修改对象内容的操作时,“深复制”可以保护原始对象内容,让系统中对象的边界更清晰。

如图 3.1.1 中计算容器的 Resource Limit 时,需要同时考虑节点可分配的资源,最终结果会是二者合并的结果,所以这里在计算前先将 container 深复制一个临时对象,然后合并直接在这个临时对象上进行。

k8s:deepcopy-gen:声明是否生成 DeepCopy 接口,添加的位置决定了该 Tag 的作用域,可以添加到 Package(任意文件 package 关键字前)或 Struct 前,取值相关含义如下:

  • true/false: 是否生成 DeepCopy 接口,常用于声明某些 Struct 不需要生成 DeepCopy
  • package: 只用于 Package 域,为该 Package 下所有未显式禁用 DeepCopy 的类型全部生成 DeepCopy 接口

k8s:deepcopy-gen:nonpointer-interfaces: 声明是否为某类型生成值类型的 DeepCopy 接口,只能作用于 Struct 域

  • true/false:生成值类型 DeepCopy 接口,否则为指针类型

k8s:deepcopy-gen:interfaces:指定为 Struct 生成返回任意接口类型的 DeepCopy 接口,取值为逗号分隔的类型全名。

接下来介绍conversion-gen 和defaulter-gen,这两个工具的作用时相辅相成的,它们为多版本Resource 提供了服务端自动转换的能力,比如前面例子中提到的v1alpha1.Bee 和v1alpha2.Bee 之间的自动转换。

图3.1.6 的例子中v1alpha1.Bee 向v1alpha2.Bee 转换时,缺少了gender 字段,在v1alpha2.Bee 中赋值为缺省值Unknown;而v1alpha2.Bee 向v1alpha1.Bee 转换时,只需要将它的location 字段赋值给v1alpha1.Bee 即可。

再看conversion-gen,它实现了不同版本的Resource 在服务端自动转换的能力,这在API 兼容性设计中起到了至关重要的作用,是笔者看来这也是最常用的代码生成工具。

k8s:conversion-gen 为“源 Package”和“目标 Package”之间的同名 Struct 生成自动转换代码:

  • true/false: 声明是否注册 Conversion 逻辑,作用域可以为 Struct 和 Field。
  • Package 名:声明为当前 Package 和传入的 Package 中同名 Struct 生成 Conversion 逻辑

k8s:conversion-gen-external-types: 指定生成 Conversion 的“当前 Package”位置,这是因为有时候当前 Package 中 Resource 定义是独立维护的。

需要注意的是,图3.1.8 中“源类型”Package 需要保证和“目标”Package 分属不同的版本,否则生成的Method 会出现重名的情况,无法编译。

类型转换是Go 开发中一个比较麻烦的地方,加之语言层面反射的性能和标准库支持都限制了开发的灵活性,自动转换接口为API 在进行兼容性的转换时做到游刃有余。

最后看defaulter-gen,在定义了SetDefaults 函数(图3.1.9)之后,为之自动生成Object/List 等使用场景的Defaulter 函数和注册逻辑。

生成Defaulter 注册函数后,还需要注册RegisterDefaults(图3.1.10)函数将该默认值规则应用于任意Scheme 的初始化阶段,在该Scheme 的作用范围内就会使用输入的默认值规则。

defaulter-gen 在维护状态完整中起到至关重要的作用,如果不同版本的 Resource 互相转换时,缺失的字段默认为零值,而有了初始化默认值的能力后,就能保证转换的结果始终满足对应 Resource 的语义约束,如前面例子中 v1alpha2 中增加了 Gender(性别) 后,读取 v1alpha1 数据时,Gender 字段默认给出的是空字符串,这显然在语义上是说不通的。

k8s:defaulter-gen:

  • true/false: 如果作用域为 Type,则声明是否为 Type 生成 Defaulter;如果作用于
  • Function 常用来生成明明满足 SetDefault_$Name 格式的 Function

FIELDNAME: 声明为所有含有传入的 Field 的 Type 生成 Defaulter,作用域为 Package

k8s:defaulter-gen-input:用来指定生成 Defaulter 的输入 Package。

图 3.1.11 指定 “…/…/…/…/vendor/k8s.io/api/apps/v1” 作为实际 Struct 的输入,在当前目录生成 Defaulter 注册逻辑。

此外Kubernetes 中为构建灵活的扩展提供了丰富的高层代码生成工具,超出本文要论述的范畴,不赘述。

客户端抽象

代码生成工具还可以为扩展程序生成三种常用的客户端抽象:Clientset, Lister, Informer。

相比状态定义的代码生成工具的复杂配置,客户端代码生成通常使用默认配置即可。

其中Clientset 封装了对Resource 以及对应集合类型的基础CRUD 以及常用复杂读写接口;Lister 封装了对Resource 按照Label 过滤的接口;Informer 提供了状态主动分发能力,让客户端能监听服务端状态的变化并执行相应的回调逻辑。Lister 和Informer 和API Server 通信都基于Clientset 实现。

client.AlphaV1alpha2().Bees(“default”) 返回的 BeeInterface 封装了具体版本的 RESTful 接口,此处就是 v1alpha2 的 RESTful 接口,正如前文兼容性设计介绍的,v1alpha2 客户端是可以读取 v1alpha1.Bee 的 。

此处 AddEventHandler 可以传入 ResourceEventHandler 接口,允许实现三个回调函数,如图 3.2.3 所示。

  • OnAdd:创建 Resource 时
  • OnUpdate:修改 Resource 时,或定时获取最新的 Resource 状态时
  • OnDelete:删除 Resource 时

其中值得一提的是 OnUpdate 被调用时,Resource 不一定真的被修改,也可能只是定时获取 Resource 最新的状态,这个回调函数常用在启动后来自动恢复客户端的状态。

小结

代码生成除了需要结合各种需求灵活使用 Tag 之外,大部分的工具生成的代码都是可以局部自定义的,比如现在有 alpha/v1alpha2.Bee 和 beta/v1beta1.Bee 两个版本的 Bee,并为它们生成了 conversion 逻辑,有时会希望自定义生成的逻辑,只需要在 conversion 代码所在 Package 下任意代码文件添加具有相同签名的函数,代码生成工具就会忽略该函数,充分利用代码生成工具的前提下又不失其灵活性(如图 3.3.1)。

总结

自v1.0 开始,Kubernetes API 形成一套完整的状态管理解决方案, 其高度灵活的API Server 和客户端实现可以为任意复杂系统提供状态管理支持 。

让人眼前一亮的是它的兼容性设计,它为第三方扩展提供了稳定的接口;第三方扩展集成到平台中后,维护周期可以和平台保持相对独立。兼容性设计对微服务模块的设计和实现也具有极强的指导意义,微服务中一个重要的指导原则之一就是“自治”,模块之间的Service Contract 不但需要做到稳定可靠,还需要做到向下兼容,否则就会出现模块之间互相影响,就与“自治”这个基本假设矛盾了。

API 聚合层不仅为 Kubernetes APIServer 提供了无限横向扩展能力,独立的 APIServer 可以拥有独立的存储(不一定是 ETCD),这意味着数据量不再是 APIServer 的瓶颈,也让客户端插件无缝集成成为可能。

还有 Kubernetes 提供的代码生成工具链也很值得借鉴, 这些工具不但极大的降低了扩展开发的成本,还为自动生成的代码提供了定制能力。

他山之石可以攻玉,Kubernetes 作为 Google 的重要开源项目之一,集中体现了 Google 优秀的分布式系统实践,也为 Go 社区提供了诸多良好的典范。

作者简介

杨谕黔,FreeWheel 基础架构部 高级软件工程师。 目前主要从事服务化框架、容器化平台相关的研发与推广。关注和感兴趣的技术主要有 Golang, Docker, Kubernetes 和它们的周边生态。

2018-05-07 18:297762

评论 1 条评论

发布
用户头像
非常赞的一篇文章!有两个问题请教一下:
1,CRD的主要优势是什么?既然已经有了聚合层API(而且还更灵活),为什么还有推出CRD?
2, CRD 的namespaced scope 和 cluster scope 有什么区别?如何选择?
2019-04-17 22:53
回复
没有更多了
发现更多内容

Wallys miniPCIe wlan modules/ QCA9880 /2.4G&5G

Cindy-wallys

QCA9880

GitHub标星30k!基于Spring MVC Mybatis分布式开发系统-zheng项目(内附源码)

Java你猿哥

开源 架构设计 分布式架构 JavaEE zheng

JVM调优实战:优化Java应用程序的性能

做梦都在改BUG

Java JVM 性能调优

【安全运维】免费运维软件有哪些?哪款好用一点?

行云管家

运维 安全运维 免费 小微企业

区块链DAPP互助逻辑模式系统开发技术方案

I8O28578624

NFTScan:05.15~05.21 NFT 市场热点汇总

NFT Research

IPQ8072 or IPQ8072A with the QCN9074/9024 chipset / well-suited for high-end routers.

Cindy-wallys

IPQ8072

DAPP合约拆分公排模式项目系统开发技术讲解

I8O28578624

阿里、字节等大佬神创,必须是全网最全的Netty核心原理手册

Java你猿哥

Java 源码 Netty ssm netty内存管理

真香!阿里最新产出分布式进阶实战手册,涵盖分布式架构所有操作

Java你猿哥

架构 微服务架构 Spring Cloud Spring Boot ssm

系统梳理面试6大专题,阿里爆款Java面试速成笔记也太香了

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

系统梳理面试6大专题,阿里爆款Java面试速成笔记也太香了

Java你猿哥

Java MySQL redis MQ java面试

在行 | 唱响钢铁冶金行业绿色发展进行曲

用友BIP

云从科技进入百模大战,行业大模型成为胜负手

ToB行业头条

聊聊 万亿流量场景下的负载均衡实践

Java你猿哥

负载均衡 ssm 高并发 DNS 负载均衡架构

直击面试!阿里技术官手码12W字面试小册在Github上爆火

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

SpringBoot限制接口访问频率 - 这些错误千万不能犯

做梦都在改BUG

Java spring Spring Boot 框架

深化企业数据智能应用 用友敢当“急先锋”

用友BIP

2023用友BIP技术大会

刷爆LeetCode!字节技术官亲码算法面试进阶神技太香了

做梦都在改BUG

Java 数据结构 算法 LeetCode

学会这招,来给你的 SpringBoot 工程部署的 jar 包瘦瘦身吧!

Java你猿哥

Java jar Spring Boot ssm

面试官:Spring Boot 的启动流程你了解吗?我:。。

Java你猿哥

Java spring Spring Boot ssm main

最全iOS 上架指南

雪奈椰子

优秀!阿里甩出GC面试小册,仅7天Github获赞96.9K

做梦都在改BUG

Java JVM 垃圾回收 GC

共享电单车生产厂家排名!怎么选?

共享电单车厂家

共享电动车厂家 共享电单车生产 本铯共享电动车 共享电单车厂家排名

【活动预告】数据集成引擎BitSail遇上CDC

字节跳动数据平台

数据集成平台 bitsail

阿里开源SpringBoot全栈小册!Github已标星百万

做梦都在改BUG

Java spring Spring Boot 框架

2023年企业降低云支出的小方法汇总

行云管家

云计算 云资源 云成本 云支出

进阶面试皆宜!阿里强推Java程序员进阶笔记,差距不止一点点

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

【全网首发】华秋CAM:免费Gerber查看器,离线版!

华秋电子

华为云加速器首期加速营圆满结营,40+位创业者携手出海

科技热闻

3F聆听

郭明

  • 需要帮助,请添加网站小助手,进入 InfoQ 技术交流群
Kubernetes 状态管理与扩展_DevOps & 平台工程_杨谕黔_InfoQ精选文章