Skip to main content

Kubernetes Ingestor Plugin

Note: For advanced Crossplane integration, consider using the new Crossplane Ingestor Plugin which provides enhanced features specifically designed for Crossplane workflows.

The Kubernetes Ingestor is a custom Backstage plugin that automatically discovers Crossplane Composite Resource Definitions (XRDs) from Kubernetes clusters and transforms them into Backstage template entities.

Overview​

The Kubernetes Ingestor plugin bridges the gap between Crossplane infrastructure templates and the Backstage developer portal by:

  • Discovering XRDs from connected Kubernetes clusters
  • Generating template entities automatically in the Backstage catalog
  • Extracting form schemas from XRD OpenAPI specifications
  • Managing template versions from XRD labels
  • Enabling self-service infrastructure provisioning

Architecture​

┌─────────────────────────┐
│ Kubernetes Cluster │
│ ┌──────────────────┐ │
│ │ Crossplane XRDs │ │ ◄── Flux deploys from catalog repo
│ └──────────────────┘ │
└────────────┬───────────┘
│ Poll (60s interval)
▼
┌─────────────────────────┐
│ Kubernetes Ingestor │
│ (Backstage Plugin) │
│ ┌──────────────────┐ │
│ │ XRD Discovery │ │
│ │ Template Gen │ │
│ │ Schema Extract │ │
│ └──────────────────┘ │
└────────────┬───────────┘
│ Create entities
▼
┌─────────────────────────┐
│ Backstage Catalog │
│ ┌──────────────────┐ │
│ │ Template Entities│ │ ◄── Displayed in /create
│ └──────────────────┘ │
└─────────────────────────┘

How It Works​

1. XRD Discovery​

The ingestor polls the Kubernetes API every 60 seconds to discover XRDs with specific labels:

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: cloudflareDNSRecords.openportal.dev
labels:
openportal.dev/tags: "dns,networking,cloudflare" # Required for discovery
openportal.dev/version: "1.0.2" # Version displayed in UI
spec:
group: openportal.dev
names:
kind: CloudflareDNSRecord
versions:
- name: v1alpha1
schema:
openAPIV3Schema: # Forms generated from this schema
type: object
properties:
spec:
type: object
properties:
name:
type: string
description: DNS record name

2. Template Entity Generation​

For each discovered XRD, the ingestor creates a Backstage template entity:

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: cloudflare-dns-record
title: CloudflareDNSRecord v1.0.2
description: DNS management via External-DNS
tags:
- dns
- networking
- cloudflare
- source:kubernetes # Identifies ingestor-created templates
spec:
type: infrastructure
parameters:
# Generated from XRD schema
required:
- name
- type
- value
properties:
name:
title: Name
type: string
description: DNS record name
type:
title: Type
type: string
enum: ['A', 'AAAA', 'CNAME', 'TXT', 'MX']
value:
title: Value
type: string
description: IP address or target

3. Form Schema Processing​

The ingestor extracts and processes the OpenAPI schema from XRDs to:

  • Generate form fields with proper types
  • Add validation rules (required, patterns, min/max)
  • Include descriptions and help text
  • Set default values where specified
  • Create enum dropdowns for constrained fields

4. Catalog Integration​

Generated templates are added to the Backstage catalog with:

  • Unique identifiers based on XRD name
  • Version labels from XRD metadata
  • Tags for filtering and discovery
  • source:kubernetes tag for identification
  • Descriptions from XRD annotations

Configuration​

Plugin Installation​

The plugin is included in the app-portal repository:

// packages/backend/src/plugins/catalog.ts
import { KubernetesIngestorProvider } from '@internal/plugin-kubernetes-ingestor-backend';

export default async function createPlugin(env: PluginEnvironment): Promise<Router> {
const builder = await CatalogBuilder.create(env);

// Add Kubernetes Ingestor provider
builder.addEntityProvider(
KubernetesIngestorProvider.fromConfig(env.config, {
logger: env.logger,
scheduler: env.scheduler,
}),
);

const { processingEngine, router } = await builder.build();
await processingEngine.start();

return router;
}

App Configuration​

Configure the ingestor in app-config.yaml:

kubernetesIngestor:
enabled: true
pollInterval: 60000 # Polling interval in milliseconds
clusters:
- name: production
url: ${KUBERNETES_API_URL}
authProvider: serviceAccount
serviceAccountToken: ${KUBERNETES_SA_TOKEN}
skipTLSVerify: false

# XRD discovery filters
filters:
labelSelector: "openportal.dev/tags" # Only XRDs with this label
namespaces: [] # Empty = all namespaces

# Template generation settings
templates:
defaultType: infrastructure
defaultOwner: platform-team
publishPhase: # How to structure catalog-orders
path: /clusters/${cluster}/${namespace}/${kind}

Required XRD Labels​

XRDs must have specific labels to be discovered:

metadata:
labels:
openportal.dev/tags: "tag1,tag2,tag3" # Required: comma-separated tags
openportal.dev/version: "1.0.0" # Optional: version to display
openportal.dev/icon: "dns" # Optional: icon name
openportal.dev/owner: "platform-team" # Optional: template owner

XRD Annotations for Enhanced Templates​

Use annotations to provide additional template metadata:

metadata:
annotations:
openportal.dev/description: "Create and manage DNS records via Cloudflare"
openportal.dev/documentation: "https://docs.example.com/dns"
openportal.dev/support: "platform-team@example.com"
openportal.dev/publishPhase: |
path: /clusters/infra/${namespace}/dns-records
autoMerge: true

Usage Workflow​

1. Template Development​

Create an XRD with proper labels and schema:

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: databases.platform.io
labels:
openportal.dev/tags: "database,postgresql,storage"
openportal.dev/version: "2.1.0"
spec:
group: platform.io
names:
kind: Database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required: ["size", "version"]
properties:
size:
type: string
enum: ["small", "medium", "large"]
default: "small"
description: "Database instance size"
version:
type: string
pattern: "^[0-9]+\\.[0-9]+$"
default: "14.0"
description: "PostgreSQL version"
backup:
type: boolean
default: true
description: "Enable automated backups"

2. Deploy to Cluster​

Deploy the XRD via GitOps (Flux):

# XRD is in catalog repository
catalog/
└── templates/
└── database/
├── xrd.yaml # The XRD above
└── composition.yaml

# Flux syncs it to cluster
flux get sources git catalog
flux get kustomizations catalog-sync

3. Discovery in Backstage​

The ingestor automatically discovers the XRD:

  1. Polls cluster every 60 seconds
  2. Finds XRD with openportal.dev/tags label
  3. Extracts schema from OpenAPI specification
  4. Generates template entity
  5. Adds to catalog with source:kubernetes tag

4. Use in Developer Portal​

Developers can now use the template:

  1. Navigate to https://backstage.example.com/create
  2. Filter templates by tags (database, postgresql)
  3. Select "Database v2.1.0" template
  4. Fill out the generated form
  5. Submit to create XR in catalog-orders

Template Features​

Dynamic Form Generation​

Forms are generated from XRD schemas with:

  • Field types: string, number, boolean, array, object
  • Validation: required, patterns, min/max, enums
  • UI hints: descriptions, placeholders, defaults
  • Grouping: nested objects become form sections
  • Arrays: dynamic add/remove for list fields

Version Management​

Templates display versions from XRD labels:

labels:
openportal.dev/version: "1.2.3"

Displayed as: "TemplateName v1.2.3"

Tag-based Discovery​

Tags enable filtering and categorization:

labels:
openportal.dev/tags: "networking,security,firewall"

Users can filter by any tag in the /create catalog.

Monitoring and Debugging​

Check Ingestor Status​

# View ingestor logs
kubectl logs -n backstage deployment/backstage-backend | grep -i ingestor

# Check discovered XRDs
kubectl get xrd -A -l openportal.dev/tags

# Verify template generation in Backstage
curl http://localhost:7007/api/catalog/entities?filter=kind=Template,metadata.tags=source:kubernetes

Common Issues​

Templates Not Appearing​

  1. Check XRD labels:

    kubectl get xrd your-xrd -o yaml | grep -A5 labels
  2. Verify ingestor is running:

    kubectl logs -n backstage deployment/backstage-backend | grep "KubernetesIngestor"
  3. Check Backstage catalog:

    • Navigate to /catalog
    • Filter by kind=Template
    • Look for source:kubernetes tag

Form Fields Missing​

  1. Verify XRD schema:

    kubectl get xrd your-xrd -o yaml | grep -A50 openAPIV3Schema
  2. Check schema validation:

    • Ensure all spec.properties are defined
    • Add descriptions for better UX
    • Set required fields appropriately

Version Not Displayed​

Add version label to XRD:

kubectl label xrd your-xrd openportal.dev/version="1.0.0"

Advanced Configuration​

Custom Template Actions​

Extend generated templates with custom actions:

# In XRD annotation
metadata:
annotations:
openportal.dev/scaffolder-actions: |
- id: publish
name: github:publish
action: publish:github
input:
repoUrl: github.com?owner=org&repo=catalog-orders
sourcePath: ./
targetPath: /clusters/${cluster}/${namespace}/${kind}

Multi-Cluster Support​

Configure multiple clusters:

kubernetesIngestor:
clusters:
- name: dev
url: https://dev-cluster.example.com
authProvider: serviceAccount

- name: staging
url: https://staging-cluster.example.com
authProvider: serviceAccount

- name: production
url: https://prod-cluster.example.com
authProvider: serviceAccount

Templates will be discovered from all configured clusters.

Filtering and Namespaces​

Control which XRDs are discovered:

kubernetesIngestor:
filters:
labelSelector: "openportal.dev/tags,environment=production"
namespaces:
- crossplane-system
- platform-templates
excludeKinds:
- TestResource
- DebugResource

Integration with Scaffolder​

The ingestor works seamlessly with the Backstage Scaffolder:

  1. Template Discovery: XRDs become available as templates
  2. Form Rendering: Scaffolder uses generated schema
  3. Action Execution: Creates XRs in catalog-orders
  4. GitOps Flow: Flux deploys XRs to cluster

Best Practices​

1. XRD Design​

  • Include comprehensive OpenAPI schemas
  • Add meaningful descriptions to all fields
  • Set appropriate defaults
  • Use enums for constrained choices
  • Group related fields in nested objects

2. Labeling Strategy​

  • Always include openportal.dev/tags
  • Use semantic versioning in openportal.dev/version
  • Apply consistent tag taxonomy
  • Document tag meanings

3. Schema Validation​

  • Test XRD schemas before deployment
  • Validate with sample XRs
  • Include example values in descriptions
  • Use regex patterns for validation

4. Performance​

  • Keep polling interval reasonable (60s default)
  • Limit number of XRDs with labels
  • Use namespace filtering if possible
  • Monitor ingestor resource usage

Troubleshooting Guide​

Logs and Metrics​

# Ingestor logs
kubectl logs -n backstage deployment/backstage-backend | grep -i kubernetes-ingestor

# Check processing time
kubectl logs -n backstage deployment/backstage-backend | grep "Processing XRD"

# View discovered templates
curl http://localhost:7007/api/catalog/entities | jq '.items[] | select(.metadata.tags[]? == "source:kubernetes")'

Debug Mode​

Enable debug logging:

# app-config.yaml
kubernetesIngestor:
debug: true
logLevel: debug

Health Checks​

# Check catalog health
curl http://localhost:7007/api/catalog/health

# Verify Kubernetes connectivity
kubectl auth can-i list xrd --as=system:serviceaccount:backstage:backstage

Comparison with Crossplane Ingestor​

The newer Crossplane Ingestor Plugin provides enhanced capabilities:

FeatureKubernetes IngestorCrossplane Ingestor
FocusGeneric K8s + XRDsCrossplane-specific
Template GenerationBasicAdvanced with GitOps
API DocumentationNoAuto-generated API entities
Composition TrackingNoFull relationship mapping
CLI ToolsNoComprehensive suite
CachingSimpleMulti-level optimization
Transform PipelineFixedExtensible with hooks
Metadata SupportBasicRich annotations

Consider migrating to the Crossplane Ingestor for:

  • Better Crossplane-native features
  • Advanced template generation
  • API documentation generation
  • CLI tools for debugging
  • Performance optimizations