Skip to main content

KubeVela 1.3 发布:开箱即用的可视化应用交付平台,引入权限、认证、版本化等企业级新特性

KubeVela 社区

KubeVela 社区

KubeVela 团队

得益于 KubeVela 社区上百位开发者的参与和 30 多位核心贡献者的 500 多次代码提交, KubeVela 1.3 版本正式发布。相较于三个月前发布的 v1.2 版本,新版本在 OAM 核心引擎(Vela Core),可视化应用交付平台 (VelaUX) 和社区插件生态这三方面都给出了大量新特性。这些特性的诞生均源自于阿里巴巴、LINE、招商银行、爱奇艺等社区用户大量的深度实践,最终贡献到 KubeVela 项目中,形成大家可以开箱即用的功能。

现代化应用交付的痛点和挑战#

那么,现代化的云原生应用交付和管理,我们到底遇到了什么痛点和挑战呢?

  1. 混合云、多集群成为业务常态,应用的组成不仅包含容器,还包含云资源和各类自建服务。

一方面,随着国内外云厂商不断发展,大多数企业构建基础设施的方式已经变成以云服务为主,自建为辅的模式。更多的传统企业可以直接享受云技术发展带来的业务便利,使用云的弹性、降低自建基础设施的成本。企业需要一个标准化的应用交付层,可以统一囊括容器、云服务和各类自建服务,以便可以轻易的达成云上云下的互通,降低繁琐的应用迁移带来的风险,上云无忧。 另一方面,为了基础设施稳定性和多环境隔离等安全风控因素,也受到 Kubernetes 集群本身规模的限制 ,越来越多的企业开始采纳多个 Kubernetes 集群来管理容器工作负载。如何在多集群层面管理、编排容器应用,解决好调度、依赖关系、版本、灰度等难题,同时提供给业务开发者一个低门槛的使用体验,是一个很大的挑战。 可以看到,现代化应用交付中涉及的混合云、多集群不光是多个 Kubernetes 集群,还包括云服务、SaaS、自建服务在内的多样化工作负载及运维能力。

  1. 超过 1000+ 的云原生生态技术和产品如何按需选择。

我们以加入 CNCF 生态的开源项目为例,其数量已经超过了 1000。对于不同规模阶段、不同行业,以及不同技术背景的团队来说,看似研发团队都在做相似的业务应用交付和管理,但是随着需求和使用场景的变化会衍生出技术栈的巨大差异,这里就涉及非常大的学习成本和集成、迁移使用门槛。而 CNCF 上千个生态项目又时刻诱惑着我们,集成新项目,加入新 feature,更好地完成业务目标,技术栈一成不变的时代早已过去

alt 图 1 CNCF Landscape

下一代应用交付和管理需要具备灵活的装配能力,根据团队的需要,在最小能力集的基础上,以较小的成本扩充新的功能,同时让各种技术有效的智能协作,开发者学习成本却不能显著提高。只基于一套经验固化封装的传统 PaaS 方案,已经被验证了难以满足一个团队在产品演进过程中不断变化的场景需求。

  1. 新一代 DevOps 技术,面向复杂多样化的基础设施交付和管理应用。

十多年来,DevOps 技术一直伴随着开发者以提高生产效率为目标不断演进。如今来看,业务应用的制作流程也发生了很大的变化,从传统的编码、测试、打包、部署、运维观测,到如今云的基础设施不断加厚,各类 SaaS 服务直接以 API 的形式成为了应用的组成部分。应用从开发语言多样化,到部署环境多样化,再到组成成分的多样化,传统的 DevOps 工具链逐渐力不从心,而映射到用户这一层的就是不断增加的复杂性。 同样的 DevOps 理念,我们需要不一样的解决思路。现代化的应用交付和管理,我们依然有着同样的追求即尽可能减少人力投入,更加智能化。新一代的 DevOps 技术需要具备更易用的集成能力,服务治理能力,和观测与运维一体的管理能力。与此同时,工具需要简单好用,复杂留在平台内部。企业选择时能够结合自身业务需要,新架构与遗留的系统一同协作,组装合适自己团队的平台方案,避免新的平台成为业务开发者或企业的负担。

KubeVela 的解法和路径#

打造下一代应用交付平台,我们这么做:

alt

图 2 分层的 OAM/KubeVela 生态体系

  1. OAM 开放应用模型:标准先行,通过实践持续沉淀方法论

基于阿里和微软的内部实践经验,我们在 2019 年推出了 OAM 这一全新的应用模型和理念,其核心在于关注点分离,通过组件和运维特征这一层统一抽象,规范化云原生时代业务研发和运维人员之间的协作关系,提高交付和运维效率,同时也期望能够通过标准化的应用层避免不同基础设施差异带来的复杂性。随后我们便发布了 KubeVela 作为 OAM 模型的标准化实现,帮助企业能够快速落地 OAM,同时保证符合 OAM 规范的应用能够随处运行。简单来说,OAM 用声明式的方式描述了现代化应用完整的组成部分,而 KubeVela 则按照 OAM 声明的终态去运行,通过面向终态的控制循环,两者共同保证了应用交付的一致性和正确性。 最近我们看到谷歌发表的论文公布了其内部基础设施建设的成果 “Prodspec 和 Annealing”,其设计理念和实践方式与 “OAM 和 KubeVela” 惊人的相似,可见国内外不同的企业在云原生应用交付领域的实践殊途同归,这也侧面印证了标准化模型和 KubeVela 实践的正确性。未来,我们也将不断根据社区对 KubeVela 地实践和演进,推动 OAM 模型的发展,持续将最佳实践沉淀为方法论。

  1. 打造混合环境、多集群交付控制平面,充分满足不同规模、不同场景用户自建平台的需要

KubeVela 的内核以 CRD Controller 的形式存在,它可以轻易的被 Kubernetes 生态集成,OAM 模型也与 Kubernetes API 兼容。KubeVela 的微内核除了具备 OAM 模型的抽象和编排能力,还是一个天然面向多集群、混合云环境设计的应用交付控制平面。这也意味着 KubeVela 可以无缝的衔接云资源、容器等多样化的工作负载,在不同的云、不同集群下的编排和交付。 除了基本的编排能力,KubeVela 的特色之一是允许用户自定义交付工作流,工作流的步骤可以使用现成的功能如部署组件到集群、等待人工审批、发送通知等,也可以通过基于 CUE 配置语言的扩展能力集成任意 IaC 化的流程,如 K8s CRD、SaaS API、Terraform 模块、镜像脚本等。工作流执行过程中进入到稳定状态时(如等待人工审批),KubeVela 同样会自动化地做状态维持。KubeVela 的 IaC 扩展能力使得它可以以极低的成本集成 Kubernetes 的生态技术,它非常适合被平台构建者集成到自己的 PaaS 或交付系统中,可以通过 KubeVela 的扩展性将企业现有的能力集成进来,并作为标准化能力与其他生态能力一同呈现给用户。

  1. 开箱即用的可视化应用交付平台,直接满足中小团队的业务需求

除了先进的模型和扩展的内核,我们在社区也遇到了大量的用户呼声,它们希望能够拿到开箱即用的产品,以便更好、更快地采用 KubeVela。从 1.2 版本开始,社区便投入到了可视化应用交付平台(VelaUX)项目的研发中,它以 KubeVela 的内核能力为基础,贯穿标准化、可扩展的理念,通过插件生态(Addon)的方式,打造了面向 CI/CD 垂直场景的可视化应用交付平台。我们希望企业可以直接采用 VelaUX 满足业务需求,又能具备很强的自定义能力,满足未来业务发展的需要。

alt 图 3 KubeVela 产品架构说明

围绕着这条路,在 1.3 版本中,社区带来了下述更新:

核心引擎:Kubernetes 多集群控制平面能力增强#

应用不用改造,切换到多集群#

企业已经完成应用云原生改造的基础上,切换到多集群部署是否还需要进行配置改造呢?答案是否定的。 KubeVela 天然建立在多集群基础之上,对于同一份应用描述,我们只需要在交付策略中指定需要交付的集群名称,或通过标签筛选特定集群即可,如图 4 所示应用配置代表将一个具有一个 nginx组件的应用发布到标签为 region=hangzhou的所有集群。

alt 图 4 OAM 应用描述-选择部署集群

当然,图4 所示的应用描述是完全以 OAM 推荐规范来的,如果你的现状是应用已经以 Kubernetes 原生资源的形式定义,不用担心,我们支持内嵌或引用的方式继承 Kubernetes 原生资源的描述风格,如下图 5 “引用 Kubernetes 资源做多集群部署”所示,描述了一个特殊应用,它的组件是依赖了一个管控集群中存在的 Secret 资源,将其发布到标签为 region=hangzhou的所有集群。

alt 图 5 引用 Kubernetes 资源做多集群部署

除了应用的多集群部署以外,引用 Kubernetes 对象的功能还可以用于诸如已有资源的多集群复制,集群数据备份等场景。

处理多集群差异#

应用统一描述之后,不同的集群部署时可能存在差异,如不同的区域采用不同的环境变量、不同的镜像仓库地址;又比如不同的集群部署不同的组件、或者一个组件在多个集群部署互为高可用等。针对这类需求,我们提供了部署差异描述策略,如下图 6 所示,这是应用配置的策略部分,第一和第二条 topology 类型的策略以两种方式定义了两个目标策略。第三差异性策略,代表只部署指定的组件。第四条差异性策略,代表部署指定的两个组件和其中一个组件的差异性镜像配置。

alt 图 6 多集群差异化配置

KubeVela 支持灵活的差异性配置策略,可通过组件属性、Trait等形式来配置差异。如上图所示第三个策略表达了组件选择能力,第四个策略表达了镜像版本差异。我们可以看到,描述差异时没有指定目标,即差异性描述是可以复用的,它与目标策略在工作流步骤中进行灵活组合。

配置多集群交付流程#

应用交付到不同的目标集群的过程是可控的,通过工作流描述部署过程。如图 7 所示,表达了部署到两个集群的步骤以及分别采用的目标策略和差异化策略。结合上文可知,策略部署只需要进行原子定义,在工作流部分可以灵活组合以实现不同场景的控制需求。

alt 图 7 自定义多集群交付流程

交付工作流有更多的使用场景,包括多集群灰度发布,企业审批,发布精确控制等等。

版本控制,安全可追溯#

复杂应用的描述随着敏捷开发随时都在改变,为了保障应用发布安全,我们需要具有在发布时或发布后的任何时间可以让我们应用根据需要回到之前的某一个正确状态的能力。因此当前版本我们引入了更准确的版本记录机制。

alt 图 8 查询应用历史版本

我们可以查询应用的历史版本状态,包括了其发布时间和是否成功等。我们可以基于版本比对当前的变更,同样也可以在发布时遇到故障基于上一个成功版本渲染完成的配置快照快速回退。在新版本发布完成后如果遇到故障和其他需求需要重新发布历史版本,不用去变更配置源(路径可能会比较长,你也可能不记得进行了哪些变更),直接基于历史版本重新发布即可。 版本控制机制的背后是应用配置管理的集中化思想,应用完整描述统一渲染后进行统一检查,存储和下发。

查看 KubeVela 核心引擎用法的更多详情#

平台:VelaUX 引入多租隔离、用户认证和鉴权#

多租隔离匹配多团队企业需要#

在 VelaUX 中,我们引入了基于“项目”的概念来进行逻辑的多租隔离,包括应用交付目标,应用和环境,成员和权限等。当企业中存在多个团队或多个项目组同时使用 VelaUX 平台发布各自业务应用时该能力变得非常重要。图 9 所示为项目列表页面,项目管理员可根据团队需求在该页面创建不同的项目,从而分配对应的资源。

alt 图 9 项目管理页面

开放的认证&鉴权#

作为一个基础平台,用户认证和鉴权能力是必须具备的基础能力之一。从 1.3 版本开始,我们支持了用户认证和 RBAC 鉴权。 对于用户认证我们相信大多数企业都有建设统一的认证平台(Oauth 或 LDAP),因此 VelaUX 集成 Dex 优先打通了单点登陆能力,支持 LDAP,OIDC,Gitlab/Github 等用户认证方式,把 VelaUX 作为你的开发者门户中的子系统之一。当然如果你的团队暂无统一认证的需求,我们同样提供了基础的本地用户认证能力。

alt 图 10 本地用户管理页面

对于鉴权,我们采用 RBAC 模式,但同时我们也看到了基础的 RBAC 模式无法处理精确权限控制场景,比如授权某一个应用的操作权给某用户,这类场景技术上涉及了数据授权。我们继承了 IAM 的设计理念,将权限扩展为资源+动作+条件+行为的策略组成,鉴权系统(前端 UI 鉴权/后端 API 鉴权)已经实现了面向策略的细粒度鉴权。但在授权方面当前版本仅内置了部分常用权限策略,后续版本提供自定义创建权限的能力。 同时我们也看到部分大型企业建设了独立的 IAM 平台,VelaUX 的 RBAC 数据模型与市场上常见 IAM 平台基本一致,因此希望将 VelaUX 对接到自建 IAM 的用户可以进行扩展支持。

运维配置集中管理,保障多集群应用分发安全#

应用交付过程中必然会面对一些运维需求的配置管理,特别是多集群基础上,配置管理需求尤其突出,例如私有镜像仓库的认证配置,又或者 Helm 制品库的认证配置,又或者 SSL证书等。我们需要统一管理这些配置的有效性并将其安全的同步到需要的地方,最好还不需要业务开发者感知。

1.3 版本我们在 VelaUX 中引入了集成配置管理的模块,它的底层同样采用组件模版和应用资源分发的链路来管理和分发配置,目前采用 Secret 进行配置存储和分发。配置的生命周期独立于业务应用,我们在每一个项目中独立维护配置的分发过程。对于管理员用户来说,只需要根据配置模版填写配置信息即可。

alt 图 11 集成配置管理页面

不同的配置类型由不同的 Addon 提供,用户可以根据需要定义更多了配置类型,统一进行管理。对于业务级配置管理目前也在社区的规划中。

查看 VelaUX 用法的更多详情#

生态:Addon 引入版本控制#

Addon 版本管理,升级更安全#

Addon 功能在 1.2 版本中引入,提供一种扩展插件的规范、安装、运维的管理能力。社区可以通过制作不同的Addon 来扩充 KubeVela 的生态能力。当我们的插件和框架都在持续迭代时,版本兼容性问题逐步凸显,我们急需一套版本管理机制。

  • 与 Vela 版本的协同机制:Addon 元数据中支持定义支持的 Vela 版本,当安装环境版本不匹配时拒绝安装。
  • Addon 版本化分发:我们在 Github 中进行社区官方 Addon 的开发和管理,每一个 Addon 除了集成的第三方产品版本以外,还包括了 Definition 等多种配置,因此 Addon 每一次发布后我们根据其定义的版本号进行打包,历史记录得以保留。同时我们复用了 Helm Chart 的制品分发 API 规范来分发 Addon。

多集群 Addon 可控安装#

有一类 Addon 在安装时需要在子集群中安装,例如图 12 所示的 FluxCD 插件,它提供了 Helm Chart 渲染和部署能力。我们需要将其部署到子集群中,过去这个处理过程是分发到所有子集群。但社区反馈,对于不同的插件,不一定都需要安装到所有集群,我们需要一种差异性处理机制,按需的把扩展安装到指定的集群。

alt 图 12 Addon 配置管理页面 用户在启用 Addon 时可以指定需要部署的集群,系统将根据用户配置将插件完成部署。

Addon 生态增加新成员#

在迭代扩展框架能力的同时,社区已有的 Addon 也在持续增加和升级。云服务支持层面,支持的厂商增加到7个。生态技术方面新增了AI 训练和服务化插件,Kruise Rollout 插件,Dex 插件等。同时 Helm Chart 插件和 OCM 集群管理插件也做了用户体验更新。

查看 Addon 用法的更多详情#

近期规划(Roadmap)#

随着 KubeVela 内核的逐步稳定,可扩展内核的红利逐步释放,使得社区在 1.2 / 1.3 的版本演进逐渐

KubeVela v1.3 多集群初体验,轻松管理应用分发和差异化配置

段威(段少)

段威(段少)

KubeVela 团队

在当今的多集群业务场景下,我们经常遇到的需求有:分发到多个指定集群、按业务规划实现分组分发、以及对多集群进行差异化配置等等。

KubeVela v1.3 在之前的多集群功能上进行了迭代,本文将为你揭示,如何使用 KubeVela 进行多集群应用的部署与管理,实现以上的业务需求。

开始之前#

  1. 准备一个 Kubernetes 集群作为 KubeVela 的控制平面。
  2. 确保 KubeVela v1.3 和 KubeVela CLI v1.3.0 已经安装成功。
  3. 你要管理的子集群列表 kubeconfig。我们将以 beijing-1,beijing-2 和 us-west-1 这 3 个集群为例。
  4. 下载并结合 multi-cluster-demo 来更好的理解,如何使用 KubeVela 多集群能力。

分发到多个指定集群#

对多个指定集群进行分发是最基本的多集群管理操作。在 KubeVela 中,你将使用一个叫做 topology 的应用策略来实现它。集群以数组的形式,列在其属性的 clusters 字段里。

首先让我们确保切换 KUBECONFIG 到准备好的管控集群,使用 vela cluster join 将 beijing-1,beijing-2 和 us-west-1 这 3 个集群全部纳管进来:

➜ vela cluster join beijing-1.kubeconfig --name beijing-1
➜ vela cluster join beijing-2.kubeconfig --name beijing-2
➜ vela cluster join us-west-1.kubeconfig --name us-west-1
➜ vela cluster list
CLUSTER TYPE ENDPOINT ACCEPTED LABELS
beijing-1 X509Certificate https://47.95.22.71:6443 true
beijing-2 X509Certificate https://47.93.117.83:6443 true
us-west-1 X509Certificate https://47.88.31.118:6443 true

接着打开 multi-cluster-demo,查看 basic.yaml

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-app
namespace: default
spec:
components:
- name: hello-world-server
type: webservice
properties:
image: crccheck/hello-world
port: 8000
traits:
- type: scaler
properties:
replicas: 3
- type: gateway
properties:
domain: testsvc-mc.example.com
# classInSpec : true 如果你所下发的集群里有安装 v1.20 以下版本的 Kubernetes ,请加上这个字段
http:
"/": 8000
policies:
- type: topology
name: beijing-clusters
properties:
clusters: ["beijing-1","beijing-2"]

可以看到,这个应用使用了 webservice 类型的组件,最后通过 topology 的应用策略分别向 beijing-1 和 beijing-2 两个集群分发 3 副本 Deployment。

请注意,管控集群对子集群下发资源成功的前提是,子集群必须有已经新建的对应命名空间。由于每个集群默认都有 default 命名空间,所以可以正常下发。假设我们将 basic.yaml 的命名空间改成 multi-cluster ,则会收到报错:

...
Status: runningWorkflow
Workflow:
mode: DAG
finished: false
Suspend: false
Terminated: false
Steps
- id:9fierfkhsc
name:deploy-beijing-clusters
type:deploy
phase:failed
message:step deploy: step deploy: run step(provider=oam,do=components-apply): Found 1 errors. [(failed to apply component beijing-1-multi-cluster-0: HandleComponentsRevision: failed to create componentrevision beijing-1/multi-cluster/hello-world-server-v1: namespaces "multi-cluster" not found)]
Services:
...

在未来的 KubeVela 版本中,我们将支持使用鉴权系统,更便捷更安全的完成这项操作:通过管控集群一键在子集群创建命名空间。

完成子集群命名空间创建后,切回管控集群创建应用并下发资源:

➜ vela up -f basic.yaml
Applying an application in vela K8s object format...
"patching object" name="example-app" resource="core.oam.dev/v1beta1, Kind=Application"
✅ App has been deployed 🚀🚀🚀
Port forward: vela port-forward example-app
SSH: vela exec example-app
Logging: vela logs example-app
App status: vela status example-app
Service status: vela status example-app --svc hello-world-server

我们通过 vela status <应用名> 查看服务相关信息:

➜ vela status example-app
About:
Name: example-app
Namespace: default
Created at: 2022-03-25 17:42:33 +0800 CST
Status: running
Workflow:
mode: DAG
finished: true
Suspend: false
Terminated: false
Steps
- id:wftf9d4exj
name:deploy-beijing-clusters
type:deploy
phase:succeeded
message:
Services:
- Name: hello-world-server
Cluster: beijing-1 Namespace: default
Type: webservice
Healthy Ready:3/3
Traits:
✅ scaler ✅ gateway: Visiting URL: testsvc-mc.example.com, IP: 60.205.222.30
- Name: hello-world-server
Cluster: beijing-2 Namespace: default
Type: webservice
Healthy Ready:3/3
Traits:
✅ scaler ✅ gateway: Visiting URL: testsvc-mc.example.com, IP: 182.92.222.128

beijing-1 和 beijing-2 都下发了对应的资源,它们可供外部访问的 IP 地址也显示出来,你因而可以用你希望的方式供用户访问了。

使用集群 labels 按需分组分发#

除了上述的基本操作,我们常常会遇到另外的情况:跨地域部署到某些集群、指定哪个云厂商的集群等等。为了实现类似这样的需求,可以使用多集群的 labels 功能。

在这里,假设 us-west-1 集群来自 AWS,我们要额外分发应用到 AWS 的集群,则可以使用 vela cluster labels add 来对集群进行标记。当然,如果还有 us-west-2 等多个 AWS 相关集群,同样进行标记后,将会统一下发:

➜ ~ vela cluster labels add us-west-1 provider=AWS
Successfully update labels for cluster us-west-1 (type: X509Certificate).
provider=AWS
➜ ~ vela cluster list
CLUSTER TYPE ENDPOINT ACCEPTED LABELS
beijing-1 X509Certificate https://47.95.22.71:6443 true
beijing-2 X509Certificate https://47.93.117.83:6443 true
us-west-1 X509Certificate https://47.88.31.118:6443 true provider=AWS

接下来我们对 basic.yaml 进行更新,新增一个应用策略 topology-aws

...
policies:
- type: topology
name: beijing-clusters
properties:
clusters: ["beijing-1","beijing-2"]
- type: topology
name: topology-aws
properties:
clusterLabelSelector:
provider: AWS

为了方便你学习,请直接部署基于 basic.yaml 更新后的 intermediate.yaml

➜ ~ vela up -f intermediate.yaml

再次查看应用的状态:

➜ vela status example-app
...
- Name: hello-world-server
Cluster: us-west-1 Namespace: default
Type: webservice
Healthy Ready:3/3
Traits:
✅ scaler ✅ gateway: Visiting URL: testsvc-mc.example.com, IP: 192.168.40.10

通过应用策略进行配置差异化#

除了在 basic.yaml 里定义的 deploy-beijing 这种应用策略,我们往往有更多的应用策略需求,比如高可用,希望单独给某些资源分发 5 个副本。这样的话,使用 override 类型的应用策略即可:

...
clusterLabelSelector:
provider: AWS
- type: override
name: override-high-availability
properties:
components:
- type: webservice
traits:
- type: scaler
properties:
replicas: 5

同时假设,我们希望的是,给 AWS 的应用分发并设置为高可用。那我们可以使用 KubeVela 提供的专门用于定义过程控制的工作流来管理。我们使用如下的一个工作流,它希望将本次应用部署,首先通过 deploy-beijing 的应用策略,分发给北京的集群们,接着给 Label 为 AWS 的集群分发 5 个副本高可用的应用策略:

...
properties:
replicas: 5
workflow:
steps:
- type: deploy
name: deploy-beijing
properties:
policies: ["beijing-clusters"]
- type: deploy
name: deploy-aws
properties:
policies: ["override-high-availability","topology-aws"]

接着我们给 intermediate.yaml 加上以上的应用策略和工作流后,更新为 advanced.yaml

...
policies:
- type: topology
name: beijing-clusters
properties:
clusters: ["beijing-1","beijing-2"]
- type: topology
name: topology-aws
properties:
clusterLabelSelector:
provider: AWS
- type: override
name: override-high-availability
properties:
components:
- type: webservice
traits:
- type: scaler
properties:
replicas: 5
workflow:
steps:
- type: deploy
name: deploy-beijing
properties:
policies: ["beijing-clusters"]
- type: deploy
name: deploy-aws
properties:
policies: ["override-high-availability","topology-aws"]

然后对其进行部署,并再次查看应用的状态:

➜ vela up -f advanced.yaml
Applying an application in vela K8s object format...
"patching object" name="example-app" resource="core.oam.dev/v1beta1, Kind=Application"
✅ App has been deployed 🚀🚀🚀
Port forward: vela port-forward example-app
SSH: vela exec example-app
Logging: vela logs example-app
App status: vela status example-app
Service status: vela status example-app --svc hello-world-serverapplication.core.oam.dev/podinfo-app configured
➜ vela status example-app
...
- Name: hello-world-server
Cluster: us-west-1 Namespace: default
Type: webservice
Healthy Ready:5/5
Traits:
✅ scaler ✅ gateway: Visiting URL: testsvc-mc.example.com, IP: 192.168.40.10

以上就是本次的全部分享,感谢你的阅读和试玩。

欢迎你继续探索 KubeVela v1.3 正式版,这里有更多差异化配置的进阶用法等你发现和使用,比如 override 应用策略如何完成资源类型通配还是针对某些特定组件进行覆盖等等,以满足更加复杂的场景需求。

招商银行 KubeVela 离线部署实践

马祥博

马祥博

(云平台开发团队)

招商银行云平台开发团队自2021年开始接触 KubeVela,并探索 KubeVela 在招商银行云平台的落地实践,借此提升云原生应用交付与管理能力。同时因为金融保险行业的特殊性,网络安全管控措施相对严格,行内网络无法直接拉取 Docker Hub 镜像,同时行内暂时没有可用的 Helm 镜像源。因此,要想实现 KubeVela 在行内私有环境的落地,必须进行完全的离线部署。

本文将以 KubeVela v1.2.5 版本为例,介绍招商银行 KubeVela 的离线部署实践,来帮助其他用户在离线环境中更便捷的完成 KubeVela 的部署。

KubeVela 离线部署方案#

我们将 KubeVela 的离线部署主要分为三部分,分别是 Vela Cli、Vela Core 以及 Addon 的离线部署,每一部分主要涉及到相关 docker 镜像的加载及 Helm 的 repackage,通过该离线部署方案,能够大大加快 KubeVela 在离线环境的部署。

在离线部署前请确保 Kubernetes 集群版本 >= v1.19 && < v1.22,KubeVela 控制平面依赖 Kubernetes,可以放置在任何托管 Kubernetes 作为底座的产品或自建 Kubernetes 集群中。同时你也可以使用 kind 或 minikube 在本地部署、测试 KubeVela。

Vela Cli 离线部署#

  • 首先,需要通过 KubeVela 的 发布日志 下载你所需版本的 vela 二进制文件
  • 解压二进制文件,并且在 $PATH 中配置相应的环境变量
    • 解压二进制文件
      • tar -zxvf vela-v1.2.5-linux-amd64.tar.gz
      • mv ./linux-amd64/vela /usr/local/bin/vela
    • 设置环境变量
      • vi /etc/profile
      • export PATH="$PATH:/usr/local/bin"
      • source /etc/profile
    • 通过 vela version 验证 Vela Cli 的安装,并检查输出
CLI Version: v1.2.5
Core Version:
GitRevision: git-ef80b66
GolangVersion: go1.17.7
  • 至此,Vela Cli 已经离线部署完成!

Vela Core 离线部署#

  • 离线部署 Vela Core 之前,首先需要在离线环境中 安装 Helm , 并且 Helm 的版本需要满足v3.2.0+
  • 准备 docker 镜像, Vela Core 的部署主要涉及5个镜像,你需要首先访问互联网从 Docker Hub 下载相应镜像,之后再 load 到离线环境
    • 从Docker Hub拉取镜像
      • docker pull oamdev/vela-core:v1.2.5
      • docker pull oamdev/cluster-gateway:v1.1.7
      • docker pull oamdev/kube-webhook-certgen:v2.3
      • docker pull oamdev/alpine-k8s:1.18.2
      • docker pull oamdev/hello-world:v1
    • 将镜像保存到本地磁盘
      • docker save -o vela-core.tar oamdev/vela-core:v1.2.5
      • docker save -o cluster-gateway.tar oamdev/cluster-gateway:v1.1.7
      • docker save -o kube-webhook-certgen.tar oamdev/kube-webhook-certgen:v2.3
      • docker save -o alpine-k8s.tar oamdev/alpine-k8s:1.18.2
      • docker save -o hello-world.tar oamdev/hello-world:v1
    • 在私有环境中重新加载镜像
      • docker load vela-core.tar
      • docker load cluster-gateway.tar
      • docker load kube-webhook-certgen.tar
      • docker load alpine-k8s.tar
      • docker load hello-world.tar
  • 下载 KubeVela 源码 ,拷贝到离线环境中,并使用 Helm 重新打包
    • 将 KubeVela 源码重新打 chart 包,并离线安装 chart 包到控制集群
      • helm package kubevela/charts/vela-core --destination kubevela/charts
      • helm install --create-namespace -n vela-system kubevela kubevela/charts/vela-core-0.1.0.tgz --wait
    • 检查输出
KubeVela control plane has been successfully set up on your cluster.
  • 至此,Vela Core 已经离线部署完成!

Addon 离线部署#

  • 首先下载 Catalog 源码 并拷贝到私有环境中
  • 这里将以 VelaUX 为例介绍 Addon 的离线部署,首先准备 docker 镜像,VelaUX 主要涉及2个镜像,需要首先访问互联网从 Docker Hub 下载相应镜像,之后再 load 到离线环境
    • 从 Docker Hub 拉取镜像
      • docker pull oamdev/vela-apiserver:v1.2.5
      • docker pull oamdev/velaux:v1.2.5
    • 将镜像保存到本地磁盘
      • docker save -o vela-apiserver.tar oamdev/vela-apiserver:v1.2.5
      • docker save -o velaux.tar oamdev/velaux:v1.2.5
    • 在私有环境中重新加载镜像
      • docker load vela-apiserver.tar
      • docker load velaux.tar
  • 安装 VelaUX
    • 通过 Vela Cli 安装VelaUX
      • vela addon enable catalog-master/addons/velaux
    • 检查输出
Addon: velaux enabled Successfully.
  • 若有集群中安装了 route Controller 或 Nginx Ingress Controller,且有可用域名,你可以部署外部路由访问 VelaUX,这里以 openshift route 为例,也可以选择 ingress
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: velaux-route
namespace: vela-system
spec:
host: velaux.xxx.xxx.cn
port:
targetPort: 80
to:
kind: Service
name: velaux
weight: 100
wildcardPolicy: None
  • 检查安装
curl -I -m 10 -o /dev/null -s -w %{http_code} http://velaux.xxx.xxx.cn/applications
  • 至此,VelaUX 已经离线部署完成! 同时,对于其他类型 Addon 的离线部署,只需要去 Catalog 源码的对应目录确定所需镜像,并重复以上操作即可完成相应 Addon 的离线部署

总结#

在离线部署的过程中,我们也尝试将 Vela Core 和 Addon 在互联网环境中部署后产生的资源实例保存为 yaml 文件,并在私有环境中进行重新部署,从而完成离线部署,但由于涉及的资源实例较多以及服务授权问题,导致该种方式较为繁琐。

通过 KubeVela 离线部署实践,可以帮助你更便捷的在离线环境中搭建一整套的 KubeVela,探索 KubeVela 的落地实践。针对离线部署这个共性的问题,我们也看到 KubeVela 社区即将推出全新的 velad,一个完全离线、数据高可用的安装工具。Velad 可以帮助自动化完成准备集群、下载打包镜像并安装到离线环境等一系列步骤。它支持了:在 Linux 机器(例如阿里云 ECS)本地启动集群、安装 vela-core;在快速启动一个 KubeVela 控制平面的同时,不必担心控制平面的数据随着机器关机等情况而丢失;velad 可以将控制平面全部数据存储到一个传统数据库(例如 RDS 或另一个 ECS 上部署的 MySQL)。

近期的版本中,招行将加大在 KubeVela 开源社区的投入,积极共建,在企业级集成能力、多集群能力增强、离线部署和应用级统一可观测等诸多领域,贡献来自于金融行业的特定用户场景和业务需求,推动云原生生态实现更易用更高效的应用管理平台向前发展,也欢迎更多的社区成员一起加入进来。

使用 Nocalhost 与 KubeVela 端云联调,一键完成多集群混合云环境部署

Tianxin Dong and Yicai Yu

Tianxin Dong and Yicai Yu

KubeVela、Nocalhost 团队

在云原生快速发展的当下,如何让云的技术赋能业务开发?在上线应用时,如何让云的开发者在现代化的多集群、混合云环境中便捷地进行应用的开发和调试?在部署过程中,又该如何让应用部署具备充分的验证和可靠性?

这些至关重要的问题,都是我们急需解决的。

在本文中,我们将结合 KubeVela 以及 Nocalhost 开源项目,给出一个基于 Kubernetes 和容器生态的端云联调、一键完成多集群混合环境部署的解决方案,来回答上述问题。

当一个新应用需要开发上线时,我们希望本地 IDE 中调试的结果能和云端最终部署的状态保持一致。这样一致的姿态,能最大程度上给予我们部署的信心,并且让我们可以采用类似 GitOps 这种更高效、敏捷的方式迭代应用更新。即:当新代码被推送至代码仓库中后,环境中的应用会自动化地实时更新。同时,基于端云联调的模式,可以让这整个过程不仅敏捷高效、同样更加稳定可靠。

基于 KubeVela 和 Nocalhost,我们可以完成这样一种部署过程:

alt

如图:通过 KubeVela 创建应用,将应用部署到测试环境后,暂停部署。使用 Nocalhost 在测试环境中对应用进行云端联调。调试完毕后,将调试完毕的代码推送到代码仓库,通过 KubeVela 进行 GitOps 部署,在测试环境进行验证后,再同步更新到生产环境。

在本文中,我们将介绍如何使用 KubeVela 及 Nocalhost 完成上述云端应用开发及上线的全过程。

什么是 KubeVela#

KubeVela 是一个简单易用且高度可扩展的应用交付和管理平台,基于 Kubernetes 与 OAM 技术构建。其核心功能是让开发人员方便快捷地在 Kubernetes 上定义与交付现代微服务应用,而无需了解任何 Kubernetes 本身相关的细节。

KubeVela 提供了 VelaUX 功能,能够让整个应用分发的过程可视化,使应用组装、分发、交付的流程变得更简单。在 UX 上,不仅可以便捷地通过页面及时了解整个交付链路状态,还可以通过配置触发器,使应用随着制品仓库的更新而更新。

而在本文的场景中,KubeVela 提供了以下能力:

  1. 完整的 GitOps 发布:
  • KubeVela 同时支持了 Pull 模式以及 Push 模式的 GitOps 发布:我们只需要将更新后的代码推送到代码仓库,KubeVela 就能自动基于最新代码完成部署。在本文中,我们将使用 Push 模式的 GitOps,关于 Pull 模式的 GitOps 支持,可以查看这篇文章
  1. 强大的工作流能力,实现跨环境(集群)部署、审批以及通知:
  • KubeVela 借助其工作流能力,可以轻松让应用实现跨环境部署,并且支持用户在编排工作流的过程中,加入例如人工审批、消息通知等功能,使整个部署过程生产级可用。
  1. 应用抽象能力,让开发者都能看懂使用并且自定义基础设施能力
  • KubeVela 遵循 OAM 的开放应用模型,提供了一套简单易用的应用抽象能力,使开发者能够更加清晰地理解应用的功能,并且可以自定义基础设施能力。例如,对于一个简单的应用来说,我们可以将其划分为组件,运维特征,工作流三大部分。在本文的例子中,我们的组件是一个简单的业务应用;在运维特征部分,我们为这个组件绑定了一个 Nocalhost 的运维特征,让这个组件能够使用 Nocalhost 端云联调的能力;在工作流部分,通过多环境管理,我们可以先让这个组件部署在测试环境,部署完成后自动暂停工作流的发布,直至人工验证审批通过后,再进行生产环境的部署。

什么是 Nocalhost#

Nocalhost 是一个允许开发者直接在 Kubernetes 集群内开发应用的工具。

Nocalhost 的核心功能是:提供 Nocalhost IDE 插件(包括 VSCode 和 Jetbrains 插件),将远端的工作负载更改为开发模式。在开发模式下,容器的镜像将被替换为包含开发工具(例如 JDK、Go、Python 环境等)的开发镜像。当开发者在本地编写代码时,任何修改都会实时被同步到远端开发容器中,应用程序会立即更新(取决于应用的热加载机制或重新运行应用),开发容器将继承原始工作负载所有的声明式配置(ConfigMap、Secret、Volume、Env 等)。

Nocalhost 还提供: VSCode 和 Jetbrains IDE 一键 Debug 和 HotReload;在 IDE 内直接提供开发容器的终端,获得和本地开发一致的体验;提供基于 Namespace 隔离的开发空间和 Mesh 开发空间 。此外,Nocalhost 还提供了 Server 端帮助企业管理 Kubernetes 应用、开发者和开发空间,方便企业统一管理各类开发和测试环境。

在使用 Nocalhost 开发 Kubernetes 的应用过程中,免去了镜像构建,更新镜像版本,等待集群调度 Pod 的过程,把编码/测试/调试反馈循环(code/test/debug cycle)从分钟级别降低到了秒级别,大幅提升开发效率。

调试云端应用#

我们以一个简单的前端应用为例,首先,我们通过 VelaUX 进行多环境部署。

关于如何开启 KubeVela 的 VelaUX 插件,请查看 官方文档

使用 VelaUX 部署云端应用#

在 VelaUX 中创建一个环境,每个环境中可以有多个部署目标,我们以一个包含了测试部署目标以及生产部署目标的环境为例。

首先,创建两个部署目标,一个用于测试部署,一个用于生产部署。这里的部署目标会分别将资源下发到 local 集群的 test 以及 prod namespace 当中。你也可以通过 VelaUX 的集群管理功能,来添加新的集群用于部署。

alt

创建完部署目标后,新建一个环境,环境中包含这两个部署目标。

alt

创建完环境后,新建应用来进行云端调试。这个前端应用会在 80 端口暴露服务,因此,我们把这个应用的 80 端口打开。

alt

创建完应用后,应用会默认带一个工作流,自动将应用部署到两个部署目标当中。但我们并不希望未经过调试的应用直接部署到生产目标中。因此,我们来编辑一下这个默认工作流:在部署到测试目标和生产目标中添加一个暂停步骤。这样,我们就可以在部署到测试环境中后,暂停部署,等待用户调试并验证完成后,再继续部署到生产环境中。

alt

完成这些配置后,我们来为这个应用添加一个 Nocalhost 的 Trait,用于云端调试。 在这里,详细介绍一下 Nocalhost Trait 中的几个参数:

alt

Command 分两种,Debug 和 Run。开发时在插件右键点击 Remote Debug、Remote Run 会在远端 Pod 中运行对应的命令,从而达到云端 Debug 的效果。在这里,我们使用的是前端应用,所以将命令设置为 yarn serve。

alt

alt

这里的 Image 指的是调试镜像,Nocalhost 默认提供了五种语言的镜像(go/java/python/ruby/node),可以通过填写语言名来使用内置镜像,当然,也可以填写完整镜像名以使用自定义镜像。 开启 HotReload 意味着开启热加载功能,能够在修改代码后直接看到效果。PortForward 会将云端应用的 80 端口转发到本地的 8080 端口。

alt

在 Sync 部分,将 Type 设置为 sendReceive (双向同步),或者设置为 send (单向发送)。 完成配置后,部署该应用。可以看到,应用在部署到测试目标之后,将自动暂停。

alt

此时,打开 VSCode 或者 Jetbrains IDE 中的 Nocalhost 插件页面,可以在 test namespace 下看到我们已部署的应用,点击应用旁边的锤子按钮进入调试模式:

alt

进入 Nocalhost 调试模式后,可以看到,IDE 中的终端已经被替换成了容器的终端。通过 ls 命令,可以看到容器内的所有文件。

alt

此时,右键 Nocalhost 中的应用,可以选择进入 Remote Debug 或者 Remote Run 模式。这两个按键将自动执行我们之前配置的 Debug 和 Run 命令。

alt

进入 Debug 模式后,可以看到,我们的云端应用被转发到了本地的 8080 端口:

alt

打开本地浏览器,可以看到,目前我们部署的前端应用版本为 v1.0.0:

alt

此时,我们可以在本地 IDE 中修改一下代码,将版本修改为 v2.0.0:

alt

在之前的 Nocalhost 配置中,我们已经开启了热加载功能。因此,我们再次刷新一下本地的 8080 端口页面,可以看到,应用版本已经变成了 v2.0.0:

alt

此时,我们可以终止 Nocalhost 的调试模式。将已通过调试的代码推送至代码仓库中。

alt

使用 GitOps 进行多环境发布#

在我们结束调试后,环境上的应用依旧是之前 v1.0.0 的版本。那么,该使用什么方式来更新环境中的应用呢?

在整个云端调试的过程中,我们修改的是源代码。因此,我们可以借助 GitOps 的模式,以代码作为更新来源,来完成对环境中应用的更新。

查看 VelaUX 中部署的应用,可以看到,每个应用都会拥有一个默认 Trigger:

alt

点击 Manual Trigger 查看详情, 可以看到,VelaUX 为每个应用提供了一个 Webhook URL,请求该地址,并带上需要更新的字段(如:镜像等),可以方便快捷的完成应用的更新。(注:由于需要对外暴露地址,需要在部署 VelaUX 的时候使用 LoadBalancer 或者使用其他方式暴露 VelaUX 的服务)。

alt

在 Curl Command 里,还提供了手动 Curl 该触发器的请求示例。我们来详细解析一下请求体:

{
// 必填,此次触发的更新信息
"upgrade": {
// Key 为应用的名称
"<application-name>": {
// 需要更新的值,这里的内容会被 Patch 更新到应用上
"image": "<image-name>"
}
},
// 可选,此次触发携带的代码信息
"codeInfo": {
"commit": "<commit-id>",
"branch": "<branch>",
"user": "<user>",
}
}

upgrade 下是本次触发要携带的更新信息,在应用名下,是需要被 Patch 更新的值。默认推荐的是更新镜像 image,也可以扩展这里的字段来更新应用的其他属性。

codeInfo 中是代码信息,可以选择性地携带,比如提交 ID、分支、提交者等,一般这些值可以通过在 CI 系统中使用变量替换来指定。

当我们经过更新后的代码被合入代码仓库后,我们可以通过代码仓库中的 CI 配置来完成和 VelaUX Trigger 的对接。以 GitLab CI 为例,可以增加如下步骤:

webhook-request:
stage: request
before_script:
- apk add --update curl && rm -rf /var/cache/apk/*
script:
- |
curl -X POST -H "Content-Type: application/json" -d '{"upgrade":{"'"$APP_NAME"'":{"image":"'"$BUILD_IMAGE"'"}},"codeInfo":{"user":"'"$CI_COMMIT_AUTHOR"'","commit":"'"$CI_COMMIT_SHA"'","branch":"'"$CI_COMMIT_BRANCH"'"}}' $WEBHOOK_URL

配置完成后,当代码被更新时,将自动触发该 CI,并且更新对应 VelaUX 中的应用。

alt

当镜像被更新后,再次查看应用的页面,可以看到,测试环境中的应用已经变成了 v2.0.0 版本。

在测试部署目标中验证完毕后,我们可以点击应用工作流中的 Continue ,使最新版本的应用部署到生产部署目标中。

alt

部署完毕后,查看生产环境中的应用,可以看到,生产环境中已经是最新的 v2.0.0 版本:

alt

至此,我们就通过 KubeVela 首先在测试环境中使用 Nocalhost 进行端云联调,验证通过后,再通过更新代码,使用 GitOps 来完成部署更新,并且继续更新生产环境中的应用,从而完成了一次应用从开发到上线的完整部署流程。

总结#

使用 KubeVela + Nocalhost,不仅能够便捷地在开发环境中进行云端的联调测试,还能在测试完成后一键更新部署到生产环境,使整个开发上线过程稳定可靠。

基于 KubeVela 的机器学习实践

Tianxin Dong

Tianxin Dong

KubeVela 团队

在机器学习浪潮迸发的当下,AI 工程师除了需要训练、调试自己的模型之外,还需要将模型进行部署上线,从而验证模型的效果(当然,有的时候,这部分工作由 AI 系统工程师来完成)。这一部分工作对于 AI 工程师们来说是繁琐、且消耗额外精力的。

而在云原生时代,我们的模型训练和模型服务也通常在云上进行。这样做不仅提高了可扩展性,还能够提升资源的利用率。这对于需要消耗大量计算资源的机器学习场景来说,是十分有效的。

但是 AI 工程师要想使用云原生的能力通常比较困难。随着时间的推移,云原生的概念已经越来越复杂。想要在云原生之上部署一个简单的模型服务,可能对于 AI 工程师来说,需要额外学习数种概念:比如 Deployment、Service、Ingress 等。

而 KubeVela 作为一个简单、易用、且高可扩展的云原生应用管理工具,能让开发人员方便快捷地在 Kubernetes 上定义与交付应用,无需了解任何底层云原生基础设施相关的细节。KubeVela 拥有着丰富的可扩展性,其 AI 插件提供了模型训练、模型服务、A/B 测试等功能,覆盖了 AI 工程师的基本需求,能够帮助 AI 工程师快速在云原生环境中进行模型训练和模型服务。

本文主要介绍如何使用 KubeVela 的 AI 插件,来帮助工程师更便捷地完成模型训练及模型服务。

KubeVela AI 插件#

KubeVela AI 插件分为模型训练和模型服务两个插件,模型训练插件基于 KubeFlow 的 training-operator,能够支持如 TensorFlow、PyTorch、MXNet 等不同框架的分布式模型训练。而模型服务插件基于 Seldon Core,可以便捷地使用模型启动模型服务,同时也支持流量分发,A/B 测试等高级功能。

alt

通过 KubeVela AI 插件,可以大大简化模型训练任务的部署以及模型服务的部署,同时,可以将模型训练、模型服务等过程与 KubeVela 本身的工作流、多集群等功能相结合,从而完成生产可用的服务部署。

注:你可以在 KubeVela Samples 中找到所有的源码和 YAML 文件。如果你想使用在这个例子中预训练的模型,文件夹中的 style-model.yamlcolor-model.yaml 会将模型复制到 PVC 中。

模型训练#

首先启动模型训练和模型服务的两个插件。

vela addon enable model-training
vela addon enable model-serving

模型训练中包含 model-trainingjupyter-notebook 两个组件类型, 模型服务中包含 model-serving 这个组件类型。可以通过 vela show 命令来查看这三个组件中的具体参数。

你也可以选择查阅 KubeVela AI 插件文档, 来获取更多信息。

vela show model-training
vela show jupyter-notebook
vela show model-serving

我们来训练一个简单的使用 TensorFlow 框架的模型,这个模型的效果是能够将灰色的图片变成彩色的。部署如下 YAML 文件:

注:模型训练的源码来源于:emilwallner/Coloring-greyscale-images

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: training-serving
namespace: default
spec:
components:
# 训练模型
- name: demo-training
type: model-training
properties:
# 训练模型的镜像
image: fogdong/train-color:v1
# 模型训练的框架
framework: tensorflow
# 声明存储,将模型持久化。此处会使用集群内的默认 storage class 来创建 PVC
storage:
- name: "my-pvc"
mountPath: "/model"

此时, KubeVela 将拉起一个 TFJob 进行模型训练。

仅仅是训练模型很难看出效果,我们修改一下这个 YAML 文件,将模型服务放到模型训练的步骤之后。同时,因为模型服务会直接启动模型,而模型的输入输出不太直观(ndarray 或者 Tensor),因此,我们再部署一个测试服务来调用服务,并将结果转换成图像。

部署如下 YAML 文件:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: training-serving
namespace: default
spec:
components:
# 训练模型
- name: demo-training
type: model-training
properties:
image: fogdong/train-color:v1
framework: tensorflow
storage:
- name: "my-pvc"
mountPath: "/model"
# 启动模型服务
- name: demo-serving
type: model-serving
# 模型服务会在模型训练完成后启动
dependsOn:
- demo-training
properties:
# 启动模型服务使用的协议,可以不填,默认使用 seldon 自身的协议
protocol: tensorflow
predictors:
- name: model
# 模型服务的副本数
replicas: 1
graph:
# 模型名
name: my-model
# 模型框架
implementation: tensorflow
# 模型地址,上一步会将训练完的模型保存到 my-pvc 这个 pvc 当中,所以通过 pvc://my-pvc 指定模型的地址
modelUri: pvc://my-pvc
# 测试模型服务
- name: demo-rest-serving
type: webservice
# 测试服务会在模型训练完成后启动
dependsOn:
- demo-serving
properties:
image: fogdong/color-serving:v1
# 使用 LoadBalancer 暴露对外地址,方便调用
exposeType: LoadBalancer
env:
- name: URL
# 模型服务的地址
value: http://ambassador.vela-system.svc.cluster.local/seldon/default/demo-serving/v1/models/my-model:predict
ports:
# 测试服务的端口
- port: 3333
expose: true

部署之后,通过 vela ls 来查看应用的状态:

$ vela ls
training-serving demo-training model-training running healthy Job Succeeded 2022-03-02 17:26:40 +0800 CST
├─ demo-serving model-serving running healthy Available 2022-03-02 17:26:40 +0800 CST
└─ demo-rest-serving webservice running healthy Ready:1/1 2022-03-02 17:26:40 +0800 CST

可以看到,应用已经正常启动。通过 vela status <app-name> --endpoint 来查看应用的服务地址。

$ vela status training-serving --endpoint
+---------+-----------------------------------+---------------------------------------------------+
| CLUSTER | REF(KIND/NAMESPACE/NAME) | ENDPOINT |
+---------+-----------------------------------+---------------------------------------------------+
| | Service/default/demo-rest-serving | tcp://47.251.10.177:3333 |
| | Service/vela-system/ambassador | http://47.251.36.228/seldon/default/demo-serving |
| | Service/vela-system/ambassador | https://47.251.36.228/seldon/default/demo-serving |
+---------+-----------------------------------+---------------------------------------------------+

该应用有三个服务地址,第一个是我们的测试服务的地址,第二个和第三都是原生模型的地址。我们可以调用测试服务来查看模型的效果:测试服务会读取图像的内容,并将其转成 Tensor 并请求模型服务,最后将模型服务返回的 Tensor 转成图像返回。

我们选择一张黑白的女性图片作为输入:

alt

请求后,可以看到,输出了一张彩色图片:

alt

模型服务:灰度测试#

除了直接启动模型服务,我们还可以在一个模型服务中使用多个版本的模型,并对其分配不同的流量以进行灰度测试。

部署如下 YAML,可以看到,v1 版本的模型和 v2 版本的模型都设置为了 50% 的流量。同样,我们在模型服务后面部署一个测试服务:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: color-serving
namespace: default
spec:
components:
- name: color-model-serving
type: model-serving
properties:
protocol: tensorflow
predictors:
- name: model1
replicas: 1
# v1 版本的模型流量为 50
traffic: 50
graph:
name: my-model
implementation: tensorflow
# 模型地址,在 color-model 这个 pvc 中 /model/v1 路径下存放了我们的 v1 版本模型,所以通过 pvc://color-model/model/v1 指定模型的地址
modelUri: pvc://color-model/model/v1
- name: model2
replicas: 1
# v2 版本的模型流量为 50
traffic: 50
graph:
name: my-model
implementation: tensorflow
# 模型地址,在 color-model 这个 pvc 中 /model/v2 路径下存放了我们的 v2 版本模型,所以通过 pvc://color-model/model/v2 指定模型的地址
modelUri: pvc://color-model/model/v2
- name: color-rest-serving
type: webservice
dependsOn:
- color-model-serving
properties:
image: fogdong/color-serving:v1
exposeType: LoadBalancer
env:
- name: URL
value: http://ambassador.vela-system.svc.cluster.local/seldon/default/color-model-serving/v1/models/my-model:predict
ports:
- port: 3333
expose: true

当模型部署完成后,通过 vela status <app-name> --endpoint 查看模型服务的地址:

$ vela status color-serving --endpoint
+---------+------------------------------------+----------------------------------------------------------+
| CLUSTER | REF(KIND/NAMESPACE/NAME) | ENDPOINT |
+---------+------------------------------------+----------------------------------------------------------+
| | Service/vela-system/ambassador | http://47.251.36.228/seldon/default/color-model-serving |
| | Service/vela-system/ambassador | https://47.251.36.228/seldon/default/color-model-serving |
| | Service/default/color-rest-serving | tcp://47.89.194.94:3333 |
+---------+------------------------------------+----------------------------------------------------------+

使用一张黑白的城市图片请求模型:

alt

可以看到,第一次请求的结果如下。虽然天空和地面都被渲染成彩色了,但是城市本身还是黑白的:

alt

再次请求,可以看到,这次请求的结果中,天空、地面和城市都被渲染成了彩色:

alt

通过对不同版本的模型进行流量分发,可以帮助我们更好地对模型结果进行判断。

模型服务:A/B 测试#

同样一张黑白的图片,我们既可以通过模型将其变成彩色的,也可以通过上传另一张风格图片,对原图进行风格迁移。

对于用户来说,究竟是彩色的图片好还是不同风格的图片更胜一筹?我们可以通过进行 A/B 测试,来探索这个问题。

部署如下 YAML,通过设置 customRouting,将 Header 中带有 style: transfer 的请求,转发到风格迁移的模型。同时,使这个风格迁移的模型与彩色化的模型共用一个地址。

注:风格迁移的模型来源于 TensorFlow Hub

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: color-style-ab-serving
namespace: default
spec:
components:
- name: color-ab-serving
type: model-serving
properties:
protocol: tensorflow
predictors:
- name: model1
replicas: 1
graph:
name: my-model
implementation: tensorflow
modelUri: pvc://color-model/model/v2
- name: style-ab-serving
type: model-serving
properties:
protocol: tensorflow
# 风格迁移的模型需要的时间较长,设置超时时间使请求不会被超时
timeout: "10000"
customRouting:
# 指定自定义 Header
header: "style: transfer"
# 指定自定义路由
serviceName: "color-ab-serving"
predictors:
- name: model2
replicas: 1
graph:
name: my-model
implementation: tensorflow
modelUri: pvc://style-model/model
- name: ab-rest-serving
type: webservice
dependsOn:
- color-ab-serving
- style-ab-serving
properties:
image: fogdong/style-serving:v1
exposeType: LoadBalancer
env:
- name: URL
value: http://ambassador.vela-system.svc.cluster.local/seldon/default/color-ab-serving/v1/models/my-model:predict
ports:
- port: 3333
expose: true

部署成功后,通过 vela status <app-name> --endpoint 查看模型服务的地址:

$ vela status color-style-ab-serving --endpoint
+---------+---------------------------------+-------------------------------------------------------+
| CLUSTER | REF(KIND/NAMESPACE/NAME) | ENDPOINT |
+---------+---------------------------------+-------------------------------------------------------+
| | Service/vela-system/ambassador | http://47.251.36.228/seldon/default/color-ab-serving |
| | Service/vela-system/ambassador | https://47.251.36.228/seldon/default/color-ab-serving |
| | Service/vela-system/ambassador | http://47.251.36.228/seldon/default/style-ab-serving |
| | Service/vela-system/ambassador | https://47.251.36.228/seldon/default/style-ab-serving |
| | Service/default/ab-rest-serving | tcp://47.251.5.97:3333 |
+---------+---------------------------------+-------------------------------------------------------+

这个应用中,两个服务各自有两个地址,但是第二个 style-ab-serving 的模型服务地址是无效的,因为这个模型服务已经被指向了 color-ab-serving 的地址中。同样,我们通过请求测试服务来查看模型效果。

首先,在不加 header 的情况下,图像会从黑白变为彩色:

alt

我们添加一个海浪的图片作为风格渲染:

alt

我们为本次请求加上 style: transfer 的 Header,可以看到,城市变成了海浪风格:

alt

我们还可以使用一张水墨画的图片作为风格渲染:

alt

可以看到,这次城市变成了水墨画风格:

alt

总结#

通过 KubeVela 的 AI 插件,可以帮助你更便捷地进行模型训练与模型服务。

除此之外,通过与 KubeVela 的结合,我们还能将测试完效果的模型通过 KubeVela 的多环境功能,下发到不同的环境中,从而实现模型的灵活部署。

如何用 100 行代码快速引入 AWS 最受欢迎的 50 种云资源

KubeVela 目前已经支持了 AWS、Azure、GCP、阿里云、腾讯云、百度云、UCloud 等云厂商,也提供了简单快捷的命令行工具引入云服务商的云资源,但是在 KubeVela 里一个一个地支持云服务商的云资源不利于快速满足用户对于云资源的需求,本文提供了一个方案,用不到 100 行代码快速引入 AWS 前 50 最受欢迎的云资源。

同时,我们也期望用户受到本文的启发,贡献其他云服务商的云资源。

AWS 最受欢迎的云资源在哪里?#

Terraform 官网提供了各个云服务商的 Terraform modules,比如 AWS 的云资源 Terraform modules。其中,云资源按照受欢迎的使用程度(下载量)排序,比如 AWS VPC 下载量为 1870 万次。

通过简单分析,我们发现 AWS 前 50 Terraform modules 的数据可以通过请求 https://registry.terraform.io/v2/modules?filter%5Bprovider%5D=aws&include=latest-version&page%5Bsize%5D=50&page%5Bnumber%5D=1 获取。

开始之前#

代码接受两个用户传入参数:

  • provider 的名称
  • 该 provider 对应的 Terraform Modules 的 URL

对于 AWS 来说,Provider名称为 “aws”,对应的 Terraform modules为Terraform Modules json格式接口(即在Terraform Registry中搜索provider为aws时最受欢迎的50种云资源)。

在执行代码之前需要确认providerName(aws)和Modules链接无误。

执行代码#

那么你就可以通过以下 100 行左右的代码(文件名 gen.go)来批量地快速引入 AWS 最受欢迎的前 50 种云资源。

import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/pkg/errors"
)
type TFDownload struct {
Data []DataItem `json:"data"`
Included []IncludedItem `json:"included"`
}
type IncludedItem struct {
Id string `json:"id"`
Attributes Attributes `json:"attributes"`
}
type DataItem struct {
Attributes Attributes `json:"attributes"`
Relationships Relationships `json:"relationships"`
}
type Relationships struct {
LatestVersion RelationshipLatestVersion `json:"latest-version"`
}
type RelationshipLatestVersion struct {
Data RelationshipData `json:"data"`
}
type RelationshipData struct {
Id string `json:"id"`
}
var errNoVariables = errors.New("failed to find main.tf or variables.tf in Terraform configurations")
type Attributes struct {
Name string `json:"name"`
Downloads int `json:"downloads"`
Source string `json:"source"`
Description string `json:"description"`
Verified bool `json:"verified"`
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Please provide the cloud provider name and an official Terraform modules URL")
os.Exit(1)
}
providerName := os.Args[1]
terraformModulesUrl := os.Args[2]
resp, err := http.Get(terraformModulesUrl)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var modules TFDownload
if err := json.Unmarshal(body, &modules); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
if _, err = os.Stat(providerName); err == nil {
if err := os.RemoveAll(providerName); err != nil {
log.Fatal(err)
}
fmt.Printf("Successfully deleted existed directory %s\n", providerName)
}
if _, err = os.Stat(providerName); os.IsNotExist(err) {
if err := os.Mkdir(providerName, 0755); err != nil {
if !os.IsExist(err) {
log.Fatal(err)
}
fmt.Printf("Successfully created directory %s\n", providerName)
}
}
for _, module := range modules.Data {
var description string
for _, attr := range modules.Included {
if module.Relationships.LatestVersion.Data.Id == attr.Id {
description = attr.Attributes.Description
}
}
if description == "" {
description = strings.ToUpper(providerName) + " " + strings.Title(module.Attributes.Name)
}
outputFile := fmt.Sprintf("%s/terraform-%s-%s.yaml", providerName, providerName, module.Attributes.Name)
if _, err := os.Stat(outputFile); !os.IsNotExist(err) {
continue
}
if providerName == "aws" && (module.Attributes.Name == "rds" || module.Attributes.Name == "s3-bucket" ||
module.Attributes.Name == "subnet" || module.Attributes.Name == "vpc") {
continue
}
if err := generateDefinition(providerName, module.Attributes.Name, module.Attributes.Source, "", description); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}
}
func generateDefinition(provider, name, gitURL, path, description string) error {
defYaml := filepath.Join(provider, fmt.Sprintf("terraform-%s-%s.yaml", provider, name))
cmd := fmt.Sprintf("vela def init %s --type component --provider %s --git %s.git --desc \"%s\" -o %s",
name, provider, gitURL, description, defYaml)
if path != "" {
cmd = fmt.Sprintf("%s --path %s", cmd, path)
}
fmt.Println(cmd)
stdout, err := exec.Command("bash", "-c", cmd).CombinedOutput()
if err != nil {
return errors.Wrap(err, string(stdout))
}
fmt.Println(string(stdout))
return nil
}

执行命令:

go run gen.go aws "https://registry.terraform.io/v2/modules?filter%5Bprovider%5D=aws&include=latest-version&page%5Bsize%5D=50&page%5Bnumber%5D=1"

代码简要说明#

解析云资源数据#

访问用户传入的URL,将返回的json数据解析为Go中的结构体。

资源对应的json格式如下:

{
"data": [
{
"type": "modules",
"id": "23",
"attributes": {
"downloads": 18440513,
"full-name": "terraform-aws-modules/vpc/aws",
"name": "vpc",
"namespace": "terraform-aws-modules",
"owner-name": "",
"provider-logo-url": "/images/providers/aws.png",
"provider-name": "aws",
"source": "https://github.com/terraform-aws-modules/terraform-aws-vpc",
"verified": true
},
"relationships": {
"latest-version": {
"data": {
"id": "142143",
"type": "module-versions"
}
}
},
"links": {
"self": "/v2/modules/23"
}
},
...
],
"included": [
{
"type": "module-versions",
"id": "36806",
"attributes": {
"created-at": "2020-01-03T11:35:36Z",
"description": "Terraform module Terraform module for creating AWS IAM Roles with heredocs",
"downloads": 260030,
"published-at": "2020-02-06T06:26:08Z",
"source": "",
"tag": "v2.0.0",
"updated-at": "2022-02-22T00:45:44Z",
"version": "2.0.0"
},
"links": {
"self": "/v2/module-versions/36806"
}
},
...
],
...
}

在Modules对应的json数据中,我们只关心两个键值对,即:

  • data:包含Modules名称及属性的列表
  • Included:筛选出的特定版本的Modules具体信息

其中,对于data中的每个Module元素,解析它的属性,Id和relationship中的latest-version对应的id;对于Included中的每个Module版本元素,解析它的属性和Id。

属性又解析如下五项:

  • Name
  • Downloads
  • Source
  • Description
  • Verified

结构体定义在结构体 TFDownload 中,通过 http 库获取 json 数据,再通过 json.Unmarshal 解析出 Terraform modules 的结构体。

批量生成云资源#

  1. 新建目录,生成资源所需文件

解析完毕后,在当前目录下新建文件夹,文件夹命名为provider名称。

遍历解析后的data,对于其中每个Module元素,执行下述操作,为其生成相应配置文件,定义和相应文档。

  1. 生成定义文件

通过下述 vela 指令从模块对应的github仓库读取相应信息生成定义文件。

vela def init {ModuleName} --type component --provider {providerName} --git {gitURL} --desc {description} -o {yamlFileName}

指令中需要填入的几项由解析好的Module结构体传入。

  • gitURL: {Module.Attributes.Source}.git
  • description: 如果Included中存在元素ID与模块relationship中latest-version对应ID相同,则description为Included中对应元素属性的description;否则description为providerName与模块名称的拼接
  • yamlFileName:terraform-{providerName}-{Module.Attributes.Name}.yaml

你也来试试?#

还有不少云服务商也提供了丰富的 Terraform modules,比如

GCP:https://registry.terraform.io/namespaces/terraform-google-modules

阿里云:https://registry.terraform.io/namespaces/terraform-alicloud-modules

你要不要也为 KubeVela 引入你正在使用的、或喜欢的云服务商的云资源?

KubeVela v1.2 发布:聚焦开发者体验,轻松发布你的多集群应用

随着云原生的不断发展和成熟,越来越多的基础设施能力逐渐标准化成为 PaaS 平台或者 SaaS 化产品。一个产品的诞生不再像过去那样需要建立一个团队,从开发、测试一直到运维、基础设施全部分多种角色系统完成。如今,敏捷组织文化和云原生技术驱动,使得这些职责更多的是“左移”到了开发者身上,测试左移、监控左移、安全左移,以及 DevOps 等一系列理念都是在强调,通过开源项目或者云的产品和服务将测试、监控、安全、运维等一系列事务提前到开发阶段完成。这看似美好的愿景却给开发者带来了巨大的挑战,开发者对底层五花八门的产品和复杂 API 缺乏掌控力,他们不仅仅是在做选择,更多的需要去理解和协调底层复杂异构的基础设施能力,以便满足上层业务的快速发展和迭代需求。

这种复杂性和不确定性无疑大大降低了开发者的体验,降低了业务系统的交付效率,增加了运维风险。开发者体验的核心是“简单”和“高效率”,不管是开发者还是企业都需要更好用的开发者工具或者平台来达成。在现代云原生技术之上打造一款帮助开发者从开发、交付以及后续持续运维的一体化平台,一直是 KubeVela 演进的核心目标。如图 1 所示,在 v1.2 版本中,我们围绕开发者体验新增了 UI 控制台组件(VelaUX),简化了编排 YAML 的复杂性,完善了插件体系建设,丰富了云资源的扩展能力,增加了大量 CI/CD 等生态对接的能力,进一步完善了开发者端到端的使用体验。

image.png 图1:KubeVela 架构设计

发展历程回顾#

让我们再来简单回顾一下 OAM 和 KubeVela 的发展阶段和历程:

  • OAM(Open Application Model)诞生和成长 在复杂的世界中要创造简单,首先我们需要解决的问题就是抽象和标准化。阿里云和微软联合推出 OAM 模型,创新性地提出“关注点分离”的理念,开发者关注业务本身、运维关注模块化能力。OAM 模型围绕“一切皆服务,全面模块化”的思想,为各大厂商和云原生的平台构建者们实现自己的应用管理平台提供了简单易用与高度可扩展相结合的标准实践方式。该模型提出后的短短一年内便得到了包括 AWS、Oracle、腾讯、华为在内的国内外各大厂商响应,被国家信通院立项作为行业标准。因为大家有共同的目标,降低云原生的使用门槛,让应用交付和管理更简单。

  • KubeVela 开源项目 v1.0 发布,为社区带来了 OAM 的标准实现 有了 OAM 模型作为实践指导,社区高级玩家也开始创造自己的工具来实践,包括阿里、微软、Oracle、Upbond、腾讯在内的一系列公司都基于 OAM 的指导构建了自己的业务平台。但对于更广大的开发者和中小型企业群体来说,他们却无法直接享受模型带来的红利,于是,KubeVela 作为 OAM 社区的官方实现引擎诞生了。它从一开始就由 7 家来自不同组织的 OAM 社区成员从零到一构建。KubeVela 的实现吸收了多家公司针对 OAM 的实践经验,同时结合 Kubernetes 社区生态优势,实现了自动化、可收敛、幂等且稳定的应用发布控制器,围绕 IaC(基础设施即配置)构造了用户友好的抽象层,帮助开发者实现了开箱基于的 OAM 实现引擎。

  • KubeVela v1.1 发布,实现应用交付工作流,原生支持混合环境多集群应用交付 随着企业上云进程的推进,混合云、分布式云等多元化基础设施逐渐成为常态。KubeVela 作为现代应用管理系统也顺应潮流,整体架构升级为面向混合环境做应用交付和管理的控制平面,将所有的功能天然构筑在多集群技术之上。我们相信,出于高可用、成本性能、数据安全等多方面因素,未来大多数企业应用的形态都将是异构多元的。KubeVela v1.1 版本的发布,同时也实现了高度可扩展的应用发布工作流,它天然以混合环境架构呈现,创新性的实现了交付工作流与应用抽象相结合的工作模式,实现了面向终态的应用交付工作流,大大简化了流程编排的复杂性。

时间来到 2022 年,KubeVela 也正式进入了第四个阶段,在原先核心控制器 API 基本稳定的基础上,我们以插件的形式增加了一系列开箱即用的功能。让开发者可以通过 UI 控制台的方式,连接 CI/CD 完整流程,端到端发布多集群应用,进一步提升开发者体验。

v1.2 版本的核心能力#

图形化操作控制台(VelaUX)#

提供好用的图形化操作界面是降低开发者使用门槛的首选途径,从 KubeVela 诞生以来,社区对 UI 控制台的呼声一直很高。从 v1.2 版本开始,它正式到来了。打造 UI 控制台的目的是帮助开发者以更标准化的方式组装和管理异构业务应用,帮助他们分析和更快的发现业务故障和阻碍。

VelaUX 是 KubeVela 的前端项目,设计实现时它充分考虑了 KubeVela 的可扩展性这一核心要点。引入了低代码平台的理念来打造前端,我们的目标是打造一个可以通过拖拉拽方式就能做到自定义应用交付输入参数,并且实现运行数据可观测的平台。为此我们设计了前端描述规范 UISchema,配合 KubeVela 的模块化定义 X-Definition,通过配置就可以渲染出丰富的前端交互元素。同时为了让前端的数据查询也配置化,我们设计了多维数据自定义查询语言 VelaQL,这样的设计形成了 KubeVela 交付和管理异构应用的基础。

目前通过 VelaUX ,用户可以管理扩展,连接 Kubernetes 集群,分配交付目标,规划环境和交付各类型应用,并观测应用运行状态,实现应用交付的完整闭环。

image.png 图2:VelaUX 预览

如图 2 所示,VelaUX 中出现了一些新名词,请参考 核心概念 文档进行学习和了解。

多环境统一化管理#

KubeVela 将 N 个Kubernetes 集群,N 个云厂商服务或其他私有云服务统一为大的基础设施资源池。在此基础上,我们的开发者可以按照业务需求、流程需求、团队需求等多种业务维度划分环境。在大资源池的基础上形成环境空间。同一个应用可发布到不同的环境,环境之间从管理到运行态完全隔离。

image.png 图3:多环境/多集群应用管理页面

如图 3 所示,应用可被发布到生产、测试、默认三个环境中,每一个环境可以包括多个交付目标,每一个交付目标背后可以是独立的 Kubernetes 集群。

异构应用标准化交付#

在云原生体系中,我们交付应用的形式选择非常多。基于 Kubernetes 基础设施,我们既可以通过成熟的 Helm Chart 包交付中间件和第三方开源应用,也可以通过镜像交付企业业务应用,还可以通过 OpenYurt 交付管理边缘应用。 基于云服务商的开放能力,我们可以交付数据库、消息、缓存等中间件,也有日志、应用监控等运维能力。

对于这么多的可选项,KubeVela 采用标准的 OAM 规范实现对异构应用的统一交付和管理。KubeVela 实现了高度可扩展的交付系统,通过内置、社区共享等形态帮助用户扩展平台,以一致化的交付和管理体验处理异构的应用。在 KubeVela 之上,开发者看到的都是模块化、一切皆服务的管理形态。

image.png 图4:云服务应用管理页面

如图 4 所示,我们可以看到,相同的应用管理页面,用户可以非常便捷得获取到云服务应用。开发者可以通过阅读下面几篇文档查看异构应用的交付过程:

  1. 交付 Docker 镜像
  2. 交付 Helm Chart 包
  3. 交付 Kubernetes 资源
  4. 交付 云服务

扩展体系(Addon)#

KubeVela 从一开始就是设计为一款微内核高可扩展的系统,上文我们说到异构应用,KubeVela 可以通过扩展体系,以标准化的形态,扩充无限的应用交付能力。既匹配企业差异性诉求,也不带来过多的认知负担。KubeVela 中可扩展的点包括了组件类型、运维能力、工作流类型、应用交付策略等。在当前版本中,我们发布了 Addon 扩展体系。Addon 是组织各种扩展能力的承载体,它便于分发和管理。

image.png 图5:KubeVela 插件管理页面

目前在官方仓库中已经存在如图 5 所示的可用 Addon。同时在实验性仓库中我们正在联合社区用户积极创造更多的扩展能力。当然,这里需要每一个社区开发者的积极参与。

截止到现在,KubeVela 已经成长为一款可直接服务于广大开发者的应用交付平台,那么企业哪些场景可以直接利用 KubeVela 呢?我们整理了以下几个常见场景:

企业开发场景解决方案#

多集群应用 DevOps#

在过往社区的交流中,我们发现企业主流的研发体系都类似如图 6 所示的结构,他们使用云服务厂商提供的计算资源作为生产、演示环境。使用自己购买或历史遗留的服务器搭建开发、测试环境。如果业务有多区域或灾备需求,生产环境可能需要部署到多个区域或多云。

image.png 图6:多集群应用实践架构

对于基础的 DevOps 流程,包括了代码托管和 CI/CD 的环节。KubeVela 目前为你提供 CD 环节的支持。对于企业实践的步骤如下:

  1. 根据实际情况准备本地或云服务资源。至少单项打通本地和云资源的网络,便于资源集中管理。
  2. 将 KubeVela 系统搭建在生产环境中,保障持续的可用性。
  3. 通过 KubeVela 部署 Gitlab、Jenkins、Sonar 等 DevOps 工具,并打通工具链。通常情况下,代码托管和开发工具的可用性至关重要,我们需要将其部署在生产环境中(如果你本地机房具备生产可用性,且希望代码数据在本地环境流转,可部署在本地机房)。
  4. 通过 KubeVela 规划本地开发环境,部署本地测试用中间件,规划生产环境和部署云服务中间件。
  5. 通过 Jenkins 搭建业务代码 CI 流水线,产出 Docker 镜像交由 KubeVela 进行多环境部署,形成完整应用交付工作流。

结合 KubeVela 的多集群应用 DevOps 方案有如下优势:

  1. 开发者无需掌握过多的 Kubernetes 生态知识,可实现异构应用云原生部署。
  2. 多集群,多环境统一管理,原生可部署跨集群应用。
  3. 统一的应用管理模式,无论是业务应用还是开发工具链。
  4. 灵活的工作流,帮助企业打通各种开发规范流程。

混合环境一体化管理#

不同的企业往往都存在不一样的基础设施和业务诉求。在基础设施侧:企业可能搭建了私有云,可能购买了公有云,可能还有边缘计算资源。在业务侧:不同的业务规模不同,资源需求不同,可能有多云多活应用,也有企业遗留系统。在研发侧:业务研发往往需要开发、测试、预发和生产环境。在管理侧:不同的业务团队需要相互隔离,又可能需要业务互通。

随着时间的累积,企业由于职责边界和不同分工的影响,会逐渐形成不同业务团队相互独立甚至割裂的状态,这种割裂包括了:开发工具割裂,技术架构割裂,业务管理形态割裂。KubeVela 秉持着“尊重现实,积极创新”的原则,带来的方案是追求统一的过程中用高扩展的能力去兼容差异性。

  • 面对基础设施差异,我们支持以 Kubernetes API、云服务 API 或其他自定义 API 的形态,去对基础设施进行充分的模型化。最终通过统一的 OAM 模型向上暴露一致的概念。
  • 面对业务架构差异,应用模型是开放的,对架构无要求的。KubeVela 做的是连接和赋能,连接已有系统,通过扩展机制加持新的生态技术。
  • 面对开发工具链的差异,企业中可能已经存在不同的开发工具链,产出不同的业务制品。 KubeVela 通过扩展和标准模型去支持各类制品,实现其标准化交付。当然,它的标准逐步衍生到前置环节,帮助企业逐步实现工具链一致化。因此,你不用担心你是用的 Gitlab 还是 Jenkins,它都能对接。
  • 面对运维能力差异,企业中不同团队的运维能力、工具方案可以在 KubeVela 的规范下逐步积累,能力互通。更多运维能力也同样在社区的维度进行共享和复用。

因此,使用 KubeVela 来作为企业打通业务,进行统一能力建设的基础平台,它是可落地、有未来的方案

自定义企业发布平台#

从 Heroku 、Cloud Foundry 时代开始,市场上一直在产生不同的 PaaS 平台,我们都知道固定模式的发布平台往往不适合所有的企业。举个例子,某些规范化程度较高的企业,他们基于业务的特性,发布应用时仅需更新镜像名称,然而使用通用 PaaS 就不得不去理解大量的概念和参数。再比如某个企业生产的是 AI 应用,对于 AI 应用的发布与普通应用有比较大的区别,这时就需要定制 AI 场景的 PaaS,企业不得不付更多的费用和学习更多的概念。

通用产品不符合企业需求时,自研是真实存在的诉求。但是对于从零开始自研平台,必然又需要投入大量的人力物力,甚至超过了企业核心业务的投入,这显得得不偿失。KubeVela 也考虑到了具备自研能力企业的独特诉求,他们可以基于 KubeVela 微内核、高可扩展的设计,针对自己的业务场景和领域知识,打造属于自己的、更为简单易用的业务平台。

对于需要自研发布平台的企业来说,KubeVela 的微内核是一个 PaaS 平台研发框架。一方面,企业可以根据自己的需求自研或者安装社区的各种功能插件;另一方面,企业也可以基于 OAM 模型修改模块化配置,新增或裁剪用户使用的参数。这种模块化的设计可以大大降低企业的投入成本,同时可以跟上社区的发展潮流,随时将社区更多的先进技术转化为自身的生产力。

参与社区#

做了这么多的介绍,你是否对 KubeVela 的发展有了一些新的认识,没有哪个产品是绝对的银弹,也没有一个方案可以解决所有的问题。但是我们的理想是可以创造一个标准化模式,让更多的企业和开发者用户参与到这场为了“简单”和“高效”的开发者体验战役中来。KubeVela 还很年轻,我们希望你可以参与进来共同打造。这里非常感谢在过去参与 KubeVela 贡献的 100 多位开发者,正是因为你们的携手努力,才让我们的社区生态变得更加繁荣。

共建 OAM 应用规范#

对于 OAM 应用规范,模型的更新和升级基于 KubeVela 实践驱动,但是它并不绑定 KubeVela 实现。它是 KubeVela 在云原生应用交付和管理层面实践经验的总结和抽象,是创造规范化应用管理体系的最佳实践和核心理念。我们非常欢迎云厂商、平台厂商、最终用户可以参与进来,同时我们也欣喜的看到国内包括腾讯在内的多家厂商对 OAM 应用规范的关注和支持。任何人、组织都可以发表你的想法、建议和思考。

访问,参与 OAM 模型讨论

共建 Addon 扩展生态#

如上文介绍的一样,我们已经开启了 Addon 的扩展体系,非常欢迎社区的创造者、开发者可以来贡献更多的扩展能力。

访问,如何扩展和贡献 Addon 参考文档

贡献云服务能力#

KubeVela 通过集成 Terraform Module 来扩展云服务集成能力,我们已经支持了 常用的云资源 ,欢迎社区朋友参考并贡献更多的云服务厂商和产品。

访问,如何扩展和贡献云资源

反馈你的需求或痛点#

或许你是普通开发者,也或许你是云原生领域的从业者,如果你认可我们的方向,认可我们正在做的事情,我们非常欢迎你可以参与到 KubeVela 社区讨论中来。

访问,参与社区讨论

KubeVela 网站加速访问#

KubeVela 的官方文档托管在 GitHub kubevela.io 上,如果你发现有任何错漏或者想要参与翻译,欢迎直接到项目中贡献。同时为了国内用户可以加速访问,我们增加了 kubevela.net 这个域名,可以方便国内用户更快的访问,内容与 kubevela.io 的域名完全一致、实时同步。

KubeVela 是 CNCF 沙箱项目,了解更多信息,请查阅官方文档

基于 KubeVela 的 GitOps 交付

Tianxin Dong

Tianxin Dong

KubeVela 团队

KubeVela 作为一个简单、易用、且高可扩展的云原生应用管理工具,能让开发人员方便快捷地在 Kubernetes 上定义与交付现代微服务应用,无需了解任何 Kubernetes 基础设施相关的细节。

KubeVela 背后的 OAM 模型天然解决了应用构建过程中对复杂资源的组合、编排等管理问题,同时也将后期的运维策略模型化,这意味着 KubeVela 可以结合 GitOps 管理复杂大规模应用,收敛团队与系统规模变大以后的系统复杂度问题。

什么是 GitOps#

GitOps 是一种现代化的持续交付手段,它的核心思想是:在拥有一个包含环境基础设施及各种应用配置的 Git 仓库中,配合一个自动化过程————使得每次仓库被更新后,自动化过程都能逐渐将环境更新到最新配置。

这样的方式允许开发人员通过直接更改 Git 仓库中的代码和配置来自动部署应用,使用 GitOps 的好处有很多,如:

  • 提高生产效率。通过自动的持续部署能够加快平均部署时间,增加开发效率。
  • 降低开发人员部署的门槛。通过推送代码而非容器配置,开发人员可以不需要了解 Kubernetes 的内部实现,便可以轻易部署。
  • 使变更记录可追踪。通过 Git 来管理集群,可以使每一次更改都可追踪,加强了审计跟踪。
  • 可通过 Git 的回滚/分支功能来恢复集群。

KubeVela 与 GitOps#

KubeVela 作为一个声明式的应用交付控制平面,天然就可以以 GitOps 的方式进行使用,并且这样做会在 GitOps 的基础上为用户提供更多的益处和端到端的体验,包括:

  • 应用交付工作流(CD 流水线)
    • 即:KubeVela 支持在 GitOps 模式中描述过程式的应用交付,而不只是简单的声明终态;
  • 处理部署过程中的各种依赖关系和拓扑结构;
  • 在现有各种 GitOps 工具的语义之上提供统一的上层抽象,简化应用交付与管理过程;
  • 统一进行云服务的声明、部署和服务绑定;
  • 提供开箱即用的交付策略(金丝雀、蓝绿发布等);
  • 提供开箱即用的混合云/多云部署策略(放置规则、集群过滤规则等);
  • 在多环境交付中提供 Kustomize 风格的 Patch 来描述部署差异,而无需学习任何 Kustomize 本身的细节;
  • …… 以及更多。

在本文中,我们主要讲解直接使用 KubeVela 在 GitOps 模式下进行交付的步骤。

GitOps 工作流#

GitOps 工作流分为 CI 和 CD 两个部分:

  • CI(Continuous Integration):持续集成对业务代码进行代码构建、构建镜像并推送至镜像仓库。目前有许多成熟的 CI 工具:如开源项目常用的 GitHub Action、Travis 等,以及企业中常用的 Jenkins、Tekton 等。在本文中,我们使用 GitHub Action 来完成 CI 这一步,你也可以使用别的 CI 工具来代替此步,KubeVela 围绕 GitOps 可以对接任意工具下的 CI 流程。
  • CD(Continuous Delivery):持续部署会自动更新集群中的配置,如将镜像仓库中的最新镜像更新到集群中。
    • 目前主要有两种方案的 CD:
      • Push-Based:Push 模式的 CD 主要是通过配置 CI 流水线来完成的,这种方式需要将集群的访问秘钥共享给 CI,从而使得 CI 流水线能够通过命令将更改推送到集群中。这种方式的集成可以参考我们之前发表的博客:使用 Jenkins + KubeVela 完成应用的持续交付
      • Pull-Based:Pull 模式的 CD 会在集群中监听仓库(代码仓库或者配置仓库)的变化,并且将这些变化同步到集群中。这种方式与 Push 模式相比,由集群主动拉取更新,从而避免了秘钥暴露的问题。这也是本文介绍的核心内容。

交付的面向人员有以下两种,我们将分别介绍:

  1. 面向平台管理员/运维人员的基础设施交付,用户可以通过直接更新仓库中的配置文件,从而更新集群中的基础设施配置,如系统的依赖软件、安全策略、存储、网络等基础设施配置。
  2. 面向终端开发者的交付,用户的代码一旦合并到应用代码仓库,就自动化触发集群中应用的更新,可以更高效的完成应用的迭代,与 KubeVela 的灰度发布、流量调拨、多集群部署等功能结合可以形成更为强大的自动化发布能力。

面向平台管理员/运维人员的交付#

如图所示,对于平台管理员/运维人员而言,他们并不需要关心应用的代码,所以只需要准备一个 Git 配置仓库并部署 KubeVela 配置文件,后续对于应用及基础设施的配置变动,便可通过直接更新 Git 配置仓库来完成,使得每一次配置变更可追踪。

alt

准备配置仓库#

具体的配置可参考 示例仓库

在本例中,我们将部署一个 MySQL 数据库软件作为项目的基础设施,同时部署一个业务应用,使用这个数据库。配置仓库的目录结构如下:

  • clusters/ 中包含集群中的 KubeVela GitOps 配置,用户需要将 clusters/ 中的文件手动部署到集群中。这个是一次性的管控操作,执行完成后,KubeVela 便能自动监听配置仓库中的文件变动且自动更新集群中的配置。其中,clusters/apps.yaml 将监听 apps/ 下所有应用的变化,clusters/infra.yaml 将监听 infrastructure/ 下所有基础设施的变化。
  • apps/ 目录中包含业务应用的所有配置,在本例中为一个使用数据库的业务应用。
  • infrastructure/ 中包含一些基础设施相关的配置和策略,在本例中为 MySQL 数据库。
├── apps
│   └── my-app.yaml
├── clusters
│   ├── apps.yaml
│   └── infra.yaml
└── infrastructure
└── mysql.yaml

KubeVela 建议使用如上的目录结构管理你的 GitOps 仓库。clusters/ 中存放相关的 KubeVela GitOps 配置并需要被手动部署到集群中,apps/infrastructure/ 中分别存放你的应用和基础设施配置。通过把应用和基础配置分开,能够更为合理的管理你的部署环境,隔离应用的变动影响。

clusters/ 目录#

首先,我们来看下 clusters 目录,这也是 KubeVela 对接 GitOps 的初始化操作配置目录。

clusters/infra.yaml 为例:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: infra
spec:
components:
- name: database-config
type: kustomize
properties:
repoType: git
# 将此处替换成你需要监听的 git 配置仓库地址
url: https://github.com/FogDong/KubeVela-GitOps-Infra-Demo
# 如果是私有仓库,还需要关联 git secret
# secretRef: git-secret
# 自动拉取配置的时间间隔,由于基础设施的变动性较小,此处设置为十分钟
pullInterval: 10m
git:
# 监听变动的分支
branch: main
# 监听变动的路径,指向仓库中 infrastructure 目录下的文件
path: ./infrastructure

apps.yamlinfra.yaml 几乎保持一致,只不过监听的文件目录有所区别。 在 apps.yaml 中,properties.path 的值将改为 ./apps,表明监听 apps/ 目录下的文件变动。

cluster 文件夹中的 GitOps 管控配置文件需要在初始化的时候一次性手动部署到集群中,在此之后 KubeVela 将自动监听 apps/ 以及 infrastructure/ 目录下的配置文件并定期更新同步。

apps/ 目录#

apps/ 目录中存放着应用配置文件,这是一个配置了数据库信息以及 Ingress 的简单应用。该应用将连接到一个 MySQL 数据库,并简单地启动服务。在默认的服务路径下,会显示当前版本号。在 /db 路径下,会列出当前数据库中的信息。

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: my-app
namespace: default
spec:
components:
- name: my-server
type: webservice
properties:
image: ghcr.io/fogdong/test-fog:master-cba5605f-1632714412
port: 8088
env:
- name: DB_HOST
value: mysql-cluster-mysql.default.svc.cluster.local:3306
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: ROOT_PASSWORD
traits:
- type: ingress
properties:
domain: testsvc.example.com
http:
/: 8088

这是一个使用了 KubeVela 内置组件类型 webservice 的应用,该应用绑定了 Ingress 运维特征。通过在应用中声明运维能力的方式,只需一个文件,便能将底层的 Deployment、Service、Ingress 集合起来,从而更为便捷地管理应用。

infrastructure/ 目录#

infrastructure/ 目录下存放一些基础设施的配置。此处我们使用 mysql controller 来部署了一个 MySQL 集群。

注意,请确保你的集群中有一个 secret,并通过 ROOT_PASSWORD 声明了 MySQL 密码。

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: mysql
namespace: default
spec:
components:
- name: mysql-controller
type: helm
properties:
repoType: helm
url: https://presslabs.github.io/charts
chart: mysql-operator
version: "0.4.0"
- name: mysql-cluster
type: raw
dependsOn:
- mysql-controller
properties:
apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
name: mysql-cluster
spec:
replicas: 1
# 关联 secret 名称
secretName: mysql-secret

在这个 MySQL 应用中,我们使用了 KubeVela 工作流的能力。工作流分为两个步骤,第一个步骤会去部署 MySQL 的 controller。当 controller 部署成功且正确运行后,第二个步骤将开始部署 MySQL 集群。

部署 clusters/ 目录下的文件#

配置完以上文件并存放到 Git 配置仓库后,我们需要在集群中手动部署 clusters/ 目录下的 KubeVela GitOps 配置文件。

首先,在集群中部署 clusters/infra.yaml。可以看到它自动在集群中拉起了 infrastructure/ 目录下的 MySQL 部署文件:

kubectl apply -f clusters/infra.yaml
$ vela ls
APP COMPONENT TYPE TRAITS PHASE HEALTHY STATUS CREATED-TIME
infra database-config kustomize running healthy 2021-09-26 20:48:09 +0800 CST
mysql mysql-controller helm running healthy 2021-09-26 20:48:11 +0800 CST
└─ mysql-cluster raw running healthy 2021-09-26 20:48:11 +0800 CST

接着,在集群中部署 clusters/apps.yaml,可以看到它自动拉起了 apps/ 目录下的应用部署文件:

kubectl apply -f clusters/apps.yaml
APP COMPONENT TYPE TRAITS PHASE HEALTHY STATUS CREATED-TIME
apps apps kustomize running healthy 2021-09-27 16:55:53 +0800 CST
infra database-config kustomize running healthy 2021-09-26 20:48:09 +0800 CST
my-app my-server webservice ingress running healthy 2021-09-27 16:55:55 +0800 CST
mysql mysql-controller helm running healthy 2021-09-26 20:48:11 +0800 CST
└─ mysql-cluster raw running healthy 2021-09-26 20:48:11 +0800 CST

至此,我们通过部署 KubeVela GitOps 配置文件,自动在集群中拉起了应用及数据库。

通过 curl 应用的 Ingress,可以看到目前的版本是 0.1.5,并且成功地连接到了数据库:

$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
my-server <none> testsvc.example.com <ingress-ip> 80 162m
$ curl -H "Host:testsvc.example.com" http://<ingress-ip>
Version: 0.1.5
$ curl -H "Host:testsvc.example.com" http://<ingress-ip>/db
User: KubeVela
Description: It's a test user

修改配置#

完成了首次部署后,我们可以通过修改配置仓库中的配置,来完成集群中应用的配置更新。

修改应用 Ingress 的 Domain:

...
traits:
- type: ingress
properties:
domain: kubevela.example.com
http:
/: 8089

经过一段时间后,重新查看集群中的 Ingress:

NAME CLASS HOSTS ADDRESS PORTS AGE
my-server <none> kubevela.example.com <ingress-ip> 80 162m

可以看到,Ingress 的 Host 地址已被成功更新。

通过这种方式,我们可以方便地通过更新 Git 配置仓库中的文件,从而自动化更新集群中的配置。

面向终端开发者的交付#

如图所示,对于终端开发者而言,在 KubeVela Git 配置仓库以外,还需要准备一个应用代码仓库。在用户更新了应用代码仓库中的代码后,需要配置一个 CI 来自动构建镜像并推送至镜像仓库中。KubeVela 会监听镜像仓库中的最新镜像,并自动更新配置仓库中的镜像配置,最后再更新集群中的应用配置。使用户可以达成在更新代码后,集群中的配置也自动更新的效果。

alt

准备代码仓库#

准备一个代码仓库,里面包含一些源代码以及对应的 Dockerfile。

这些代码将连接到一个 MySQL 数据库,并简单地启动服务。在默认的服务路径下,会显示当前版本号。在 /db 路径下,会列出当前数据库中的信息。

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "Version: %s\n", VERSION)
})
http.HandleFunc("/db", func(w http.ResponseWriter, r *http.Request) {
rows, err := db.Query("select * from userinfo;")
if err != nil {
_, _ = fmt.Fprintf(w, "Error: %v\n", err)
}
for rows.Next() {
var username string
var desc string
err = rows.Scan(&username, &desc)
if err != nil {
_, _ = fmt.Fprintf(w, "Scan Error: %v\n", err)
}
_, _ = fmt.Fprintf(w, "User: %s \nDescription: %s\n\n", username, desc)
}
})
if err := http.ListenAndServe(":8088", nil); err != nil {
panic(err.Error())
}

我们希望用户改动代码进行提交后,自动构建出最新的镜像并推送到镜像仓库。这一步 CI 可以通过集成 GitHub Actions、Jenkins 或者其他 CI 工具来实现。在本例中,我们通过借助 GitHub Actions 来完成持续集成。具体的代码文件及配置可参考 示例仓库

配置秘钥信息#

在新的镜像推送到镜像仓库后,KubeVela 会识别到新的镜像,并更新仓库及集群中的 Application 配置文件。因此,我们需要一个含有 Git 信息的 Secret,使 KubeVela 向 Git 仓库进行提交。部署如下文件,将其中的用户名和密码替换成你的 Git 用户名及密码(或 Token):

apiVersion: v1
kind: Secret
metadata:
name: git-secret
type: kubernetes.io/basic-auth
stringData:
username: <your username>
password: <your password>

准备配置仓库#

配置仓库与之前面向运维人员的配置大同小异,只需要加上与镜像仓库相关的配置即可。具体配置请参考 示例仓库

修改 clusters/ 中的 apps.yaml,该 GitOps 配置会监听仓库中 apps/ 下的应用文件变动以及镜像仓库中的镜像更新:

...
imageRepository:
# 镜像地址
image: <your image>
# 如果这是一个私有的镜像仓库,可以通过 `kubectl create secret docker-registry` 创建对应的镜像秘钥并相关联
# secretRef: imagesecret
filterTags:
# 可对镜像 tag 进行过滤
pattern: '^master-[a-f0-9]+-(?P<ts>[0-9]+)'
extract: '$ts'
# 通过 policy 筛选出最新的镜像 Tag 并用于更新
policy:
numerical:
order: asc
# 追加提交信息
commitMessage: "Image: {{range .Updated.Images}}{{println .}}{{end}}"

修改 apps/my-app.yaml 中的 image 字段,在后面加上 # {"$imagepolicy": "default:apps"} 的注释。KubeVela 会通过该注释去更新对应的镜像字段。default:apps 是上面 GitOps 配置对应的命名空间和名称。

spec:
components:
- name: my-server
type: webservice
properties:
image: ghcr.io/fogdong/test-fog:master-cba5605f-1632714412 # {"$imagepolicy": "default:apps"}

clusters/ 中包含镜像仓库配置的文件更新到集群中后,我们便可以通过修改代码来完成应用的更新。

修改代码#

将代码文件中的 Version 改为 0.1.6,并修改数据库中的数据:

const VERSION = "0.1.6"
...
func InsertInitData(db *sql.DB) {
stmt, err := db.Prepare(insertInitData)
if err != nil {
panic(err)
}
defer stmt.Close()
_, err = stmt.Exec("KubeVela2", "It's another test user")
if err != nil {
panic(err)
}
}

提交该改动至代码仓库,可以看到,我们配置的 CI 流水线开始构建镜像并推送至镜像仓库。

而 KubeVela 会通过监听镜像仓库,根据最新的镜像 Tag 来更新配置仓库中 apps/ 下的应用 my-app

此时,可以看到配置仓库中有一条来自 kubevelabot 的提交,提交信息均带有 Update image automatically. 前缀。你也可以通过 {{range .Updated.Images}}{{println .}}{{end}}commitMessage 字段中追加你所需要的信息。

alt

值得注意的是,如果你希望将代码和配置放在同一个仓库,需要过滤掉来自 kubevelabot 的提交来防止流水线的重复构建。可以在 CI 中通过如下配置过滤:

jobs:
publish:
if: "!contains(github.event.head_commit.message, 'Update image automatically')"

重新查看集群中的应用,可以看到经过一段时间后,应用 my-app 的镜像已经被更新。

KubeVela 会通过你配置的 interval 时间间隔,来每隔一段时间分别从配置仓库及镜像仓库中获取最新信息:

  • 当 Git 仓库中的配置文件被更新时,KubeVela 将根据最新的配置更新集群中的应用。
  • 当镜像仓库中多了新的 Tag 时,KubeVela 将根据你配置的 policy 规则,筛选出最新的镜像 Tag,并更新到 Git 仓库中。而当代码仓库中的文件被更新后,KubeVela 将重复第一步,更新集群中的文件,从而达到了自动部署的效果。

通过 curl 对应的 Ingress 查看当前版本和数据库信息:

$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
my-server <none> kubevela.example.com <ingress-ip> 80 162m
$ curl -H "Host:kubevela.example.com" http://<ingress-ip>
Version: 0.1.6
$ curl -H "Host:kubevela.example.com" http://<ingress-ip>/db
User: KubeVela
Description: It's a test user
User: KubeVela2
Description: It's another test user

版本已被成功更新!至此,我们完成了从变更代码,到自动部署至集群的全部操作。

总结#

在运维侧,如若需要更新基础设施(如数据库)的配置,或是应用的配置项,只需要修改配置仓库中的文件,KubeVela 将自动把配置同步到集群中,简化了部署流程。

在研发侧,用户修改代码仓库中的代码后,KubeVela 将自动更新配置仓库中的镜像。从而进行应用的版本更新。

通过与 GitOps 的结合,KubeVela 加速了应用从开发到部署的整个流程。

KubeVela 1.1 发布,开启混合环境应用持续交付新里程碑

在云原生理念迅速普及的今天,混合环境部署(混合云/多云/分布式云/边缘)已经成为了大多数企业应用、SaaS 服务、应用持续交付平台的必然选择,而云原生技术的发展趋势也正在朝着“一致的、跨云、跨环境的的应用交付”不断迈进。然而,无论是 Kubernetes 本身还是现有的各类应用交付系统,都没有在现今混合、分布式的部署环境之上引入一致的上层抽象来为应用交付进行建模。这种缺乏统一上层抽象的应用交付过程,往往同底层基础设施紧密耦合,导致用户心智负担很重并且严重依赖于用户个人的经验和能力。这不仅会大幅影响用户体验、降低生产效率,甚至还会导致错误和故障的发生。

而现在,这个问题终于有了一个开源、标准,又不失灵活度的解法。它就是:

kubevela-logo.png

KubeVela 作为一个开箱即用、面向现代微服务架构的应用交付与管理平台,今天正式发布了 1.1 版本,以更加用户友好和完善的功能集,开启了”让混合环境应用交付更加简单高效“的重要里程碑。

具体来说,1.1 版本的 KubeVela 与现有各类应用交付系统相比,有着显著的不同和优势:

  • 完全以应用为中心 与各类“搭积木”式的 PaaS 系统或者应用平台不同,KubeVela 项目本身是构建于一套完善的应用交付模型与理论基础之上的,这就是“开放应用模型(OAM)”技术。OAM 模型能够通过声明式的定义来捕获面向混合环境的微服务应用交付的整个过程,甚至包括云服务的拉起与绑定、可观测性、多集群分发策略、流量调配和滚动更新等各种运维行为和特征。通过这样一个统一的、基础设施无关的上层模型,KubeVela 天然就能够做到让用户无需关心任何基础设施细节、只专注于业务价值和交付过程,真正实现了完全 Serverless 化的应用管理与交付体验。

  • 可编程式交付工作流 - 在 Kubernetes 面向终态的基础上,KubeVela 还通过“交付流水线(Workflow)“来支持面向过程的应用交付流程,同时通过 Kubernetes 终态能力来保证该流水线执行的正确性与幂等性。在内核中,KubeVela 流水线是通过 CUE 来实现的。CUE 是一种诞生自 Google Borg 系统的数据配置语言(即:borgcfg),它可以将应用交付过程的所有步骤、所需资源、关联的运维动作以可编程的方式定义成一个 DAG(有向无环图),并以此作为用户最终的交付计划。这使得 KubeVela 的交付流水线不仅使用简单、扩展性极强,也更符合现代 GitOps 应用交付的趋势与要求。

  • 基础设施无关 - 在 1.1 版本中,KubeVela 完成了 100% 的“控制平面化”。这意味着它本身成为了一个运行在管控集群中的、完全与应用运行基础设施无关的交付控制平面。这种“使用 Kubernetes 作为管控平面、面向任何基础设施进行应用交付与管理”的新架构,使得 KubeVela 可以按照用户定义的工作流与交付策略,面向任何环境交付和管理任意类型的应用组件,包括:容器、云函数、数据库、云服务、虚拟机实例等等。

KubeVela 1.1 介绍#

自 Kubevela 1.0 版本发布以来,KubeVela 社区发展非常迅速,截止目前已经有超过 100+ 名开发者参与贡献,而且就在上个月,KubeVela 和 OAM 项目也已经整体捐赠给了 CNCF 基金会进行托管。在 1.1 版本中,KubeVela 更加聚焦面向混合环境的应用交付流程,带来了多集群交付、交付流程定义、灰度发布、公有云资源接入等多个开箱即用的能力和更加友好的用户体验。这其中,有两个核心能力值得特别关注:

  • 天然支持多环境、多集群应用交付:Kubevela 将底层环境的基础设施进行了面向应用的标准化抽象,涵盖了交付制品、算力(基础计算、AI计算、云边协同计算)、运维特征(监控、流量治理、日志收集等)等多个维度。用户能够非常方便的将应用描述跟不同的待交付环境(集群)进行匹配、定义不同环境下的配置 Patch,从而把应用差异化地交付到不同环境或者集群当中。

  • 天然支持声明式交付工作流:众所周知,Kubernetes 的资源模型是以终态来维护的,但是实际的应用交付场景,却往往是一个面向过程的系列操作(比如:声明组件 A - 部署组件 A 到测试集群 - 切 50% 流量到组件 A - 运行测试 - 发布到生成集群等等)。所以在社区中,用户希望简单、透明的控制应用交付流程的诉求非常强烈,但往往又不希望因此引入一套全新的、完整的 CI/CD 系统。为此,KubeVela 1.1 在应用模型中增加了 Workflow 语义来精细化的描述整个应用交付工作流,并且内置就提供”人工审批“、”回滚“、”数据传递“、“Slack/钉钉通知”等多个工作流步骤(Step)。更重要的是,这种实现在应用模型层的声明式 Workflow 天然具备被集成能力,可以非常自然的同现有 CI/CD 系统或者 GitOps 工具通过扩展的方式做集成,而不需要用户在取舍间痛苦。

正是通过上述设计,KubeVela 可以帮助你从“静态配置、模板、胶水代码”的初级阶段,直接升级至“自动化、声明式、统一模型、天然面向多环境”的下一代以工作流为核心的交付体验当中。

undefined

基于上述能力,用户现在可以通过 KubeVela 非常轻松的处理以下场景:

多环境、多集群应用交付#

面向 Kubernetes 的多环境、多集群交付已是一个标准性需求。你或许是需要环境隔离,开发、预发和生产三套集群;或许是需要交付不同的客户,每个客户独立一套集群;或许是需要交付到不同区域,在北京、广州多套集群;又或许你业务规模大,单个 Kubernetes 集群无法满足你的资源需求。从 1.1 版本开始,KubeVela 不仅实现了多集群的应用交付,并且既可以独立工作直接纳管多个集群,也可以集成 OCM、Karmada 等各类多集群管理工具来进行更复杂的交付动作。

多集群应用发布Demo(结合Workflow)

在上述例子中,我们就将一个应用差异化的交付了到不同的集群环境中。这种“交付差异”在 KubeVela 中属于交付策略(Policy)的一种,它可以是环境配置差异、组件数量差异等等。值得一提的是,KubeVela 支持 Kustomize 风格的 Patch 来定义这种差异,但又不需要用户学习任何 Kustomize 相关的知识。在多集群交付策略的基础上,用户还可以通过定义 Workflow 来控制交付到不同集群的顺序、条件等工作流步骤。

进一步尝试多集群应用交付,请参考 最佳实践文档

后续版本中,KubeVela 在多集群交付方面会提供全局流量分发、多集群自动调度策略、多集群灰度发布等更多高级特性特性。

定义交付工作流(Workflow)#

Workflow 的背景前面已经提到过,而它的具体使用场景则很多,比如:在多环境应用交付场景中,用户可以定义不同的环境交付的顺序和前置条件;再例如最简单的需求,部署完成后需要通知开发者;再例如我们需要控制灰度发布的进程,流量切换的比例,再例如我们需要应用部署完成后执行E2E测试等。KubeVela 的工作流是面向持续交付(CD)过程的,同时也是声明式的,所以它既可以作为 CD 系统直接同 CI 系统(比如 Jenkins 等)对接,也可以嵌入到现有 CI/CD 体系中作为增强和补充,落地方式非常灵活。

在模型上,Workflow 是由一系列 Step 组成的,而在实现上,每一个 Step 则是一个独立的能力模块,由其具体的类型和参数来决定其具体步骤的能力。在1.1 版本中,KubeVela 内置的 Step 已经比较丰富,欢迎大家试用、反馈。并且,Step 非常容易扩展,也能够让大家去对接已有的平台能力,做到无缝迁移。

通过 Service Mesh 来实现灰度发布等高级运维动作#

通过统一的应用模型集成各种不同的底层能力,依然是 KubeVela 最大的亮点之一。具体来说,KubeVela 通过 OAM 模型可以使得用户不需要任何“脏乱差”的胶水代码或者脚本就可以同任何云原生技术或工具(比如 Service Mesh)实现集成,从而为交付过程带来更多的云原生应用运维能力。在 1.1 版本中,KubeVela 已经内置了与 Istio 集成的案例。系统管理员可以通过 KubeVela 的插件管理机制便捷的启用 Istio 插件 。KubeVela 则负责将 Istio 的能力进行封装和抽象后交付给用户使用,使得用户无需成为 Istio 专家就可以直接使用这个金丝雀发布的场景(KubeVela 会为用户提供一个封装好的 Rollout 运维特征)。这种体验开发者来说是相当友好的,他既无需花费大量的时间去学习和掌握Istio的使用和配置,也无需关注 Istio 体系和各种云上托管版 Service Mesh 的差异,彻底解耦厂商锁定。

应用渐进式发布Demo(结合Workflow)

你可以参考 Rollout Demo实现图示效果,或参考最佳实践 基于 Istio 的渐进式发布,体验完整的微服务渐进式发布和回滚。

以应用为中心的云资源交付#

云厂商资源已经成为大多数应用开发者生产业务会采用的计算资源,它包括了基础设施、SaaS服务、中间件服务、托管服务等。对此,KubeVela 的设计是从“以应用为中心”的视角出发,帮助开发者以完全 Serverless 的方式更好、更方便的管理云资源,而不是疲于应付各种不同的云产品和控制台。在实现上,KubeVela 内置集成了 Terraform 来作为云资源的编排工具,并且能够以统一的应用模型支持各个云厂商上百种不同类型云服务的部署、绑定和管理。

在使用上,我们目前将云资源分为以下三类:

  • 作为组件:比如数据库、中间件、SaaS服务等。比如 KubeVela 中的 Alibaba-RDS服务就属于这种。
  • 作为运维特征:比如日志分析、监控可视化、监控报警等服务。
  • 作为应用运行基础设施:比如 Kubernetes 托管集群、SLB 负载均衡、NAS文件存储服务等。

在后续的版本,KubeVela 会进一步增加更加丰富的云服务使用场景,对各个云厂商分散的资源和计算能力进行有效整合,降低开发者的使用门槛和服务触达路径,实现资源的复用和有效、安全的回收机制,降低用户费用。KubeVela 的 Terraform 云服务管理是目前社区中非常火热的一个组件,有大量来自北美、欧洲的贡献者参与其中,非常欢迎大家试用、贡献和提出需求。

更容易落地的 GitOps 持续交付实践#

KubeVela 作为一个声明式的应用交付控制平面,天然就可以以 GitOps 的方式进行使用(可单独使用,也可配合 ArgoCD 等工具),并且能够为 GitOps 场景提供更多端到端的能力和增强、帮助 GitOps 理念以更加亲民和解决实际问题的方式在企业中落地。这些能力包括:

  • 定义应用交付工作流(CD 流水线)
    • 即:KubeVela 支持在 GitOps 模式中描述过程式的应用交付流程,而不只是简单的声明终态;
  • 处理部署过程中的各种依赖关系和拓扑结构;
  • 在现有各种 GitOps 工具的语义之上提供统一的上层抽象,简化应用交付与管理过程;
  • 统一进行云服务的声明、部署和服务绑定;
  • 提供开箱即用的交付策略(金丝雀、蓝绿发布等);
  • 提供开箱即用的混合环境/多集群部署策略(放置规则、集群过滤规则、跨环境 Promotion 等);
  • 在多环境交付中提供 Kustomize 风格的 Patch 来描述部署差异,而用户无需学习任何 Kustomize 本身的细节;
  • …… 等等。

使用 KubeVela 践行 GitOps 理念,请参考 GitOps 最佳实践

KubeVela 社区与生态#

KubeVela 是一个从第一天就诞生在云原生社区的开源项目。截止目前,KubeVela 现已被 Salesforce、字节跳动、腾讯、网易游戏等 35+ 家不同行业的领先企业应用在实际生产环境,帮助他们在不同场景下实现更高效的云原生应用的交付和管理。而 KubeVela 在社区用户中的大规模实践,也正在促进 OAM 成为混合云/多云/分布式云领域应用交付的事实标准,并在微软、Oracle Cloud 等多家国际厂商中被采用。近日,以 OAM 模型为核心的《云计算开放应用架构》标准文件也已经由阿里云计算有限公司、中国信息通信研究院等 10 余家单位联合发起并在“云原生产业大会”现场发布。

在未来,在云原生社区和 CNCF 应用交付领域工作组(TAG App Delivery)的共同推动下,KubeVela 将继续在交付定义标准化、运维能力多样化、管理体系生态化三个方面发展,真正实现让混合环境下的应用交付就像我们今天使用 App Store 一样简单。 我们看到开源社区正在围绕 KubeVela 的交付模型提出更多标准化组件、运维特征、插件、交付 Step 等能力,也非常欢迎新老社区用户前往:https://github.com/kubevela/kubevela/issues/1662 进行登记、让社区听到每一位参与者的声音。

后续版本规划#

打造天然面向混合环境的企业应用操作系统、让开发者享受交付应用的过程,这是 Kubevela 项目的目标和愿景:

  • 1.0 版本,KubeVela 实现了基础的应用交付核心模型,解决了”交付一切“的关键能力问题,打造了可编程的应用交付和管理引擎。
  • 1.1 版本,KubeVela 进一步完善了面向多环境应用交付的能力集和工作流,并且让用户可以通过命令行进行完整体验,并且上线了完整的中文文档。

而在接下来的 1.2 版本,KubeVela 将带来以应用为中心的控制面板UI,实现便捷的企业应用组装、分发、交付流程,提供给开发者更简单的应用交付体验,同时覆盖边缘应用交付等更多的使用场景。

what-is

更多项目 Roadmap 信息,详见 Kubevela RoadMap

参考信息#

立即安装使用,请参考:安装指南

你可以通过如下材料了解更多关于 KubeVela 以及 OAM 项目的细节:

  • 项目代码库:https://github.com/kubevela/kubevela 欢迎 Star/Watch/Fork!
  • 项目官方主页与文档:https://kubevela.io ,从1.1版本开始,已提供中文、英文文档,更多语言文档欢迎开发者进行翻译。
  • 项目钉钉群:23310022;Slack:CNCF #kubevela Channel
  • 加入微信群:请先添加以下 maintainer 微信号,表明进入KubeVela用户群:

使用 Jenkins + KubeVela 完成应用的持续交付

Da Yin, Yang Song

Da Yin, Yang Song

KubeVela 团队

KubeVela 打通了应用与基础设施之间的交付管控的壁垒,相较于原生的 Kubernetes 对象,KubeVela 的 Application 更好地简化抽象了开发者需要关心的配置,将复杂的基础设施能力及编排细节留给了平台工程师。而 KubeVela 的 apiserver 则是进一步为开发者提供了使用 HTTP Request 直接操纵 Application 的途径,使得开发者即使没有 Kubernetes 的使用经验与集群访问权限也可以轻松部署自己的应用。

本文就以经典的持续集成 (Continuous Integration) 工具 Jenkins 为基础,简单介绍如何打造基于 GitOps 的应用持续交付的“高速公路”。

持续交付“高速公路”#

作为应用开发者的你,更多地关心自己的应用是否正常运作,开发流程是否便捷高效。为此,在这条持续交付的“高速公路”上,将会由以下部件为你保驾护航。

  1. 你需要一个 git 仓库来存放应用程序代码、测试代码,以及描述 KubeVela Application 的 YAML 文件。
  2. 你需要一个持续集成 (Continuous Integration) 的工具帮你自动化完成程序代码的测试,并打包成镜像上传到仓库中。
  3. 你需要在 Kubernetes 集群上安装 KubeVela 并启用 apiserver 功能。

目前 KubeVela 的 apiserver 在权限认证方面仍待完善,后续启用 apiserver 后将会加入权限配置环节。

本文的介绍中采用了 Github 作为 git 仓库,Jenkins 作为 CI 工具,DockerHub 作为镜像仓库。应用程序以一个简单的 HTTP Server 为例,整个持续交付的流程如下。可以看到,在这条持续交付的“高速公路”上,开发者只需要关心应用的开发并使用 Git 进行代码版本的维护,即可自动走完测试流程并部署应用到 Kubernetes 集群中。

arch

部署环境#

Jenkins 环境#

本文采用了 Jenkins 作为持续集成工具,开发者也可以使用其他 CI 工具,如 TravisCI 或者 GitHub Action。

首先你需要准备一份 Jenkins 环境来部署 CI 流水线。安装与初始化 Jenkins 流程可以参见官方文档

需要注意的是,由于本文的 CI 流水线是基于 Docker 及 GitHub 的,因此在安装 Jenkins 之后还需要安装相关插件 (Dashboard > Manage Jenkins > Manage Plugins) ,包括 Pipeline、HTTP Request Plugin、Docker Pipeline、Docker Plugin。

此外,还需要为 Jenkins 配置 Docker 的运行环境 (Dashboard > Manage Jenkins > Configure System > Docker Builder) ,如 Jenkins 所在环境已经安装了 Docker,可以将 Docker URL 配置为 unix:///var/run/docker.sock

由于在 CI 流水线运行过程中,还需要将容器镜像推至镜像仓库,为此需在 Jenkins 的 Credential 中将镜像仓库的账户配置好 (Dashboard > Manage Jenkins > Manage Credentials > Add Credentials) ,比如将 DockerHub 的用户名及密码存入。

jenkins-credential

GitHub 仓库环境#

本文的介绍采用了 Github 作为代码仓库,开发者还可以根据各自的需求与喜好,使用其他代码仓库,如 Gitlab。

为使持续集成工具 Jenkins 能够获取到 GitHub 中的更新,并将流水线的运行状态反馈回 GitHub,需要在 GitHub 中完成以下两步操作。

  1. 配置 Personal Access Token。注意将 repo:status 勾选,以获得向 GitHub 推送 Commit 状态的权限。

github-pat

然后在 Jenkins 的 Credential 中加入 Secret Text 类型的 Credential 并将上述的 GitHub 的 Personal Access Token 填入。

jenkins-secret-text

最后来到 Jenkins 的 Dashboard > Manage Jenkins > Configure System > GitHub 中点击 Add GitHub Server 并将刚才创建的 Credential 填入。完成后可以点击 Test connection 来验证配置是否正确。

jenkins-github

  1. 在 GitHub 的代码仓库的设定里添加 Webhook,将 Jenkins 的地址对应的 Webhook 地址填入,比如 http://my-jenkins.example.com/github-webhook/ 。这样,该代码仓库的所有 Push 事件推送到 Jenkins 中。

github-webhook

KubeVela 环境#

你需要在 Kubernetes 集群中安装 KubeVela,并启用 apiserver 功能,可以参考官方文档

编写应用#

本文采用的应用是一个基于 Golang 语言编写的简单的 HTTP Server。在代码中,声明了一个名叫 VERSION 的常量,并在访问该服务时打印出来。同时还附带一个简单的测试,用来校验 VERSION 的格式是否符合标准。

// main.go
package main
import (
"fmt"
"net/http"
)
const VERSION = "0.1.0-v1alpha1"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "Version: %s\n", VERSION)
})
if err := http.ListenAndServe(":8088", nil); err != nil {
println(err.Error())
}
}
// main_test.go
package main
import (
"regexp"
"testing"
)
const verRegex string = `^v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?$`
func TestVersion(t *testing.T) {
if ok, _ := regexp.MatchString(verRegex, VERSION); !ok {
t.Fatalf("invalid version: %s", VERSION)
}
}

在应用交付时需要将 Golang 服务打包成镜像并以 KubeVela Application 的形式发布到 Kubernetes 集群中,因此在代码仓库中还包含 Dockerfile 以及 app.yaml 文件,分别用来描述镜像的打包方式以及 Application 的相关配置。

# Dockerfile
FROM golang:1.13-rc-alpine3.10 as builder
WORKDIR /app
COPY main.go .
RUN go build -o kubevela-demo-cicd-app main.go
FROM alpine:3.10
WORKDIR /app
COPY --from=builder /app/kubevela-demo-cicd-app /app/kubevela-demo-cicd-app
ENTRYPOINT ./kubevela-demo-cicd-app
EXPOSE 8088

在 app.yaml 中,声明了部署的应用包含 5 个不同副本,同时通过 Ingress 的形式发布给集群外部。而 labels 则是给应用中的 Pod 打上了当前的 git commit 作为标签。当 Jenkins 的部署流水线运行时,会将 GIT_COMMIT 注入其中,提交到 KubeVela apiserver,从而触发 Application 的更新。在版本更新过程中,按照 2, 3 的数量分两次次更新副本,同时在第一次更新后停止自动更新,等待手动确认后再进行全部更新,实现金丝雀发布的过程。

# app.yaml
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: kubevela-demo-app
spec:
components:
- name: kubevela-demo-app-web
type: webservice
properties:
image: somefive/kubevela-demo-cicd-app
imagePullPolicy: Always
port: 8080
traits:
- type: rollout
properties:
rolloutBatches:
- replicas: 2
- replicas: 3
batchPartition: 0
targetSize: 5
- type: labels
properties:
jenkins-build-commit: GIT_COMMIT
- type: ingress
properties:
domain: kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com
http:
"/": 8088

配置 CI 流水线#

在本文的案例中,包含两条流水线,一条是用来进行测试的流水线 (对应用代码运行测试) ,一条是交付流水线 (将应用代码打包上传镜像仓库,同时更新目标环境中的应用,实现自动更新) 。

测试流水线#

在 Jenkins 中创建一条新的 Pipeline,并配置 Build Triggers 为 GitHub hook trigger for GITScm polling。

test-pipeline-create test-pipeline-config

在这条流水线中,首先是采用了 golang 的镜像作为执行环境,方便后续运行测试。然后将分支配置为 GitHub 仓库中的 dev 分支,代表该条流水线被 Push 事件触发后会拉取 dev 分支上的内容并执行测试。测试结束后将流水线的状态回写至 GitHub 中。

void setBuildStatus(String message, String state) {
step([
$class: "GitHubCommitStatusSetter",
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/Somefive/KubeVela-demo-CICD-app"],
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/test-status"],
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
]);
}
pipeline {
agent {
docker { image 'golang:1.13-rc-alpine3.10' }
}
stages {
stage('Prepare') {
steps {
script {
def checkout = git branch: 'dev', url: 'https://github.com/Somefive/KubeVela-demo-CICD-app.git'
env.GIT_COMMIT = checkout.GIT_COMMIT
env.GIT_BRANCH = checkout.GIT_BRANCH
echo "env.GIT_BRANCH=${env.GIT_BRANCH},env.GIT_COMMIT=${env.GIT_COMMIT}"
}
setBuildStatus("Test running", "PENDING");
}
}
stage('Test') {
steps {
sh 'CGO_ENABLED=0 GOCACHE=$(pwd)/.cache go test *.go'
}
}
}
post {
success {
setBuildStatus("Test success", "SUCCESS");
}
failure {
setBuildStatus("Test failed", "FAILURE");
}
}
}

部署流水线#

在部署流水线中,类似测试流水线,首先将代码仓库中的分支拉取下来,区别是这里采用 prod 分支。然后使用 Docker 进行镜像构建并推送至远端镜像仓库 (这里为 DockerHub,其中 withRegistry 中填写镜像仓库位置以及在先前步骤中存入的 DockerHub 的账户对应的 Credential 的 ID) 。构建成功后,再将 Application 对应的 YAML 文件转换为 JSON 文件并注入 GIT_COMMIT,最后向 KubeVela apiserver (此处为 http://47.88.24.19/) 发送请求进行创建或更新。

目前的 KubeVela apiserver 接收 JSON 参数,因此在流水线中做了相应的转换。未来的 KubeVela apiserver 将会进一步改进交互模式,简化此处的流程,同时再加上更为严格的权限认证,提高安全性。

该案例中会向 kubevela-demo-namespace 这个 Namespace 中创建名叫 cicd-demo-app 的应用,注意这个 Namespace 需要预先在 Kubernetes 中创建出来。未来 KubeVela 的 apiserver 同样会简化这一流程。

void setBuildStatus(String message, String state) {
step([
$class: "GitHubCommitStatusSetter",
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/Somefive/KubeVela-demo-CICD-app"],
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/deploy-status"],
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
]);
}
pipeline {
agent any
stages {
stage('Prepare') {
steps {
script {
def checkout = git branch: 'prod', url: 'https://github.com/Somefive/KubeVela-demo-CICD-app.git'
env.GIT_COMMIT = checkout.GIT_COMMIT
env.GIT_BRANCH = checkout.GIT_BRANCH
echo "env.GIT_BRANCH=${env.GIT_BRANCH},env.GIT_COMMIT=${env.GIT_COMMIT}"
setBuildStatus("Deploy running", "PENDING");
}
}
}
stage('Build') {
steps {
script {
docker.withRegistry("https://registry.hub.docker.com", "DockerHubCredential") {
def customImage = docker.build("somefive/kubevela-demo-cicd-app")
customImage.push()
}
}
}
}
stage('Deploy') {
steps {
sh 'wget -q "https://github.com/mikefarah/yq/releases/download/v4.12.1/yq_linux_amd64"'
sh 'chmod +x yq_linux_amd64'
script {
def app = sh (
script: "./yq_linux_amd64 eval -o=json '.spec' app.yaml | sed -e 's/GIT_COMMIT/$GIT_COMMIT/g'",
returnStdout: true
)
echo "app: ${app}"
def response = httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', httpMode: 'POST', requestBody: app, url: "http://47.88.24.19/v1/namespaces/kubevela-demo-namespace/applications/cicd-demo-app"
println('Status: '+response.status)
println('Response: '+response.content)
}
}
}
}
post {
success {
setBuildStatus("Deploy success", "SUCCESS");
}
failure {
setBuildStatus("Deploy failed", "FAILURE");
}
}
}

备注:上述的 Deploy 阶段是基于 KubeVela 1.1 版本的。在 KubeVela 1.2 版本中,Jenkins 对接 KubeVela APIServer 的方法发生了变化,需要使用 VelaUX(UI 控制面板)和 WebHook 触发器。如果你使用的是 KubeVela v1.2.0+,你需要参考对应版本的相关文档。

实际表现#

在完成上述的配置流程后,持续交付的流程便已经搭建完成。我们可以来检验一下它的效果。

pipeline-overview

我们首先将 main.go 中的 VERSION 字段修改为 Bad Version Number,即

const VERSION = "Bad Version Number"

然后提交该修改至 dev 分支。我们可以看到 Jenkins 上的测试流水线被触发运行,失败后将该状态回写给 GitHub。

test-pipeline-fail test-github-fail

我们重新将 VERSION 修改为 0.1.1,然后再次提交。可以看到这一次测试流水线成功完成执行,并在 GitHub 对应的 Commit 上看到了成功的标志。

test-pipeline-success test-github-success

接下来我们在 GitHub 上提交 Pull Request 尝试将 dev 分支上的更新合并至 prod 分支上。

pull-request

可以看到在 Jenkins 的部署流水线成功运行结束后,GitHub 上 prod 分支最新的 Commit 也显示了成功的标志。

deploy-pipeline-success deploy-github-success

$ kubectl get app -n kubevela-demo-namespace
NAME COMPONENT TYPE PHASE HEALTHY STATUS AGE
kubevela-demo-cicd-app kubevela-demo-app-web webservice running true 112s
$ kubectl get deployment -n kubevela-demo-namespace
NAME READY UP-TO-DATE AVAILABLE AGE
kubevela-demo-app-web-v1 2/2 2 2 2m1s

如图显示,要部署的应用顺利被 KubeVela apiserver 接受并由 KubeVela 控制器创建了相关资源。当前 Deployment 的副本数是 2,在删除了该 Application 中 rollout 特征内的 batchPartition: 0 后代表确认了当前的发布,然后对应的 Deployment 副本数更新至 5。这时我们可以访问 Ingress 所配置的域名,成功显示了当前的版本号。

$ kubectl edit app -n kubevela-demo-namespace
application.core.oam.dev/kubevela-demo-cicd-app edited
$ kubectl get deployment -n kubevela-demo-namespace -w
NAME READY UP-TO-DATE AVAILABLE AGE
kubevela-demo-app-web-v1 4/5 5 4 3m39s
kubevela-demo-app-web-v1 5/5 5 5 3m39s
kubevela-demo-app-web-v1 5/5 5 5 3m40s
kubevela-demo-app-web-v1 5/5 5 5 3m40s
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.1

我们重复以上步骤,将版本升级至 0.1.2,完成测试流水线及部署流水线。接着我们会发现 Kubernetes 的集群内对应的 Application 控制的 Deployment 发生了版本更替,旧版本的 Deployment 从 5 副本下降到 3 副本,新版本的 Deployment 则出现了 2 副本。如果此时我们再访问原来的服务地址,会发现有时会显示 0.1.1 版本,有时会显示 0.1.2 版本。这是因为在当前滚动更新过程中,新旧副本同时存在,访问的流量会被负载均衡器分发到不同的副本上,因此会出现两种版本的服务同时存在的现象。

$ kubectl get deployment -n kubevela-demo-namespace -w
NAME READY UP-TO-DATE AVAILABLE AGE
kubevela-demo-app-web-v1 5/5 5 5 11m
kubevela-demo-app-web-v2 0/0 0 0 0s
kubevela-demo-app-web-v2 0/0 0 0 0s
kubevela-demo-app-web-v2 0/0 0 0 0s
kubevela-demo-app-web-v1 5/5 5 5 12m
kubevela-demo-app-web-v2 0/0 0 0 0s
kubevela-demo-app-web-v2 0/0 0 0 0s
kubevela-demo-app-web-v2 0/0 0 0 0s
kubevela-demo-app-web-v2 0/0 0 0 0s
kubevela-demo-app-web-v2 0/2 0 0 0s
kubevela-demo-app-web-v2 0/2 0 0 0s
kubevela-demo-app-web-v2 0/2 0 0 0s
kubevela-demo-app-web-v2 0/2 2 0 0s
kubevela-demo-app-web-v1 5/5 5 5 12m
kubevela-demo-app-web-v2 1/2 2 1 2s
kubevela-demo-app-web-v2 2/2 2 2 2s
kubevela-demo-app-web-v1 5/3 5 5 13m
kubevela-demo-app-web-v1 5/3 5 5 13m
kubevela-demo-app-web-v1 3/3 3 3 13m
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.1
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.1
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.1
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.1
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.2
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.2
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.2
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.2
$ curl http://kubevela-demo-cicd-app.cf7c0ed25b151437ebe1ef58efc29bca4.us-west-1.alicontainer.com/
Version: 0.1.1

当我们确认新版本的服务正常运作后,可以类似上述步骤,将 Application 中 rollout 特性内的 batchPartition: 0 删去,完成整个金丝雀发布流程。

$ kubectl get deployment -n kubevela-demo-namespace -w
NAME READY UP-TO-DATE AVAILABLE AGE
kubevela-demo-app-web-v1 3/3 3 3 18m
kubevela-demo-app-web-v2 2/2 2 2 5m24s
kubevela-demo-app-web-v2 2/5 2 2 5m36s
kubevela-demo-app-web-v2 2/5 2 2 5m37s
kubevela-demo-app-web-v2 2/5 2 2 5m37s
kubevela-demo-app-web-v2 2/5 5 2 5m37s
kubevela-demo-app-web-v2 3/5 5 3 5m38s
kubevela-demo-app-web-v2 4/5 5 4 5m38s
kubevela-demo-app-web-v2 5/5 5 5 5m39s
kubevela-demo-app-web-v1 3/0 3 3 18m
kubevela-demo-app-web-v1 3/0 3 3 18m
kubevela-demo-app-web-v1 0/0 0 0 18m
kubevela-demo-app-web-v1 0/0 0 0 18m
kubevela-demo-app-web-v2 5/5 5 5 5m41s
kubevela-demo-app-web-v2 5/5 5 5 5m41s
kubevela-demo-app-web-v1 0/0 0 0 18m

小结#

至此,我们便已经成功实现了一整套持续交付流程。在这个流程中,应用的开发者借助 KubeVela + Jenkins 的能力,可以轻松完成应用的迭代更新、集成测试、自动发布与滚动升级,而整个流程在各个环节也可以按照开发者的喜好和条件选择不同的工具,比如使用 Gitlab 替代 GitHub,或是使用 TravisCI 替代 Jenkins。

在上述过程中,细心的读者可能还会发现,这套流程不仅能够实现应用服务的升级,而且还可以通过修改 app.yaml 自动完成部署方案的升级,比如将 5 副本应用扩容到 10 副本,或是为容器添加 sidecar,从而实现部分 GitOps 能力。关于使用 KubeVela 实践 GitOps 的更多内容,感兴趣的读者可以继续阅读相关案例。