CRDEntry

5 min read

Each entry in spec.crds is a CRDEntry. The map key becomes the CRD name at runtime — it is never written in the YAML body.

spec:
  crds:
    database:                  # ← this is the name
      enabled: true
      description: string
      crdFile: ./my-crd.yaml
      crFiles: [./my-cr.yaml]
      setup: [./my-setup.yaml]

      apiTypes:                # → apitypes.md
        ...

      namespaced: true
      namespace: default

      dependsOn:
        other-crd:
          condition: healthy

      enrich:                      # optional → enrich.md
        - pods
        - events

      labels:
        app: "{{ .metadata.name }}"
        env: production

      labelSelector:
        app: my-operator
      fieldSelector:
        metadata.namespace: production

      operatorBox:             # → operatorbox.md
        reconciler:
          workers: 3
          resync: 30s
          queue:
            shared: false
            maxDepth: 100
            failureThreshold: 5
        ...

      conversion:              # → conversion.md
        ...

      validation:              # → validation.md
        ...

      mutation:                # → mutation.md
        ...

      webhooks:
        validation: true
        mutation: true
        operations: [CREATE, UPDATE]

      restrictedNamespaces:
        - kube-system
      allowedNamespaces:
        - dev

      endpoints:
        enabled: true
        health: true
        info: true

      imports:
        - motif: ./motifs/postgres/motif.yaml   # → motif.md
          with:
            image: postgres:14

Identity and mode

FieldTypeDefaultDescription
enabledbooltruefalse skips this CRD entirely — it is not started or watched.
descriptionstringShown in the /katalog endpoint.
modestringautotyped or dynamic. Auto-detected from apiTypes.location.
crdFilestringPath or HTTPS URL to the CRD YAML. Used for CRD-driven API inference in dev mode.
crFileslist(string)Ordered list of CR YAML files to apply after the CRD is registered but before the runtime starts. Dev mode only. Supports relative paths and HTTPS URLs.
setuplist(string)Ordered list of YAML files to apply before the operator starts. Use for external dependencies such as namespaces, Secrets, or additional CRDs. Applied with kubectl apply -f in declaration order.

Scope

FieldTypeDefaultDescription
namespacedbooltrueWhether the CRD is namespace-scoped or cluster-scoped.
namespacestringTarget namespace for namespaced CRDs.

Runtime behaviour

FieldTypeDefaultDescription
workersint3Concurrent reconcile goroutines.
resyncduration30sFull re-list interval (e.g. 30s, 5m).
ignoreStatusPatchboolfalseSkip status patch operations.
ignoreObservedGenerationboolfalseSkip the observed-generation idempotency check.
removeFinalizersboolfalseStrip all finalizers on deletion.

dependsOn

CRDs that must reach a condition before this one starts reconciling.

# All three forms are valid:

# map with condition
dependsOn:
  schema-migrator:
    condition: healthy

# scalar shorthand
dependsOn:
  schema-migrator: healthy

# list (bare names — condition defaults to "started")
dependsOn:
  - schema-migrator
ConditionDescription
startedWorkers are running (default when no condition is given).
healthyWorkers running and consecutive failure count is zero.

queue

FieldTypeDefaultDescription
sharedboolfalseUse the shared default workqueue instead of a per-CRD queue.
maxDepthint100 (QUEUE_DEPTH env)Max items in the queue before new items are dropped.
failureThresholdint5 (FAILURE_THRESHOLD env)Consecutive reconcile failures before health transitions to degraded.

labels

Additional labels to attach to each CR managed by this CRD entry. Labels are applied on every reconcile cycle alongside the standard Orkestra ownership labels.

labels:
  app: "{{ .metadata.name }}"
  env: production
  team: platform

Keys must be valid Kubernetes label keys (static — no template syntax).
Values are Go templates resolved against the CR at reconcile time. All CR fields and user-defined notes are available as template variables.

This is distinct from labelSelector, which filters which CRs are watched. labels: writes labels onto CRs that are already being reconciled.

labelSelector

Filters which resources this CRD entry watches and reconciles. Only objects whose labels match all declared key-value pairs are picked up by the informer.

labelSelector:
  app: my-operator
  env: production

Required for built-in types (ConfigMap, Pod, Secret, etc.) — without a selector, Orkestra would reconcile every instance of that type in the cluster. Optional for custom CRDs, where it can narrow scope within a group.

Values are static strings. Template syntax is not supported here.

fieldSelector

Filters resources by field values rather than labels. Field selectors are evaluated server-side before the informer pipeline receives any events, reducing watch traffic.

fieldSelector:
  metadata.namespace: production
  metadata.name: my-config

Only fields exposed by the Kubernetes API server are valid — arbitrary user-defined fields are not supported. Common uses: restrict by namespace or target a single object by name.

fieldSelector is optional for all types. When omitted, all objects allowed by labelSelector and namespace restrictions are watched.

enrich

enrich


webhooks

Per-CRD admission webhook override. Overrides security.webhooks for this CRD only.

FieldTypeDescription
validationboolInclude in ValidatingWebhookConfiguration.
mutationboolInclude in MutatingWebhookConfiguration.
operations[]stringWhich operations trigger the webhook. Default: [CREATE, UPDATE].

restrictedNamespaces / allowedNamespaces

Per-CRD namespace guards. Override security.namespaceProtection lists for this CRD only.

restrictedNamespaces:
  - kube-system
  - production
allowedNamespaces:
  - dev
  - staging

endpoints

endpoints:
  enabled: true
  health: true
  info: true

imports

Motif imports — pull reusable resource templates into this CRD’s reconciler.

imports:
  - motif: ./motifs/postgres/motif.yaml
    with:
      image: postgres:14
  - motif: ghcr.io/orkspace/motifs/nginx:v1
    oci: true
    with:
      port: "8080"

→ Full Motif import schema: motif

serve

Controls whether this CRD is exposed through the Gateway API and the Control Center’s Serve form. Requires gateway.api.enabled: true at the Katalog level.

spec:
  crds:
    platformResource:
      serve:
        enabled: true
        category: "Compute"
        description: "Deploy and manage platform workloads"
        ignore:
          - spec.internalRef
          - spec.managedBy
        include: ./serve/platformresource.yaml   # or inline fields:
        fields:
          environment:
            label: "Environment"
            placeholder: "staging"
            category: "Basics"
            order: 1
          workloadType:
            label: "Workload Type"
            category: "Basics"
            order: 2
          productionApproval:
            label: "Approval Ticket"
            hint: "Required for production deployments"
            category: "Governance"
            order: 10
            when:
              - field: environment
                equals: production
          certIssuer:
            label: "Certificate Issuer"
            category: "TLS"
            order: 20
            or:
              - field: workloadType
                equals: cert
          maintenanceMode:
            label: "Maintenance Mode"
            disabled: "This field is managed by the platform team"
            order: 99

Full reference:serveserve.fields, serve labels/annotations, serve.name, serve.namespace, serve.config.response, serve.tokens.

Where to go next

Conceptual overview:concepts/self-service Gateway API:gateway-api


Sub-schemas

FieldReference
apiTypesapitypes
enrichenrich
operatorBoxoperatorbox
conversionconversion
validationvalidation
mutationmutation
serveserve