How KubeVela Transforms an AppFile into a Kubernetes Application
This article explains how KubeVela converts an AppFile into a Kubernetes Application by outlining the two‑stage process, showing the relevant Go source code for the `vela up` command, detailing the AppFile and Application data structures, and describing the controller logic that renders the final Kubernetes resources.
Overview
KubeVela is a cloud‑native application management engine built on Kubernetes and the Open Application Model (OAM). It transforms a user‑defined AppFile into an OAM Application object, which is then reconciled into native Kubernetes workloads such as Deployments and Services.
AppFile to Application conversion
An AppFile describes an application in a simple YAML format. Example:
# vela.yaml
name: test
services:
nginx:
type: webservice
image: nginx
env:
- name: NAME
value: kubevela
svc:
type: NodePort
ports:
- port: 80
nodePort: 32017The command vela up reads this file, creates an OAM Application, and applies it to the cluster.
The entry point for vela up is defined in cli/up.go:
// NewUpCommand creates the "up" command
func NewUpCommand(c types.Args, ioStream cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "up",
Short: "Apply an appfile",
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.Flags().StringP(appFilePath, "f", "", "specify file path for appfile")
return cmd
}The Run method loads the AppFile (see appfile/api/appfile.go) and calls BuildOAMApplication to produce an Application object.
Key data structures:
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
}
type Service map[string]interface{}The conversion logic iterates over each service, renders it to an OAM component, and assembles the components:
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)
for serviceName, svc := range app.GetServices() {
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
}Rendering a service separates workload configuration from traits:
func (s Service) RenderServiceToApplicationComponent(tm template.Manager, serviceName string) (v1alpha2.ApplicationComponent, error) {
workloadKeys := map[string]interface{}{}
var traits []v1alpha2.ApplicationTrait
wtype := s.GetType()
comp := v1alpha2.ApplicationComponent{Name: serviceName, WorkloadType: wtype}
for k, v := range s.GetApplicationConfig() {
if tm.IsTrait(k) {
traits = append(traits, v1alpha2.ApplicationTrait{Name: k})
continue
}
workloadKeys[k] = v
}
pt, err := json.Marshal(workloadKeys)
if err != nil { return comp, err }
settings := &runtime.RawExtension{}
if err := settings.UnmarshalJSON(pt); err != nil { return comp, err }
comp.Settings = *settings
if len(traits) > 0 { comp.Traits = traits }
return comp, nil
}Application controller flow
After vela up creates the Application, the application controller reconciles it, generating an ApplicationConfiguration and the corresponding Component objects.
func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
app := new(v1alpha2.Application)
if err := r.Get(ctx, client.ObjectKey{Name: req.Name, Namespace: req.Namespace}, app); err != nil { return ctrl.Result{}, err }
appfile, err := appParser.GenerateAppFile(ctx, app.Name, app)
ac, comps, err := appParser.GenerateApplicationConfiguration(appfile, app.Namespace)
if err := handler.apply(ctx, ac, comps); err != nil { return ctrl.Result{}, err }
return ctrl.Result{}, r.UpdateStatus(ctx, app)
}ApplicationConfiguration controller flow
The controller renders each component’s workload and traits into native Kubernetes objects and applies them.
func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
ctx := context.Background()
ac := &v1alpha2.ApplicationConfiguration{}
if err := r.client.Get(ctx, req.NamespacedName, ac); err != nil { return reconcile.Result{}, err }
workloads, depStatus, err := r.components.Render(ctx, ac)
applyOpts := []apply.ApplyOption{apply.MustBeControllableBy(ac.GetUID()), applyOnceOnly(ac, r.applyOnceOnlyMode, log)}
if err := r.workloads.Apply(ctx, ac.Status.Workloads, workloads, applyOpts...); err != nil { return reconcile.Result{}, err }
return reconcile.Result{RequeueAfter: waitTime}, nil
}Resulting resources
The generated .vela/deploy.yaml shows the OAM Application representation of the example:
apiVersion: core.oam.dev/v1alpha2
kind: Application
metadata:
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: {}After the controllers run, the following native resources exist in the cluster:
# kubectl get application
NAMESPACE NAME AGE
default test 24h
# kubectl get ApplicationConfiguration,Component
NAME AGE
applicationconfiguration.core.oam.dev/test 24h
NAME WORKLOAD-KIND AGE
component.core.oam.dev/nginx Deployment 24hReferences
KubeVela GitHub repository: https://github.com/oam-dev/kubevela
OAM website: https://oam.dev
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Native
We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
