TL;DR: A Kubernetes prompt that only names the workload produces YAML that boots without resource requests, limits, or probes — all valid, none of it safe to run. State CPU/memory requests and limits, a real health-check path for liveness and readiness, and your cluster's API version explicitly, then dry-run it before it reaches a real cluster.
A Deployment manifest with no resources block and no livenessProbe is perfectly valid Kubernetes YAML. It applies cleanly, the pod schedules, the container starts, and kubectl get pods shows Running. None of that tells you the pod will behave under load, survive a slow dependency at startup, or leave room for anything else on the node. Kubernetes prompts fail in this specific, quiet way more than any other: the output runs, and running is not the bar.
Why Does Generated Kubernetes YAML Skip Resource Limits and Probes?
Because nothing in a bare request forces the model to add them. "Write me a Deployment for my API service" is a complete, satisfiable instruction without either field — Kubernetes will happily schedule an unbounded container next to everything else on the node. The gap isn't a hallucination; it's an omission the prompt never ruled out. If you want both, you have to ask for both, by name, every time.
The Kubernetes Prompt Checklist: What to State Explicitly
- Resource requests and limits, with real numbers for your workload, not placeholders you'll forget to fill in.
- A liveness probe and a readiness probe, each with an actual health-check path your service exposes — not "add health checks," which a model may collapse into a single probe.
- The target Kubernetes API version, so it doesn't default to whatever was common in its training data.
- Whether this is a Deployment, StatefulSet, or something else — a stateful workload with no persistent volume claim is a different mistake than a missing probe.
- Namespace, labels, and any existing naming convention your cluster already uses.
Here's a prompt built from that list and the manifest it should produce:
Generate a Kubernetes Deployment manifest, apiVersion apps/v1, for a
stateless HTTP API service. Requirements:
- Name: {{service_name}}, namespace {{namespace}}
- 3 replicas
- Container exposes port 8080, health check at GET /healthz
- Resource requests: 250m CPU, 256Mi memory (steady-state observed usage)
- Resource limits: 500m CPU, 512Mi memory (no CPU throttling below 500m)
- Liveness probe: GET /healthz, initialDelaySeconds 10, periodSeconds 10
- Readiness probe: GET /healthz, initialDelaySeconds 3, periodSeconds 5
- Labels: app={{service_name}}, tier=backend
Do not omit resources or probes. Do not invent an apiVersion other than
apps/v1 for this Deployment.
apiVersion: apps/v1
kind: Deployment
metadata:
name: payments-api
namespace: production
labels:
app: payments-api
tier: backend
spec:
replicas: 3
selector:
matchLabels:
app: payments-api
template:
metadata:
labels:
app: payments-api
tier: backend
spec:
containers:
- name: payments-api
image: registry.example.com/payments-api:1.4.2
ports:
- containerPort: 8080
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
That resources block and both probes are the two things this post is about, and both are optional as far as the Kubernetes API is concerned — the manifest above would still be valid YAML with either one deleted, which is exactly why the prompt has to name them instead of assuming a competent-looking Deployment request implies them.
The Three Probe Types, and What to Tell the Model About Each
| Probe | Answers | Wrong config causes |
|---|---|---|
startupProbe | Has the app finished its (possibly slow) boot sequence? | Liveness probe kills a container that was still starting |
livenessProbe | Is this container still alive and should Kubernetes restart it if not? | Restart loops on a container that was only slow, not dead |
readinessProbe | Should this pod receive traffic right now? | Requests hit a pod mid-startup or mid-dependency-outage |
A model given only "add health checks" will often collapse these into a single livenessProbe and skip readinessProbe entirely, which is the combination most likely to route live traffic to a pod that isn't ready. Name each probe you want and its purpose, not just "add probes."
Requests vs Limits: Why "Same Number for Both" Is Usually Wrong
A prompt that says "set resource limits" without distinguishing requests from limits often gets both fields set to the same value. That's not wrong, but it's a specific choice with a real cost: setting CPU limits equal to requests means the container gets throttled the instant it needs to burst above its steady-state usage, which shows up as latency spikes under traffic exactly when you can least afford them. Memory behaves differently — a memory limit is a hard OOM-kill boundary, not a throttle, so headroom there matters for a different reason.
State the intent, not just the numbers: "requests should reflect typical steady-state usage; limits should allow headroom for traffic spikes; CPU limits especially should not equal requests unless you have a specific reason to guarantee a fixed slice." That sentence is what turns a generic resource block into one that matches how your workload actually behaves.
Prompting for Helm Instead of Raw Manifests
A Helm chart is a templating layer over manifests, not a manifest itself, and prompting for one works best when you give the model the underlying shape first. "Write a Helm chart for the Deployment above, templating replicas, image.tag, and the resource requests/limits into values.yaml" produces something you can actually verify, because you already know what the rendered output should look like. Asking cold for "a Helm chart for my API" tends to produce plausible Go-template syntax that doesn't render to anything you specified, because there was nothing specific to specify.
Prompting for ConfigMaps, Secrets, and StatefulSets
Configuration and stateful workloads need their own explicit constraints, because the failure modes are different from a stateless Deployment.
For configuration, separate what's genuinely secret from what isn't, and say so in the prompt: "put the database host and port in a ConfigMap, and reference the database password from an existing Secret named db-credentials, key password — do not generate a value for the password." A model asked generically for "the config for this service" has no way to know which fields your team treats as sensitive, and one asked for "a Secret" with no other guidance may fabricate a base64-encoded placeholder that looks like a real credential sitting in your repository.
apiVersion: v1
kind: ConfigMap
metadata:
name: payments-api-config
namespace: production
data:
DB_HOST: "db.internal.example.com"
DB_PORT: "5432"
LOG_LEVEL: "info"
---
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: payments-api-config
key: DB_HOST
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
For a StatefulSet, name the thing that actually makes it stateful: a stable network identity, an ordered rollout, or a persistent volume claim per replica. "Write a StatefulSet for a database with a PersistentVolumeClaim per pod, 10Gi each, and a headless Service for stable DNS" gives the model the specific reason you need a StatefulSet instead of a Deployment. A prompt that just says "make this a StatefulSet" without naming which of those properties matters tends to produce a manifest with a volumeClaimTemplates block copied from a generic example, sized and named for someone else's workload rather than yours.
Why the apiVersion Question Matters More Than a One-Line Fix
apps/v1 for a Deployment has been stable long enough that most models get it right by default, which is part of why it's easy to assume the rest of a manifest's API surface is equally settled. It isn't. Kubernetes moves resources through alpha and beta API groups before they graduate to a stable, non-versioned-with-a-suffix path, and older beta paths do eventually stop being served by the API server entirely on newer cluster versions. A model trained on a mix of documentation from different points in that timeline has no way to know which stage your specific cluster supports unless the prompt says so.
The practical fix costs one sentence: state the Kubernetes minor version your cluster runs ("this is a 1.31 cluster") and ask the model to use the current stable apiVersion for anything beyond the handful of resources (Deployments, Services, ConfigMaps) that have been unchanged for years. For anything newer, HorizontalPodAutoscalers, Ingress classes, and policy resources have all moved between API groups within the last several years, so treat those as more likely to need a version check against your actual cluster before you trust a generated manifest's apiVersion line.
How Kubernetes Manifest Prompts Differ from Application Code Prompts
The same "state the constraints, don't trust the default" discipline shows up in prompting for test generation that finds real bugs — a test suite that runs and passes tells you as little as a Deployment that schedules and runs, if nobody specified what "correct" meant. And because a manifest is generated text you're asked to trust at face value, the same caution behind does emotional prompting work applies here too: a firmly worded prompt doesn't make the YAML more correct, only a more specific one does.
If your cluster's workloads are provisioned by Terraform, the discipline in prompting for infrastructure as code — state what exists, name the blast radius, dry-run before apply — is the same discipline, one layer down the stack. And the review habits both need are the same ones covered in AI prompts for QA and DevOps teams.
Namespaces, Labels, and the Conventions a Model Can't Guess
Every cluster past a certain size has its own conventions for namespaces, label keys, and how workloads are grouped for cost allocation or access control, and none of that is visible to a model unless the prompt states it. A request that omits namespace and labels entirely doesn't fail, it defaults: the manifest lands in default with whatever labels the model considers idiomatic, which may not match anything your monitoring, RBAC rules, or NetworkPolicies are actually selecting on.
If your organization uses a label like team: payments or cost-center: platform to drive dashboards or budget alerts, say so explicitly and give an example of an existing manifest that already carries it. A model shown one real example of your convention will match it far more reliably than one asked to invent a "sensible" set of labels from general Kubernetes best practices, because your convention and a generic one only agree by coincidence.
Before You Apply: A Short Checklist
- Does every container have both
requestsandlimits, not just one? - Does every container that serves traffic have a
readinessProbewith a real path? - Is the
apiVersionthe one your actual cluster supports, not a guess? - If this replaces something already running, did
kubectl diffshow only the changes you expected? - Did a second person read the YAML, not just confirm it applied?
Stop rewriting prompts. Start shipping.
Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 4.8★ on the Chrome Web Store.
Create An Account