Skip to main content
Version: 0.8.5

Graph Inference

kro automatically infers dependencies from CEL expressions. You don't specify the order - you describe relationships, and kro figures out the rest.

How It Works​

When you reference one resource from another using a CEL expression, you create a dependency:

resources:
  - id: configmap
    template:
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: app-config
      data:
        DATABASE_URL: ${schema.spec.dbUrl}

  - id: deployment
    template:
      apiVersion: apps/v1
      kind: Deployment
      spec:
        containers:
          - env:
              - name: DATABASE_URL
                value: ${configmap.data.DATABASE_URL}

The expression ${configmap.data.DATABASE_URL} creates a dependency: deployment depends on configmap. kro will create the configmap first, wait for the expression to be resolvable, then create the deployment.

Dependency Graph (DAG)​

kro builds a Directed Acyclic Graph (DAG) where:

  • Nodes are resources
  • Edges are dependencies (created by CEL references)
  • Directed means dependencies have direction (A depends on B)
  • Acyclic means no circular dependencies

Common Patterns​

Dependency graphs follow common patterns that you'll encounter in most RGDs. Understanding these patterns helps you design effective resource relationships. Real-world RGDs often combine multiple patterns - a complex application might have parallel branches that converge into a diamond, followed by a linear chain.

In a linear chain, each resource depends on the previous one. This pattern is common when you have a sequence of resources where each step requires data from the previous step - like a ConfigMap that feeds into a Deployment, which then informs a Service.

configmap ──▶ deployment ──▶ service
resources:
  - id: configmap
    template:
      apiVersion: v1
      kind: ConfigMap
      data:
        key: ${schema.spec.value}

  - id: deployment
    template:
      apiVersion: apps/v1
      kind: Deployment
      spec:
        template:
          spec:
            containers:
              - envFrom:
                  - configMapRef:
                      name: ${configmap.metadata.name}

  - id: service
    template:
      apiVersion: v1
      kind: Service
      spec:
        selector: ${deployment.spec.selector.matchLabels}

The deployment references ${configmap.metadata.name}, creating a dependency. The service references ${deployment.spec.selector.matchLabels}, adding another link. kro creates them in sequence: configmap first, then deployment, then service.

Combining Patterns

Real-world RGDs typically combine multiple patterns. A complex application might have parallel branches (independent microservices), a diamond (services converging into a gateway), and linear chains (each service with its own config → deployment → service sequence). kro handles any valid DAG structure - these patterns are just common building blocks.

Topological Order​

kro computes a topological order - the sequence resources can be processed such that all dependencies are satisfied.

Creation: Resources created in topological order Deletion: Resources deleted in reverse order

View the computed order:

kubectl get rgd my-app -o jsonpath='{.status.topologicalOrder}'

Example output:

status:
  topologicalOrder:
    - configmap
    - deployment
    - service

Circular Dependencies​

Circular dependencies are not allowed and will cause validation to fail:

# ✗ This will fail
resources:
  - id: serviceA
    template:
      spec:
        targetPort: ${serviceB.spec.port}  # A → B

  - id: serviceB
    template:
      spec:
        targetPort: ${serviceA.spec.port}  # B → A (circular!)

Fix: Break the cycle by using schema.spec instead:

resources:
  - id: serviceA
    template:
      spec:
        targetPort: ${schema.spec.portA}  # Use schema

  - id: serviceB
    template:
      spec:
        targetPort: ${serviceA.spec.port}  # This is fine

What Happens at Runtime​

When kro reconciles an instance:

  1. Evaluate static expressions - Expressions referencing only schema.spec are evaluated once
  2. Process in topological order - For each resource:
    • Wait for all dependency expressions to be resolvable
    • Create or update the resource
    • Move to next resource in order
  3. Delete in reverse order - During deletion, process resources backwards

kro waits for CEL expressions to be resolvable before proceeding. This means the referenced resource exists and has the field being accessed.

Next Steps​

Brought to you with ♥ by SIG Cloud Provider