Skip to content

Instantly share code, notes, and snippets.

@binura-g
Created September 24, 2025 00:59
Show Gist options
  • Save binura-g/750dd4a345a499111c504d7a402ae150 to your computer and use it in GitHub Desktop.
Save binura-g/750dd4a345a499111c504d7a402ae150 to your computer and use it in GitHub Desktop.
apiVersion: kro.run/v1alpha1
kind: ResourceGraphDefinition
metadata:
name: webapps.kro.run
spec:
schema:
apiVersion: v1alpha1
kind: WebApp
spec:
name: string
image: string | default="nginx:1.27"
replicas: integer | default=1
containerPort: integer | default=8080
# Endpoints array: 0..N
endpoints:
type: array
items:
type: object
required: [name, port, path, host]
properties:
name: string
port: integer
path: string
host: string
# "ingress" (default) or "managedAPI"
type: string | enum("ingress","managedAPI") | default="ingress"
resources:
# --- Workload & ClusterIP service ---
- id: deployment
template:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${schema.spec.name}
labels:
app.kubernetes.io/name: ${schema.spec.name}
spec:
replicas: ${schema.spec.replicas}
selector:
matchLabels:
app.kubernetes.io/name: ${schema.spec.name}
template:
metadata:
labels:
app.kubernetes.io/name: ${schema.spec.name}
spec:
containers:
- name: app
image: ${schema.spec.image}
ports:
- containerPort: ${schema.spec.containerPort}
- id: service
template:
apiVersion: v1
kind: Service
metadata:
name: ${schema.spec.name}
labels:
app.kubernetes.io/name: ${schema.spec.name}
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: ${schema.spec.name}
ports:
- name: http
port: ${schema.spec.endpoints.?[0].orValue({"port": schema.spec.containerPort}).port}
targetPort: ${schema.spec.containerPort}
# ===== Endpoint slot 0 =====
# Ingress for endpoints[0] when type == "ingress"
- id: ingress-0
includeWhen:
- ${size(schema.spec.endpoints) > 0}
- ${schema.spec.endpoints[0].type == "ingress"}
template:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ${schema.spec.name}-${schema.spec.endpoints[0].name}
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: ${schema.spec.endpoints[0].host}
http:
paths:
- path: ${schema.spec.endpoints[0].path}
pathType: Prefix
backend:
service:
name: ${service.metadata.name}
port:
number: ${schema.spec.endpoints[0].port}
# HTTPRoute (Gateway API) for endpoints[0] when type == "managedAPI"
- id: httproute-0
includeWhen:
- ${size(schema.spec.endpoints) > 0}
- ${schema.spec.endpoints[0].type == "managedAPI"}
template:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ${schema.spec.name}-${schema.spec.endpoints[0].name}
spec:
parentRefs:
- name: default-gateway # adapt to your Gateway
hostnames:
- ${schema.spec.endpoints[0].host}
rules:
- matches:
- path:
type: PathPrefix
value: ${schema.spec.endpoints[0].path}
backendRefs:
- name: ${service.metadata.name}
port: ${schema.spec.endpoints[0].port}
# ===== Endpoint slot 1 =====
# This is where KRO falls short, can't generate dynamic resources in a loop.
- id: ingress-1
includeWhen:
- ${size(schema.spec.endpoints) > 1}
- ${schema.spec.endpoints[1].type == "ingress"}
template:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ${schema.spec.name}-${schema.spec.endpoints[1].name}
spec:
rules:
- host: ${schema.spec.endpoints[1].host}
http:
paths:
- path: ${schema.spec.endpoints[1].path}
pathType: Prefix
backend:
service:
name: ${service.metadata.name}
port:
number: ${schema.spec.endpoints[1].port}
- id: httproute-1
includeWhen:
- ${size(schema.spec.endpoints) > 1}
- ${schema.spec.endpoints[1].type == "managedAPI"}
template:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ${schema.spec.name}-${schema.spec.endpoints[1].name}
spec:
parentRefs:
- name: default-gateway
hostnames:
- ${schema.spec.endpoints[1].host}
rules:
- matches:
- path:
type: PathPrefix
value: ${schema.spec.endpoints[1].path}
backendRefs:
- name: ${service.metadata.name}
port: ${schema.spec.endpoints[1].port}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment