Patch in the Definitions

    By default, KubeVela will merge patched values with CUE’s merge. However, CUE cannot handle conflicting fields currently.

    For example, if replicas=5 has been set in a component instance, once there is another trait, attempting to patch the value of the replicas field, it will fail. So we recommend that you need to plan ahead and don’t use duplicate fields between components and traits.

    But in some cases, we do need to deal with overwriting fields that have already been assigned a value. For example, when set up resources in multi-environments, we hope that the envs in different environments are different: i.e., the default env is MODE=PROD, and in the test environment, it needs to be modified to MODE=DEV DEBUG=true .

    In this case, we can apply the following application:

    After deploying the application, you can see that in the test namespace, the envs of the nginx application are as follows:

    1. spec:
    2. containers:
    3. - env:
    4. - name: MODE
    5. value: test
    6. - name: DEBUG
    7. value: "true"

    At the same time, in the prod namespace, the envs are as follows:

    1. spec:
    2. containers:
    3. - env:
    4. - name: MODE
    5. value: prod

    deploy-test will deploy nginx to the test namespace. At the same time, the env trait overwrite the same envs by using the patch strategy, thus adding MODE=test DEBUG=true in the test namespace, while the nginx in the prod namespace will retain the original MODE=prod env.

    KubeVela provides a series of patching strategies to help resolve conflicting issues. When writing patch traits and workflow steps, you can use these patch strategies to solve conflicting values. Note that the patch strategy is not an official capability provided by CUE, but an extension developed by KubeVela.

    For the usage of all patch strategies, please refer to .

    This pattern is extremely useful when the component definition is provided by third-party component provider (e.g. software distributor) so app operators do not have privilege to change its template.

    Below is an example for node-affinity trait:

    In patch, we declare the component object fields that this trait will patch to.

    The patch trait above assumes the target component instance have spec.template.spec.affinity field. Hence, we need to use appliesToWorkloads to enforce the trait only applies to those workload types have this field. Meanwhile, we use // +patchStrategy=retainKeys to override the conflict fields in the original component instance.

    Another important field is podDisruptive, this patch trait will patch to the pod template field, so changes on any field of this trait will cause the pod to restart, We should add podDisruptive and make it to be true to tell users that applying this trait will cause the pod to restart.

    Now the users could declare they want to add node affinity rules to the component instance as below:

    1. apiVersion: core.oam.dev/v1beta1
    2. kind: Application
    3. metadata:
    4. name: testapp
    5. spec:
    6. components:
    7. - name: express-server
    8. type: webservice
    9. properties:
    10. image: oamdev/testapp:v1
    11. traits:
    12. - type: "gateway"
    13. properties:
    14. domain: testsvc.example.com
    15. http:
    16. "/": 8000
    17. - type: "node-affinity"
    18. properties:
    19. server-owner: ["owner1","owner2"]
    20. resource-pool: ["pool1","pool2","pool3"]
    21. tolerations:
    22. resource-pool: "broken-pool1"
    23. server-owner: "old-owner"

    Patch to traits

    You can also patch to other traits by using patchOutputs in the Definition. Such as:

    1. kind: TraitDefinition
    2. metadata:
    3. name: patch-annotation
    4. spec:
    5. schematic:
    6. cue:
    7. template: |
    8. patchOutputs: {
    9. ingress: {
    10. metadata: annotations: {
    11. "kubernetes.io/ingress.class": "istio"
    12. }
    13. }
    14. }

    The patch trait above assumes that the component it binds has other traits which have ingress resource. The patch trait will patch an istio annotation to the ingress resource.

    And the ingress resource is now like:

    1. apiVersion: networking.k8s.io/v1beta1
    2. kind: Ingress
    3. metadata:
    4. annotations:
    5. kubernetes.io/ingress.class: istio
    6. name: ingress
    7. spec:
    8. rules:
    9. spec:
    10. rules:
    11. - host: testsvc.example.com
    12. http:
    13. paths:
    14. - backend:
    15. service:
    16. name: express-server
    17. port:
    18. number: 8000
    19. path: /
    20. pathType: ImplementationSpecific

    Note: You need to put this kind of trait at the last place to patch for other traits.

    You can even write a for-loop in patch trait, below is an example that can patch for all resources with specific annotation.

    1. apiVersion: core.oam.dev/v1beta1
    2. kind: TraitDefinition
    3. metadata:
    4. name: patch-for-argo
    5. spec:
    6. cue:
    7. patch: {
    8. metadata: annotations: {
    9. "argocd.argoproj.io/compare-options": "IgnoreExtraneous"
    10. "argocd.argoproj.io/sync-options": "Prune=false"
    11. }
    12. }
    13. patchOutputs: {
    14. for k, v in context.outputs {
    15. "\(k)": {
    16. metadata: annotations: {
    17. "argocd.argoproj.io/compare-options": "IgnoreExtraneous"
    18. "argocd.argoproj.io/sync-options": "Prune=false"
    19. }
    20. }
    21. }
    22. }

    This example solved a .

    When you use op.#ApplyComponent in a custom workflow step definition, you can patch component or traits in the patch field.

    For example, when using Istio for canary release, you can add annotations of the release name to the component in patch: workload of op.#ApplyComponent; meanwhile, you can change the traffic and destination rule in patch: traits: <trait-name>.

    Following is a real example of canary rollout in a custom workflow step:

    After deploying the above definition, you can apply the following workflow to control the canary rollout:

    1. ...
    2. workflow:
    3. steps:
    4. - name: rollout-1st-batch
    5. type: canary-rollout
    6. properties:
    7. batchPartition: 0
    8. traffic:
    9. weightedTargets:
    10. - revision: reviews-v1
    11. weight: 90
    12. - revision: reviews-v2
    13. weight: 10
    14. - name: manual-approval
    15. type: suspend
    16. - name: rollout-rest
    17. type: canary-rollout
    18. properties:
    19. batchPartition: 1
    20. traffic:
    21. weightedTargets:
    22. - revision: reviews-v2
    23. weight: 100

    In the first and third steps, we declared different revisions and weight in traffic. In the step definition of canary-rollout, we will overwrite the revision and weight declared by the user through , so as to control the progressive rollout in the workflow.