源码解读:KubeVela 是如何将 appfile 转换为 K8s 特定资源对象的

简介: KubeVela 是一个简单易用又高度可扩展的云原生应用管理引擎,是基于 Kubernetes 及阿里云与微软云共同发布的云原生应用开发模型 OAM 构建。本文主要目的是探索 KubeVela 如何将一个 appfile 文件转换为 K8s 中特定的资源对象。

1.png

作者 | 樊大勇

KubeVela 是一个简单易用又高度可扩展的云原生应用管理引擎,是基于 Kubernetes 及阿里云与微软云共同发布的云原生应用开发模型 OAM 构建。

KubeVela 基于 OAM 模型构建了一套具体的实现,通过 Golang 编写,可以端到端地为用户构建云原生应用的平台,提供一个相对完整的解决方案。

KubeVela 项目自 2020 年 7 月份在社区里面发起,受到包括阿里、微软、Crossplane 等公司工程师在内的广大社区志愿者的欢迎,并一起投入到项目开发工作中。他们把在 OAM 实践里面的各种经验与教训,都总结沉淀到 KubeVela 项目中。

本文主要目的是探索 KubeVela 如何将一个 appfile 文件转换为 K8s 中特定的资源对象。

该过程总的来说分为两个阶段:

  1. appfile 转为 K8s 中的 application
  2. application 转换为对应的 K8s 资源对象
# vela.yaml
name: test
services:nginx:type: webserviceimage: nginxenv:- name: NAMEvalue: kubevela# svc traitsvc:type: NodePortports:- port: 80nodePort: 32017

利用 vela up 命令可以完成部署。

vela up 命令

建议:在看 vela 命令行工具代码之前,先去简单了解一下 cobra 框架。

// references/cli/up.go
// NewUpCommand will create command for applying an AppFile
func NewUpCommand(c types.Args, ioStream cmdutil.IOStreams) *cobra.Command {cmd := &cobra.Command{Use:                   "up",DisableFlagsInUseLine: true,Short:                 "Apply an appfile",Long:                  "Apply an appfile",Annotations: map[string]string{types.TagCommandType: types.TypeStart,},PersistentPreRunE: func(cmd *cobra.Command, args []string) error {return c.SetConfig()},RunE: func(cmd *cobra.Command, args []string) error {velaEnv, err := GetEnv(cmd)if err != nil {return err}kubecli, err := c.GetClient()if err != nil {return err}o := &common.AppfileOptions{Kubecli: kubecli,IO:      ioStream,Env:     velaEnv,}filePath, err := cmd.Flags().GetString(appFilePath)if err != nil {return err}return o.Run(filePath, velaEnv.Namespace, c)},}cmd.SetOut(ioStream.Out)cmd.Flags().StringP(appFilePath, "f", "", "specify file path for appfile")return cmd
}

上面源码展示的是 vela up 命令的入口。

在 PresistentPreRunE 函数中,通过调用 c.SetConfig() 完成 Kuberentes 配置信息 kubeconfig 的注入。

在 RunE 函数中:

  • 首先,获取 vela 的 env 变量,velaEnv.Namespace 对应 Kubernetes 的命名空间。
  • 其次,获取 Kubernetes 的客户端,kubectl。
  • 接着,利用 Kubernetes 客户端和 vleaEnv 来构建渲染 Appfile 需要的 AppfileOptions。
  • 最后,调用 o.Run(filePath, velaEnv.Namespace, c)。

    • 该函数需要三个参数,其中 filePath 用于指定 appfile 的位置,velaEnv.Namespace 和 c 用来将渲染后的 Application 创建到指定命名空间。

      • filePath: appfile 的路径
      • velaEnv.Namespace:对应 K8s 的 namespace
      • c:K8s 客户端

如何将一个 appfile 转为 Kubernetes 中的 Application

  • 起点:appfile
  • 终点:applicatioin
  • 路径:appfile -> application (services -> component)

    • comp[workload, traits]

1. 起点:AppFile

// references/appfile/api/appfile.go
// AppFile defines the spec of KubeVela Appfile
type AppFile struct {Name       string             `json:"name"`CreateTime time.Time          `json:"createTime,omitempty"`UpdateTime time.Time          `json:"updateTime,omitempty"`Services   map[string]Service `json:"services"`Secrets    map[string]string  `json:"secrets,omitempty"`configGetter config.Storeinitialized  bool
}// NewAppFile init an empty AppFile struct
func NewAppFile() *AppFile {return &AppFile{Services:     make(map[string]Service),Secrets:      make(map[string]string),configGetter: &config.Local{},}
}
// references/appfile/api/service.go
// Service defines the service spec for AppFile, it will contain all related information including OAM component, traits, source to image, etc...
type Service map[string]interface{}

上面两段代码是 AppFile 在客户端的声明,vela 会将指定路径的 yaml 文件读取后,赋值给一个 AppFile。

// references/appfile/api/appfile.go
// LoadFromFile will read the file and load the AppFile struct
func LoadFromFile(filename string) (*AppFile, error) {b, err := ioutil.ReadFile(filepath.Clean(filename))if err != nil {return nil, err}af := NewAppFile()// Add JSON format appfile supportext := filepath.Ext(filename)switch ext {case ".yaml", ".yml":err = yaml.Unmarshal(b, af)case ".json":af, err = JSONToYaml(b, af)default:if json.Valid(b) {af, err = JSONToYaml(b, af)} else {err = yaml.Unmarshal(b, af)}}if err != nil {return nil, err}return af, nil
}

下面为读取 vela.yaml 文件后,加载到 AppFile 中的数据:

# vela.yaml
name: test
services:nginx:type: webserviceimage: nginxenv:- name: NAMEvalue: kubevela# svc traitsvc:type: NodePortports:- port: 80nodePort: 32017
Name: test
CreateTime: 0001-01-01 00:00:00 +0000 UTC
UpdateTime: 0001-01-01 00:00:00 +0000 UTC
Services: map[nginx: map[env: [map[name: NAME value: kubevela]] image: nginx svc: map[ports: [map[nodePort: 32017 port: 80]] type: NodePort] type: webservice]]
Secrets    map[]
configGetter: 0x447abd0 
initialized: false

2. 终点:application

// apis/core.oam.dev/application_types.go
type Application struct {metav1.TypeMeta   `json:",inline"`metav1.ObjectMeta `json:"metadata,omitempty"`Spec   ApplicationSpec `json:"spec,omitempty"`Status AppStatus       `json:"status,omitempty"`
}// ApplicationSpec is the spec of Application
type ApplicationSpec struct {Components []ApplicationComponent `json:"components"`// TODO(wonderflow): we should have application level scopes supported here// RolloutPlan is the details on how to rollout the resources// The controller simply replace the old resources with the new one if there is no rollout plan involved// +optionalRolloutPlan *v1alpha1.RolloutPlan `json:"rolloutPlan,omitempty"`
}

上面代码,为 Application 的声明,结合 .vela/deploy.yaml(见下面代码),可以看出,要将一个 AppFile 渲染为 Application 主要就是将 AppFile 的 Services 转化为 Application 的 Components。

# .vela/deploy.yaml
apiVersion: core.oam.dev/v1alpha2
kind: Application
metadata:creationTimestamp: nullname: testnamespace: default
spec:components:- name: nginxscopes:healthscopes.core.oam.dev: test-default-healthsettings:env:- name: NAMEvalue: kubevelaimage: nginxtraits:- name: svcproperties:ports:- nodePort: 32017port: 80type: NodePorttype: webservice
status: {}

3. 路径:Services -> Components

结合以上内容可以看出,将 Appfile 转化为 Application 主要是将 Services 渲染为 Components。

// references/appfile/api/appfile.go
// BuildOAMApplication renders Appfile into Application, Scopes and other K8s Resources.
func (app *AppFile) BuildOAMApplication(env *types.EnvMeta, io cmdutil.IOStreams, tm template.Manager, silence bool) (*v1alpha2.Application, []oam.Object, error) {...servApp := new(v1alpha2.Application)servApp.SetNamespace(env.Namespace)servApp.SetName(app.Name)servApp.Spec.Components = []v1alpha2.ApplicationComponent{}for serviceName, svc := range app.GetServices() {...// 完成 Service 到 Component 的转化comp, err := svc.RenderServiceToApplicationComponent(tm, serviceName)if err != nil {return nil, nil, err}servApp.Spec.Components = append(servApp.Spec.Components, comp)}servApp.SetGroupVersionKind(v1alpha2.SchemeGroupVersion.WithKind("Application"))auxiliaryObjects = append(auxiliaryObjects, addDefaultHealthScopeToApplication(servApp))return servApp, auxiliaryObjects, nil
}

上面的代码是 vela 将 Appfile 转化为 Application 代码实现的位置。其中 comp, err := svc.RenderServiceToApplicationComponent(tm, serviceName) 完成 Service 到 Component 的转化。

// references/appfile/api/service.go
// RenderServiceToApplicationComponent render all capabilities of a service to CUE values to KubeVela Application.
func (s Service) RenderServiceToApplicationComponent(tm template.Manager, serviceName string) (v1alpha2.ApplicationComponent, error) {// sort out configs by workload/traitworkloadKeys := map[string]interface{}{}var traits []v1alpha2.ApplicationTraitwtype := s.GetType()comp := v1alpha2.ApplicationComponent{Name:         serviceName,WorkloadType: wtype,}for k, v := range s.GetApplicationConfig() {// 判断是否为 traitif tm.IsTrait(k) {trait := v1alpha2.ApplicationTrait{Name: k,}....// 如果是 triat 加入 traits 中traits = append(traits, trait)continue}workloadKeys[k] = v}// Handle workloadKeys to settingssettings := &runtime.RawExte nsion{}pt, err := json.Marshal(workloadKeys)if err != nil {return comp, err}if err := settings.UnmarshalJSON(pt); err != nil {return comp, err}comp.Settings = *settingsif len(traits) > 0 {comp.Traits = traits}return comp, nil
}

4. 总结

执行 vela up 命令,渲染 appfile 为 Application,将数据写入到 .vela/deploy.yaml 中,并在 K8s 中创建。

2.png

Application 是如何转换为对应 K8s 资源对象

  • 起点:Application
  • 中点:ApplicationConfiguration, Component
  • 终点:Deployment, Service
  • 路径:

    • application_controller
    • applicationconfiguration controller

【建议】> 了解一下内容:> - client-to

  • controller-runtime
  • operator

1. Application

# 获取集群中的 Application
$ kubectl get application
NAMESPACE   NAME   AGE
default     test   24h

2. ApplicationConfiguration 和 Component

当 application controller 获取到 Application 资源对象之后,会根据其内容创建出对应的 ApplicationConfiguration 和 Component。

# 获取 ApplicationConfiguration 和 Component
$ kubectl get ApplicationConfiguration,Component
NAME                                         AGE
applicationconfiguration.core.oam.dev/test   24hNAME                           WORKLOAD-KIND   AGE
component.core.oam.dev/nginx   Deployment      24h

ApplicationiConfiguration 中以名字的方式引入 Component:

3.png

3. application controller

基本逻辑:

  • 获取一个 Application 资源对象。
  • 将 Application 资源对象渲染为 ApplicationConfiguration 和 Component。
  • 创建 ApplicationConfiguration 和 Component 资源对象。

代码:

// pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go// Reconcile process app event
func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {ctx := context.Background()applog := r.Log.WithValues("application", req.NamespacedName)// 1. 获取 Applicationapp := new(v1alpha2.Application)if err := r.Get(ctx, client.ObjectKey{Name:      req.Name,Namespace: req.Namespace,}, app); err != nil {...}...// 2. 将 Application 转换为 ApplicationConfiguration 和 Componenthandler := &appHandler{r, app, applog}...appParser := appfile.NewApplicationParser(r.Client, r.dm)...appfile, err := appParser.GenerateAppFile(ctx, app.Name, app)...ac, comps, err := appParser.GenerateApplicationConfiguration(appfile, app.Namespace)...// 3. 在集群中创建 ApplicationConfiguration 和 Component // apply appConfig & component to the clusterif err := handler.apply(ctx, ac, comps); err != nil {applog.Error(err, "[Handle apply]")app.Status.SetConditions(errorCondition("Applied", err))return handler.handleErr(err)}...return ctrl.Result{}, r.UpdateStatus(ctx, app)
}

4. applicationconfiguration controller

基本逻辑:

  • 获取 ApplicationConfiguration 资源对象。
  • 循环遍历,获取每一个 Component 并将 workload 和 trait 渲染为对应的 K8s 资源对象。
  • 创建对应的 K8s 资源对象。

代码:

// pkg/controller/core.oam.dev/v1alpha2/applicationcinfiguratioin/applicationconfiguratioin.go// Reconcile an OAM ApplicationConfigurations by rendering and instantiating its
// Components and Traits.
func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {...ac := &v1alpha2.ApplicationConfiguration{}// 1. 获取 ApplicationConfigurationif err := r.client.Get(ctx, req.NamespacedName, ac); err != nil {...}return r.ACReconcile(ctx, ac, log)
}// ACReconcile contains all the reconcile logic of an AC, it can be used by other controller
func (r *OAMApplicationReconciler) ACReconcile(ctx context.Context, ac *v1alpha2.ApplicationConfiguration,log logging.Logger) (result reconcile.Result, returnErr error) {...// 2. 渲染// 此处 workloads 包含所有Component对应的的 workload 和 tratis 的 k8s 资源对象workloads, depStatus, err := r.components.Render(ctx, ac)...applyOpts := []apply.ApplyOption{apply.MustBeControllableBy(ac.GetUID()), applyOnceOnly(ac, r.applyOnceOnlyMode, log)}// 3. 创建 workload 和 traits 对应的 k8s 资源对象if err := r.workloads.Apply(ctx, ac.Status.Workloads, workloads, applyOpts...); err != nil {...}...// the defer function will do the final status updatereturn reconcile.Result{RequeueAfter: waitTime}, nil
}

5. 总结

当 vela up 将一个 AppFile 渲染为一个 Application 后,后续的流程由 application controller 和 applicationconfiguration controller 完成。

4.png

作者简介

樊大勇,华胜天成研发工程师,GitHub ID:@just-do1。

原文链接

本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/513934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle默认导出路径linux,传统路径导出 VS 直接路径导出(oracle exp direct=y)

Oracle 传统的Export与Import依旧被保留到11g,而且9i与10g有很多依旧使用Export与Import方式进行备份与恢复的企业。从Oracle 7.3开始,传统的exp导出程序提供两种的导出路径方式,一个是传统路径导出(Conventional Path Export),一…

web 前端 如何分享到instagram_好程序员web前端教程分享前端javascript练习题三

好程序员web前端教程分享前端javascript练习题三cookie一周内免登录样式代码:姓名:密码:一周内免登陆js功能代码:var inputdocument.getElementsByTagName("input");if(getCookie("usename")){ //判端cookie是…

一文详解SQL关联子查询

简介: 本文主要介绍什么是关联子查询以及如何将关联子查询改写为普通语义的sql查询。 本文主要介绍什么是关联子查询以及如何将关联子查询改写为普通语义的sql查询。 在背景介绍中我们将讲讲常见的关联子查询的语义,关联子查询语法的好处以及其执行时对…

阿里巴巴研究员叔同:云原生是企业数字创新的最短路径

作者:叔同 今天,数字化成为企业的核心竞争力,千行百业都在拥抱云计算,拥抱云原生。2020年我们认为是云原生的落地元年,那么2021年将是云原生加速推动企业数字创新的关键节点。在3月29日阿里云计算峰会上,阿…

Kubernetes 微服务监控体系

作者|无敌码农来源|无敌码农监控系统是运维体系乃至整个软件产品生命周期中最重要的一环,完善的监控可以帮助我们事前及时发现故障,事后快速追查定位问题。而在以微服务为代表的云原生架构体系中,系统分为多个层次,服务之间调用链…

python解zuobiaoxi方程_滑坡稳定性分析程序初探---Python版!

0 前言 山体滑坡是常见的自然灾害,从理论分析的角度讲,滑坡的稳定性分析方法源自于高中物理学,如图1所示。前者的滑动分析非常简单,在已知滑块的重量以及接触面摩擦系数的基础上通过计算下滑力和抗滑力的关系即可分析其稳定性&…

php 动态 控件,PHP技术在动态网页表单控件提取中的应用研究

曲小纳摘要:由于电子商务及网络信息技术的飞速发展,动态网站已经逐渐取代传统的静态网站,在不断向人工智能化等方向发展。该篇文章就针对PHP这种技术在动态网页表单控件提取中的应用进行详细的阐述。关键词:PHP;动态网页;表单中图…

冷启动延时缩短50%-80%,阿里云函数计算发布冷启动加速技术

简介: 近日,阿里云函数计算重磅发布冷启动加速技术,将原本属于开发者的镜像优化负担转由函数计算承担,进一步帮助开发者提高生产效率,专注业务创新。该技术源于阿里集团超大规模和场景高度复杂的容器环境,对…

评审恩仇录——IDE也能做代码评审?

简介: 云效Codeup推出了本地IDE插件端的评审,免除了黄药师来回华山的奔波之苦 现代科技公司的同事们平日一起交流开发规约和产品需求,肩上共同扛着业务发展和同行竞争的压力,这份还书贻剑的情谊如何能引来恩仇呢?通过…

云原生数据仓库TPC-H第一背后的Laser引擎大揭秘

简介: 作者| 魏闯先阿里云数据库资深技术专家 一、ADB PG 和Laser 计算引擎的介绍 (一)ADB PG 架构 ADB PG 是一款云原生数据仓库,在保证事务ACID 能力的前提下,主要解决云上海 量数据的实时分析问题。它的架构与传…

新云网、5G、Wi-Fi 6 Plus,探秘2021通信展上的锐捷网络黑科技

供稿 | 锐捷网络 出品 | CSDN云计算 2021年9月27日,主题为“创新点亮数字化未来”的第三十届中国国际信息通信展览会(PT EXPO 2021)在北京如期开幕。展会汇聚业内的科技创新技术专家和优秀企业,共同探讨数字化创新的新趋势、新场…

【OpenYurt 深度解析】边缘网关缓存能力的优雅实现

简介: 阿里云边缘容器服务上线 1 年后,正式开源了云原生边缘计算解决方案 OpenYurt,跟其他开源的容器化边缘计算方案不同的地方在于:OpenYurt 秉持 Extending your native Kubernetes to edge 的理念,对 Kubernetes 系…

python的类名一定要大写吗_python 类名

广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 如果我从中执行此操作的函数是实例的类派生的基类,我如何找到在python中创建对象实例的类的名称…

Elasticsearch生态技术峰会 | 阿里云Elasticsearch云原生内核

简介: 开源最大的特征就是开放性,云生态则让开源技术更具开放性与创造性,Elastic 与阿里云的合作正是开源与云生态共生共荣的典范。值此合作三周年之际,我们邀请业界资深人士相聚云端,共话云上Elasticsearch生态与技术…

剑指云原生数据库 2.0,阿里云发布全新一站式敏捷数据仓库解决方案

作为基础软件“三驾马车”之一的数据库,其发展历程可追溯到60年前:从上世纪50年代的层次数据库、网状数据库,70年代的关系型数据库,再到90年代的关系型数据库、数据仓库、PC单机数据库和 2000 年的开源数据库,Oracle等…

深度 | 面向云原生数据湖的元数据管理技术解析

简介: 作者:沐远、明惠 背景 数据湖当前在国内外是比较热的方案,MarketsandMarkets市场调研显示预计数据湖市场规模在2024年会从2019年的79亿美金增长到201亿美金。一些企业已经构建了自己的云原生数据湖方案,有效解决了业务痛点…

sql中“delete from 表名”表示_SQL查询语句知识点总结

为什么要学习SQL?数据分析岗位的基础技能:SQL语句和会使用SQL语句操纵数据库软件;数据量增大的工具需求:excel处理十万以内的数据;数据量增大,需要使用更快速便捷的工具分析数据。SQL知识点总结1数据库基础知识什么是…

Serverless 可观测性的过去、现在与未来

简介: 函数计算可观测性经历了 1.0 -> 2.0 的发展,从闭门造车的可观测发展成开源的可观测,从平台的可观测发展为开发者的可观测,从FaaS Only 的可观测演进成了云原生的可观测。 作者:夏莞 背景 Serverless 将成为…

Gartner:全行业投入人工智能,计算机视觉占比最高

编辑 | 宋慧 供稿 | Gartner Gartner最近一项新调研发现,三分之一拥有人工智能(AI)技术计划的技术和服务提供商企业机构表示,他们在未来两年对人工智能技术的投资将达到100万美元以上。绝大多数将人工智能技术作为主要投资领域的…

爱奇艺大数据生态的实时化建设

简介: 实时化是大数据未来最重要的方向之一。 作者|爱奇艺大数据团队 数据作为互联网时代的基础生产资料,在各大公司企业拥有举足轻重的地位。数据的价值在互联网公司的体现,大致而言可以分成三类: 发掘数据中的信息…