Skip to main content

CRD Reference

kindling defines two Custom Resource Definitions (CRDs) under the apps.example.com/v1alpha1 API group.


DevStagingEnvironment​

Declares a complete application environment: a Deployment, Service, optional Ingress, and zero or more auto-provisioned backing services.

API version: apps.example.com/v1alpha1
Kind: DevStagingEnvironment
Scope: Namespaced
Short name: dse

Full spec​

apiVersion: apps.example.com/v1alpha1
kind: DevStagingEnvironment
metadata:
name: my-app
spec:
deployment:
image: ""
port: 8080
replicas: 1
command: []
args: []
env:
- name: KEY
value: "value"
resources:
cpuRequest: "100m"
cpuLimit: "500m"
memoryRequest: "128Mi"
memoryLimit: "512Mi"
healthCheck:
path: "/healthz"
port: 8080
initialDelaySeconds: 5
periodSeconds: 10

service:
port: 8080
targetPort: 8080
type: "ClusterIP"

ingress:
enabled: true
host: "app.localhost"
path: "/"
pathType: "Prefix"
ingressClassName: "traefik"
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
tls:
secretName: "tls-secret"
hosts:
- "app.localhost"
routes:
- path: "/orders"
service: "my-orders-svc"
port: 5000
- path: "/inventory"
pathType: "Exact"
service: "my-inventory-svc"
port: 3000

dependencies:
- type: postgres
version: "16"
image: ""
port: 5432
envVarName: "DATABASE_URL"
storageSize: "1Gi"
env:
- name: POSTGRES_USER
value: "custom"
resources:
cpuRequest: "100m"
memoryLimit: "512Mi"
- type: redis
shared: true
sharedKey: "billing"

Spec fields​

spec.deployment​

FieldTypeRequiredDefaultDescription
imagestring✅—Container image reference
portint32✅—Container port (1–65535)
replicas*int32❌1Number of pod replicas
command[]string❌—Override container entrypoint
args[]string❌—Arguments passed to entrypoint
env[]EnvVar❌—Environment variables
resources*ResourceRequirements❌—CPU/memory requests and limits
healthCheck*HealthCheckSpec❌—Liveness and readiness probe config

spec.service​

FieldTypeRequiredDefaultDescription
portint32✅—Service port (1–65535)
targetPort*int32❌deployment portBackend target port
typestring❌"ClusterIP"ClusterIP, NodePort, or LoadBalancer

spec.ingress​

FieldTypeRequiredDefaultDescription
enabledbool✅falseWhether to create an Ingress
hoststring❌—Hostname for the Ingress rule
pathstring❌"/"URL path prefix for the primary route
pathTypestring❌"Prefix"Prefix, Exact, ImplementationSpecific
ingressClassName*string❌—IngressClass name (e.g. "traefik")
annotationsmap[string]string❌—Extra Ingress annotations
tls*IngressTLSSpec❌—TLS configuration
routes[]IngressRouteSpec❌—Extra path -> service routes merged onto this same Ingress (see below)
spec.ingress.routes[]​

Additional path -> service routes merged onto the same Ingress object/host as the primary route above — useful for a frontend (e.g. an SPA) that calls several backend services via same-origin path prefixes (/orgs, /auth, /billing, ...) under one shared host, without a second, unmanaged Ingress object.

FieldTypeRequiredDefaultDescription
pathstring✅—URL path to match, e.g. "/orders"
pathTypestring❌"Prefix"Prefix, Exact, ImplementationSpecific
servicestring✅—Kubernetes Service name to route to
portint32✅—Service port to route to

Manage routes without editing YAML directly via kindling ingress:

# Patch the live DSE's Ingress with a new route
kindling ingress add-route my-app --path /orders --service my-orders-svc --port 5000

# See the primary route + all extra routes
kindling ingress list my-app

# Remove a route
kindling ingress remove-route my-app --path /orders

# Once confirmed working, persist it into the DSE YAML so it's applied
# on every future deploy
kindling ingress save my-app -f dev-environment.yaml

spec.dependencies[]​

FieldTypeRequiredDefaultDescription
typeDependencyType✅—See supported types below
versionstring❌latestImage tag
imagestring❌—Full image override
port*int32❌type defaultOverride service port
envVarNamestring❌type defaultOverride injected env var name
storageSize*Quantity❌"1Gi"PVC size for stateful deps
env[]EnvVar❌—Override dependency container env vars
resources*ResourceRequirements❌—CPU/memory for dependency container
sharedbool❌falseConverge with other DSEs on one instance per type/sharedKey instead of a dedicated instance per DSE (see Dependencies)
sharedKeystring❌dependency TypeGroups shared instances into separate instances within the namespace

Supported dependency types:

postgres · redis · mysql · mongodb · rabbitmq · minio · elasticsearch · kafka · nats · memcached · cassandra · consul · vault · influxdb · jaeger

Status fields​

FieldTypeDescription
availableReplicasint32Number of ready pods
deploymentReadyboolDeployment has reached desired state
serviceReadyboolService has been created
ingressReadyboolIngress has been created (if enabled)
dependenciesReadyboolAll declared dependencies are running
urlstringExternally reachable URL
conditions[]ConditionStandard Kubernetes conditions

Examples​

Minimal:

apiVersion: apps.example.com/v1alpha1
kind: DevStagingEnvironment
metadata:
name: simple-app
spec:
deployment:
image: nginx:1.25
port: 80
service:
port: 80

Full-featured:

apiVersion: apps.example.com/v1alpha1
kind: DevStagingEnvironment
metadata:
name: platform-api
spec:
deployment:
image: registry:5000/platform:v2
replicas: 2
port: 8080
env:
- name: LOG_LEVEL
value: debug
resources:
cpuRequest: "250m"
cpuLimit: "1"
memoryRequest: "256Mi"
memoryLimit: "1Gi"
healthCheck:
path: /healthz
service:
port: 8080
ingress:
enabled: true
host: platform.localhost
ingressClassName: traefik
dependencies:
- type: postgres
version: "16"
- type: redis
- type: elasticsearch
- type: kafka
- type: vault

CIRunnerPool​

Declares a pool of self-hosted CI runners. Supports GitHub Actions and GitLab CI via the spec.ciProvider field (defaults to github).

API version: apps.example.com/v1alpha1
Kind: CIRunnerPool
Scope: Namespaced

Full spec​

apiVersion: apps.example.com/v1alpha1
kind: CIRunnerPool
metadata:
name: myuser-runner-pool
spec:
ciProvider: github # "github" or "gitlab"
githubUsername: "myuser"
repository: "myorg/myrepo"
tokenSecretRef:
name: github-runner-token
key: github-token
githubURL: "https://github.com"
replicas: 1
runnerImage: "ghcr.io/actions/actions-runner:latest"
labels:
- linux

Spec fields​

FieldTypeRequiredDefaultDescription
ciProviderstring✅""CI platform: github or gitlab
githubUsernamestring✅—Developer handle (added as runner label)
repositorystring✅—Repo slug — owner/repo (GitHub) or group/project (GitLab)
tokenSecretRefSecretKeyRef✅—Reference to CI token Secret
githubURLstring❌https://github.comBase URL (for GHE or custom GitLab instance)
replicas*int32❌1Number of runner pods
runnerImagestring❌ghcr.io/actions/actions-runner:latestRunner container image
labels[]string❌—Extra runner labels

Runner pod structure​

Each runner pod created by the operator contains:

ContainerImagePurpose
runnerPlatform-specific runner imageRegisters with CI platform (GitHub or GitLab), executes workflow jobs
build-agentKaniko executorBuilds container images from signal files

Shared volume: emptyDir at /builds/ for signal-file communication.

Runner labels automatically include:

  • self-hosted
  • <githubUsername> (from spec)
  • Any extra labels from spec.labels

Workflows target a specific developer's runner with:

runs-on: [self-hosted, "<username>"]