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

本文详细描述了如何使用vela工具将appfile转换为Kubernetes中的application,涉及appfile结构、Service到Component的映射,以及velaup命令在部署过程中的作用。重点介绍了Cobra框架和Kubernetes客户端的使用。
摘要由CSDN通过智能技术生成

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

  1. appfile 转为 K8s 中的 application

  2. application 转换为对应的 K8s 资源对象

vela.yaml

name: test

services:

nginx:

type: webservice

image: nginx

env:

  • name: NAME

value: kubevela

svc trait

svc:

type: NodePort

ports:

  • port: 80

nodePort: 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.Store

initialized 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 support

ext := 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: webservice

image: nginx

env:

  • name: NAME

value: kubevela

svc trait

svc:

type: NodePort

ports:

  • port: 80

nodePort: 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

// +optional

RolloutPlan *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: null

name: test

namespace: default

spec:

components:

  • name: nginx

scopes:

healthscopes.core.oam.dev: test-default-health

settings:

env:

  • name: NAME

value: kubevela

image: nginx

traits:

  • name: svc

properties:

ports:

  • nodePort: 32017

port: 80

type: NodePort

type: 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/trait

workloadKeys := map[string]interface{}{}

var traits []v1alpha2.ApplicationTrait

wtype := s.GetType()

comp := v1alpha2.ApplicationComponent{

Name: serviceName,

WorkloadType: wtype,

}

for k, v := range s.GetApplicationConfig() {

// 判断是否为 trait

if tm.IsTrait(k) {

trait := v1alpha2.ApplicationTrait{

Name: k,

}

// 如果是 triat 加入 traits 中

traits = append(traits, trait)

continue

}

workloadKeys[k] = v

}

// Handle workloadKeys to settings

settings := &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 = *settings

if 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

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后总结

ActiveMQ+Kafka+RabbitMQ学习笔记PDF

image.png

  • RabbitMQ实战指南

image.png

  • 手写RocketMQ笔记

image.png

  • 手写“Kafka笔记”

image

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
码讲义、实战项目、讲解视频,并且会持续更新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后总结

ActiveMQ+Kafka+RabbitMQ学习笔记PDF

[外链图片转存中…(img-tpDAdZq9-1713751727286)]

  • RabbitMQ实战指南

[外链图片转存中…(img-qYBQL4al-1713751727286)]

  • 手写RocketMQ笔记

[外链图片转存中…(img-VXQbaZhL-1713751727287)]

  • 手写“Kafka笔记”

[外链图片转存中…(img-i56UUlVq-1713751727287)]

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值