日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

發布時間:2025/3/20 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 源码解读:KubeVela 是如何将 appfile 转换为 K8s 特定资源对象的 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | 樊大勇

KubeVela 是一個簡單易用又高度可擴展的云原生應用管理引擎,是基于 Kubernetes 及阿里云與微軟云共同發布的云原生應用開發模型 OAM 構建。

KubeVela 基于 OAM 模型構建了一套具體的實現,通過 Golang 編寫,可以端到端地為用戶構建云原生應用的平臺,提供一個相對完整的解決方案。

KubeVela 項目自 2020 年 7 月份在社區里面發起,受到包括阿里、微軟、Crossplane 等公司工程師在內的廣大社區志愿者的歡迎,并一起投入到項目開發工作中。他們把在 OAM 實踐里面的各種經驗與教訓,都總結沉淀到 KubeVela 項目中。

本文主要目的是探索 KubeVela?如何將一個?appfile?文件轉換為 K8s 中特定的資源對象。

該過程總的來說分為兩個階段:

  • appfile?轉為 K8s 中的?application
  • 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 中創建。

    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. 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 完成。

    作者簡介

    樊大勇,華勝天成研發工程師,GitHub ID:@just-do1。

    加入 OAM

    • OAM 官網:
      https://oam.dev

    • KubeVela GitHub 項目地址:
      https://github.com/oam-dev/kubevela

    • 社區交流釘群:

    總結

    以上是生活随笔為你收集整理的源码解读:KubeVela 是如何将 appfile 转换为 K8s 特定资源对象的的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。