Turn "the AI wrote my manifests" from a risk into a workflow: generate Deployment/Service/HPA/PDB sets with an assistant, then wire kubeconform (schema truth) and kube-score (operational hygiene) into a pre-commit loop, and iterate your prompts — not just the YAML — until output arrives clean.
The starter set below reproduces four real AI failure modes; you will catch all four with tooling, fix them, then prove your improved prompt stops producing them.
~75 minutes hands-on · Core tier (maps to module M2).
Install two static binaries (no cluster needed): brew install kubeconform kube-score (or GitHub releases; Linux/Windows binaries exist). $0.
Create manifests/ with these four files — a plausible AI draft for an orders-api service containing four seeded defects:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
labels:
app: orders-api
spec:
replicas: 3
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
spec:
containers:
- name: orders-api
image: ghcr.io/example/orders-api:1.4.2
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: orders-api
spec:
selector:
app: orders-api
ports:
- port: 80
targetPort: 8080
protocol: TCP
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: orders-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: orders-api
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
# pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: orders-api
spec:
minAvailable: 2
selector:
matchLabels:
app: orders-service
kubeconform -strict -summary manifests/. One resource fails: the HPA rejects targetCPUUtilizationPercentage — that field belongs to autoscaling/v1, but the manifest declares autoscaling/v2. This API-version blending is the single most common K8s hallucination: models interpolate between schema generations they saw in training. Fix by asking your assistant for "the autoscaling/v2 metrics block equivalent of 70% CPU", then verify the shape against the kubeconform-fetched schema by re-running until Valid: 4.kube-score score manifests/*.yaml. Read every CRITICAL. Three are seeded:orders-service, so it matches nothing. Silent failure: everything applies cleanly and node drains evict all three replicas at once.replicas: 3 fights the HPA: every kubectl apply snaps the fleet back to 3 mid-scale-event.kubeconform -strict fully valid, and the three seeded CRITICALs gone.--ignore-test pod-networkpolicy — the flag is documentation of a decision, so record why in a comment in your Makefile.make verify) that runs kubeconform -strict then kube-score score --exit-one-on-warning with your agreed ignore list. Commit-blocking, not advisory.replicas field on HPA-targeted Deployments; every container has requests and limits; PDB selector must equal the Deployment's matchLabels verbatim; must pass kubeconform -strict." Run the gates on the fresh output. Save before/after validation reports.Feeding the exact validator error text back to the model fixes it far faster than describing the problem in your own words — validators speak a dialect models know.
kubeconform answers "will the API server accept this?"; kube-score answers "will this survive production?". AI drafts routinely pass the first and fail the second — the PDB label mismatch applies cleanly and still leaves you with zero disruption protection.
kubeconform -strict -summary manifests/ → Valid: 4, Invalid: 0.kube-score score shows none of the three seeded CRITICALs; remaining ignores are listed in your Makefile with reasons.git commit with a re-broken PDB selector is rejected by your hook.The manifests/ repo with fixed YAML, the verify hook/Makefile, and reports/before.txt + reports/after.txt validator output. Self-grading rubric (pass = 7/10):
-cache ~/.kubeconform for offline use.target wrong: metrics[].resource.target.type: Utilization with averageUtilization: 70.replicas? Say "omit the replicas field entirely; the HPA owns scale" — models default to copying the most common Deployment shape.Both validators are offline OSS and never see an LLM — run them on client manifests freely. For generation on restricted engagements, use the client's approved assistant or a local model (Ollama + a coder model handles K8s YAML well), and strip client namespaces/registry hostnames from prompts. Deliverable to the client: the same before/after reports — they double as evidence that AI-assisted work on their estate passed deterministic validation.
targetCPUUtilizationPercentage is autoscaling/v1 syntax inside an autoscaling/v2 object — caught by kubeconform -strict (additional property not allowed). Fix: metrics block with type: Resource, target.type: Utilization, averageUtilization: 70.app: orders-service ≠ Deployment label app: orders-api — caught by kube-score "Deployment has PodDisruptionBudget". Fix: match labels verbatim.limits (e.g., cpu 500m / memory 256Mi).replicas: 3 on an HPA-targeted Deployment — kube-score CRITICAL; every apply resets live scale. Fix: delete the field.