作者: 靖立明
前言
BizWorks 与 KubeVela 的合作始于 1.0.5 版本,BizWorks 在 1.0.5 版本上完成了关键技术验证并且在 1.2.5 版本上基础上扩展了 BizWorks 的应用部署和运维能力。通过近一年多的深度合作,BizWorks 通过 KubeVela 解决了一些痛点和诉求,同时基于 KubeVela 功能和特性也沉淀了一些实践,本文将分别通过介绍 BizWorks 在 KubeVela 使用场景来讲述如何探索和实践云原生时代新一代 PaaS 平台持续交付能力的落地。
BizWorks 介绍
BizWorks(https://bizworks.aliyun.com/)是一体化的阿里云原生应用的开发和运营平台,内置阿里巴巴业务中台构建的最佳技术实践。产品主要包括:业务建模平台、业务应用平台、演练压测平台、能力运营平台、一体化运行和运维平台。BizWorks 提供的产品能力(图1-1),普遍适用于企业云原生应用高效开发以及企业业务能力沉淀和复用的场景。
图 1-1 BizWorks 业务架构
BizWorks 一体化运行和运维平台提供一站式的应用生命周期管理、运行托管和运维管控能力,支持多云适配,因此应用的生命周期管理是不可或缺的,其中 CICD 作为应用持续演进的关键方式对客户产品发布以及升级迭代扮演着至关重要的角色。
CI(持续集成)主要包括中台类应用、低代码类轻应用、托管类应用、集成类应用的构建和物料产出,为客户透出个性化流水线能力,可以依据用户实际需求编排符合业务需求的流水线,也可以直接使用业界沉淀的通用流水线产品。
CD(持续交付/持续部署)主要包括上述几类应用构建制品部署上线以及运维,为客户提供核心的部署操作能力,用户可以基于内置的部署引擎完成应用的部署,同时也可以接入其他部署产品,例如 EDAS。
本文将主要讲述探索如何使用 KubeVela 在 BizWorks 一体化运行和运维平台应用部署中落地。
应用交付的需求与落地
需求背景
BizWorks 对于应用交付的需求主要包括两个思考,第一个是在云原生技术背景下,应用交付应该基于云原生技术架构进行设计,因此采用的应用交付技术选型要能够支持相应的技术组件诉求;第二个是从业务需求出发,当前应用交付配置面临碎片化的境况,包括环境配置、资源规格配置、持久化配置、网络路由配置等,同时对于应用交付制品类型也不尽相同。为了满足上述的需求,BizWorks 选择使用 KubeVela 来实现应用的持续交付,保证客户环境交付终态的稳定性和可靠性。
应用部署架构
目前 Bizworks 支持四种类型的业务应用,集成了部分开源或阿里云的中间件组件,其部分能力主要是通过使用 KubeVela 的 Application、Component、Trait 以及 WorkFlow 来实现(如图 2-1)。在 KubeVela Component 基础上 BizWorks 定义自己的无状态组件(stateless-component)、有状态组件(stateful-component)、组装网络(advanced-ingress-trait)等,然后通过 KubeVela 来屏蔽不同云厂商或 Kubernetes 底座的复杂性和差异性,构成了当前 BizWorks 的应用部署架构。
图 2-1 BizWork 应用部署业务架构
碎片化配置的痛点与解决
对于平台来说提供的功能如果具有可扩展和灵活性的话,可以为平台增强现有能力和推出更好体验的功能点带来强大的帮助。但是由于平台面对的使用者背景和诉求各不相同,为了能尽可能满足大多数场景需求可能会导致配置化内容变得多而且散乱,这是当时面临的碎片化配置痛点。BizWorks 的解决方案是借助 KubeVela 丰富和强大的插件和运维特征补丁功能,首先 KubeVela 的拥有很多常见的插件,例如分批发布、fluxcd 等,并且也内置了很多可用性高的运维特征补丁,例如标签、注解、init-container、ingress 等。如果没有定制化需求的话,使用 KubeVela 自带的插件和运维特征补丁基本就可以满足需求;如果需要针对平台自身能力进行定制的话也是可以的,这里以自定义运维特征补丁为例,介绍下 BizWorks 如何实现自定义功能。
BizWorks 应用在发布时,可以支持用户自己配置网络路由(如图 2-2),因此就需要支持同时生效多个 ingress 和 service 的配置。我们在 KubeVela 内置的 ingress 运维特征基础上进行了改进,支持批量传入声明的网络路由配置,然后通过 BizWorks 以自定义运维特征的方式下发到 KubeVela(相关 cue 定义见下方示例代码),最终生效到集群中。
"bizworks-ingress-comp-1-22": {
type: "trait"
annotations: {}
description: "Enable public web traffic for the component, the ingress API matches K8s v1.20+."
attributes: {
podDisruptive: false
}
}
template: {
outputs: {
// trait template can have multiple outputs in one trait
if parameter.route != _|_ {
for _, v in parameter.route {
"service-(v.serviceName)": {
apiVersion: "v1"
kind: "Service"
metadata:
name: v.serviceName
spec: {
selector: "app.oam.dev/component": context.name
if v.serviceType != _|_ {
type: v.serviceType
}
ports: [
{
port: v.servicePort
protocol: v.serviceProtocolType
targetPort: v.port
},
]
}
}
if v["ingressName"] != _|_ {
"ingress-(v.ingressName)": {
apiVersion: "networking.k8s.io/v1"
kind: "Ingress"
metadata: {
name: v.ingressName
annotations: {
if !v.classInSpec {
"kubernetes.io/ingress.class": v.class
}
if v.annotations != _|_ {
for _, t in v.annotations {
"(t.name)": t.value
}}
}
}
spec: {
if v.classInSpec {
ingressClassName: v.class
}
if v["ingressProtocolType"] == "HTTPS" {
tls: [{
hosts: [
v.domain,
]
secretName: v.secretName
}]
}
rules: [{
host: v.domain
http: {
paths: [
{
path: v.path
pathType: "ImplementationSpecific"
backend: service: {
name: v.serviceName
port: number: v.servicePort
}
},
]
}
}]
}
}
}
}
}
}
parameter: {
route: [...{
// +usage=Specify the port your server want to expose
port?: int
// +usage=Specify the protocol your service want to expose
serviceProtocolType?: string
// +usage=Specify the name your service want to expose
serviceName?: string
// +usage=Specify the port your service want to expose
servicePort?: int
// +usage=Specify the type your service want to expose
serviceType?: string
// +usage=Specify the type your ingress want to expose
ingressProtocolType?: string
// +usage=Specify the name your ingress want to expose
ingressName?: string
// +usage=Specify the domain you want to expose
domain?: string
// +usage=Specify the path you want to expose
path?: string
// +usage=Specify the tls secret you want to use
secretName?: string
annotations?: [...{
name: string
value: string
}]
// +usage=Specify the class of ingress to use
class: *"nginx" | string
// +usage=Set ingress class in '.spec.ingressClassName' instead of 'kubernetes.io/ingress.class' annotation.
classInSpec: *false | bool
}]
}
}
图 2-2 BizWorks 应用网络路由配置
实践案例
首先以一个无状态组件应用发布为例,介绍如何使用 KubeVela 完成应用发布计划。BizWorks 继承 OAM 设计理念,将应用作为一个交付的整体,其内部由不同类型的组件构成,并且组件可以通过绑定自定义运维特征补丁。应用内的组件可以按照自己的发布计划自行发布,并且组件之间产生的工作负载和网络拓扑不会彼此影响,具体见图 2-3.
图 2-3 BizWorks 应用发布计划
BizWorks 还支持通过 helm chart 来部署复杂结构的应用组件,并且和无状态组件一样,支持一个应用下同时发布多个 helm 类型的组件。如图 2-4 所示,模版中心提供了 helm chart 类型模版的上传、更新、下载、删除的功能,然后通过平台定义的 helm 类组件完成模版组件的部署、回滚和删除操作。
图 2-4 BizWorks helm chart 应用发布
成果与收益
-
具备了基础的部署和运维能力
-
- 借助 KubeVela Rollout,应用平台具备的基础的部署和运维能力,能够完全平台化覆盖应用实例的生命周期,运维人力成本降低 50%,公有云场景消除了产品间来回切换的成本
- 灵活的特征机制,为应用平台提供了便利的路由配置能力
-
一键搭建测试环境的快捷功能
基于 KubeVela 的 fluxcd Addon 和应用平台的模版中心,用户可以快速的搭建和释放一套测试环境,由原来正常 3-6 个小时缩减为 15 分钟左右就可以完整搭建
- 应用模型统一
KubeVela 相较于其他开源 CD 产品最大的优势,是其开放应用模型 OAM,声明式构建需要的资源,对于有多云部署和应用配置统一的产品有很大的帮助,配置统一后运维人员不需要收集各种格式的资源申请,完全可以通过平台化配置和 OAM 模型完成声明式资源创建,这部分效率几乎提升 100%
此外,借助 KubeVela 的 CD 能力,BizWorks 目前管理的集群和 Application 数量已经初具规模。其中公有云支撑 500+集群,总计 数千个应用;专有云支撑 100+局点,当前最大局点支撑 100+集群,数百个应用。
未来规划
为了更好的支持后续平台能力的扩展和增强,BizWorks 在可预见的近期会继续与 KubeVela 开展深度合作,大致规划包括:
- 可视化分批发布,基于 Kruise Rollout和KubeVela,支持无状态组件以及 helm chart
- 弹性伸缩,兼容 ACK 和 Kubernetes 原生 HPA 策略
- 社区贡献,自定义的 definition 转化为 KubeVela 的 addon
- 金丝雀发布,支持更好的流量控制和灰度策略
您可以通过如下材料了解更多关于 KubeVela 以及 OAM 项目的细节:
- 项目代码库:github.com/oam-dev/kubevela 欢迎 Star/Watch/Fork!
- 项目官方主页与文档:kubevela.io ,从 1.1 版本开始,已提供中文、英文文档,更多语言文档欢迎开发者进行翻译。
- 项目钉钉群:23310022;Slack:CNCF #kubevela Channel
- 加入微信群:请先添加以下 maintainer 微信号,表明进入 KubeVela 用户群:
戳此处:查看 KubeVela 项目官网!!