Skip to main content
Version: v0.8.x

Trait

A Trait represents a cross-cutting concern that can be attached to components to add additional capabilities like persistent storage, observability, security policies, or service mesh integration. Traits modify or extend the resources generated by ComponentTypes without requiring changes to the ComponentType itself.

API Version​

openchoreo.dev/v1alpha1

Resource Definition​

Metadata​

Traits are namespace-scoped resources typically created in an Organization's namespace to be available for components in that organization.

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: <trait-name>
namespace: <org-namespace> # Organization namespace

Spec Fields​

FieldTypeRequiredDefaultDescription
schemaTraitSchemaNo-Configurable parameters for this trait
creates[TraitCreate]No[]New Kubernetes resources to create
patches[TraitPatch]No[]Modifications to existing ComponentType resources

TraitSchema​

Defines the configurable parameters that developers can set when attaching this trait to a component.

FieldTypeRequiredDefaultDescription
typesobjectNo-Reusable type definitions referenced in parameters
parametersobjectNo-Developer-facing configuration options
envOverridesobjectNo-Parameters that can be overridden per environment

Parameter Schema Syntax​

Uses the same inline schema syntax as ComponentType: a single pipe after the type, then space-separated constraints:

fieldName: "type | default=value enum=val1,val2"

Example:

schema:
parameters:
volumeName: "string"
mountPath: "string"
containerName: "string | default=app"

envOverrides:
size: "string | default=10Gi"
storageClass: "string | default=standard"

TraitCreate​

Defines a new Kubernetes resource to be created when the trait is applied.

FieldTypeRequiredDefaultDescription
targetPlanestringNodataplaneTarget plane: dataplane or observabilityplane
templateobjectYes-Kubernetes resource template with CEL expressions

CEL expressions in trait templates have access to the following context variables:

metadata​

Platform-computed metadata for resource generation (same as ComponentType):

FieldTypeDescription
metadata.namestringBase name for generated resources (e.g., my-service-dev-a1b2c3d4)
metadata.namespacestringTarget namespace for resources
metadata.componentNamestringName of the component
metadata.componentUIDstringUnique identifier of the component
metadata.projectNamestringName of the project
metadata.projectUIDstringUnique identifier of the project
metadata.environmentNamestringName of the environment (e.g., development, production)
metadata.environmentUIDstringUnique identifier of the environment
metadata.dataPlaneNamestringName of the data plane
metadata.dataPlaneUIDstringUnique identifier of the data plane
metadata.labelsmapCommon labels to add to all resources
metadata.annotationsmapCommon annotations to add to all resources
metadata.podSelectorsmapPlatform-injected selectors for pod identity
trait​

Trait-specific metadata:

FieldTypeDescription
trait.namestringName of the trait (e.g., persistent-volume)
trait.instanceNamestringUnique instance name within the component (e.g., data-storage)
parameters​

Merged trait instance parameters with schema defaults applied. Fields depend on the Trait schema definition.

Helper Functions​
FunctionDescription
oc_generate_name(args...)Generate valid Kubernetes names with hash suffix for uniqueness
oc_hash(string)Generate 8-character FNV-32a hash from input string
oc_merge(map1, map2, ...)Shallow merge maps (later maps override earlier ones)
oc_omit()Remove field/key from output when used in conditional expressions

TraitPatch​

Defines modifications to existing resources generated by the ComponentType.

FieldTypeRequiredDefaultDescription
forEachstringNo-CEL expression for iterating over a list
varstringNo-Variable name for forEach iterations (required if forEach set)
targetPatchTargetYes-Specifies which resource to patch
targetPlanestringNodataplaneTarget plane: dataplane or observabilityplane
operations[JSONPatchOperation]Yes-List of JSONPatch operations to apply

PatchTarget​

Specifies which Kubernetes resource to modify.

FieldTypeRequiredDescription
groupstringYesAPI group (e.g., apps, batch). Use empty string "" for core resources
versionstringYesAPI version (e.g., v1, v1beta1)
kindstringYesResource type (e.g., Deployment, StatefulSet)
wherestringNoCEL expression to filter which resources to patch

JSONPatchOperation​

Defines a modification using JSONPatch format (RFC 6902) with OpenChoreo extensions.

FieldTypeRequiredDescription
opstringYesOperation: add, replace, remove
pathstringYesJSON Pointer to the field (RFC 6901)
valueanyNoValue to set (not used for remove)

Supported Operations​

  • add: Add a new field or array element
  • replace: Replace an existing field value
  • remove: Delete a field

Path Syntax​

Supports array filters for targeting specific elements:

/spec/containers[?(@.name=='app')]/volumeMounts/-

Examples​

Persistent Volume Trait​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: persistent-volume
namespace: default
spec:
schema:
parameters:
volumeName: "string"
mountPath: "string"
containerName: "string | default=app"

envOverrides:
size: "string | default=10Gi"
storageClass: "string | default=standard"

creates:
- template:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ${metadata.name}-${trait.instanceName}
namespace: ${metadata.namespace}
spec:
accessModes:
- ReadWriteOnce
storageClassName: ${parameters.storageClass}
resources:
requests:
storage: ${parameters.size}

patches:
- target:
group: apps
version: v1
kind: Deployment
operations:
- op: add
path: /spec/template/spec/containers[?(@.name=='${parameters.containerName}')]/volumeMounts/-
value:
name: ${parameters.volumeName}
mountPath: ${parameters.mountPath}
- op: add
path: /spec/template/spec/volumes/-
value:
name: ${parameters.volumeName}
persistentVolumeClaim:
claimName: ${metadata.name}-${trait.instanceName}

Sidecar Container Trait​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: logging-sidecar
namespace: default
spec:
schema:
parameters:
logPath: "string | default=/var/log/app"
sidecarImage: "string | default=fluent/fluent-bit:latest"

patches:
- target:
group: apps
version: v1
kind: Deployment
operations:
- op: add
path: /spec/template/spec/containers/-
value:
name: log-collector
image: ${parameters.sidecarImage}
volumeMounts:
- name: logs
mountPath: ${parameters.logPath}
- op: add
path: /spec/template/spec/volumes/-
value:
name: logs
emptyDir: {}

Resource Limits Trait​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: resource-limits
namespace: default
spec:
schema:
envOverrides:
cpuLimit: "string | default=1000m"
memoryLimit: "string | default=512Mi"

patches:
- target:
group: apps
version: v1
kind: Deployment
operations:
- op: add
path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/cpu
value: ${parameters.cpuLimit}
- op: add
path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/memory
value: ${parameters.memoryLimit}

Multi-Container Trait with forEach​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: multi-volume
namespace: default
spec:
schema:
types:
Mount:
name: "string"
path: "string"
parameters:
mounts: "[]Mount"

patches:
- target:
group: apps
version: v1
kind: Deployment
forEach: ${parameters.mounts}
var: mount
operations:
- op: add
path: /spec/template/spec/volumes/-
value:
name: ${mount.name}
emptyDir: {}
- op: add
path: /spec/template/spec/containers[?(@.name=='app')]/volumeMounts/-
value:
name: ${mount.name}
mountPath: ${mount.path}

Usage​

Developers attach traits to components in the Component specification:

apiVersion: openchoreo.dev/v1alpha1
kind: Component
metadata:
name: my-service
spec:
componentType: deployment/service

traits:
- name: persistent-volume
instanceName: data-storage
parameters:
volumeName: data
mountPath: /var/data
containerName: app
envOverrides:
size: 20Gi
storageClass: fast-ssd

Platform engineers can also override trait parameters in ReleaseBinding:

apiVersion: openchoreo.dev/v1alpha1
kind: ReleaseBinding
metadata:
name: my-service-production
namespace: default
spec:
environment: production
owner:
componentName: my-service
projectName: default

traitOverrides:
- instanceName: data-storage
parameters:
size: 100Gi
storageClass: production-ssd

Best Practices​

  1. Single Responsibility: Each trait should address one cross-cutting concern
  2. Naming: Use descriptive names that indicate the capability being added
  3. Parameters: Provide sensible defaults for all non-required parameters
  4. Target Specificity: Use where clauses when needed to avoid unintended modifications
  5. Testing: Test traits with different ComponentTypes to ensure compatibility
  6. Documentation: Document which ComponentTypes a trait is designed to work with
  7. Idempotency: Ensure traits can be safely applied multiple times

Trait vs ComponentType​

AspectComponentTypeTrait
PurposeDefines core deployment patternAdds cross-cutting concerns
ScopeOne per componentMultiple can be attached to one component
ResourcesCreates primary workload resourcesCreates supplementary resources or patches existing ones
ModificationDetermines base resource structureModifies or extends ComponentType resources
ExamplesService, WebApp, ScheduledTaskPersistent Storage, Logging, Security
  • ComponentType - Defines the base deployment pattern
  • Component - Attaches traits to components
  • ReleaseBinding - Binds a ComponentRelease to an environment with trait parameter overrides