Writing Kubernetes Manifests With LLMs in October 2026: Validate Against Your Cluster Version, Lock Down the Security Context, and Diff Before You Apply
Ask a language model for a Kubernetes Deployment and you will get valid-looking YAML in seconds. It usually has the right shape: an apiVersion, a kind, some labels, a container, maybe a Service to go with it. The trouble is that "looks right" and "is right for my cluster" are different things. Models are trained on years of blog posts, Helm charts, and Stack Overflow answers, and a lot of that material targets Kubernetes versions that are long gone or skips the security settings nobody bothered to write down.
This guide walks through a practical workflow for using LLMs to write Kubernetes manifests without shipping broken or risky YAML. The short version: tell the model exactly what cluster it is writing for, validate the output against real schemas, add the security settings the model tends to leave out, and look at a server-side diff before anything touches a live namespace.
Why LLM-generated manifests go wrong
Most problems fall into a handful of buckets, and knowing them makes review much faster.
- Outdated API versions. Models still produce
extensions/v1beta1Ingress objects (removed in Kubernetes 1.22),batch/v1beta1CronJobs andpolicy/v1beta1PodDisruptionBudgets (both removed in 1.25), and occasionally PodSecurityPolicy, which was removed entirely in 1.25. These fail at apply time on a modern cluster, or worse, get "fixed" by someone who guesses at the new schema. - Invented or misplaced fields. A field that belongs on the container ends up on the pod spec, or a plausible-sounding field that does not exist appears. Some tools silently ignore unknown fields, so the setting you think you configured simply is not there.
- Missing security context. The default example on the internet runs as root, allows privilege escalation, and keeps every Linux capability the runtime grants. The model reproduces what it saw most often.
- No resource requests or limits. Without requests, the scheduler cannot place pods sensibly, and without memory limits a leaking container can starve its neighbors.
- Floating image tags.
image: nginx:latestmeans two pods in the same Deployment can run different code after a reschedule. - Probe mistakes. Liveness probes that check a database dependency, or that start before the app has had time to boot, cause restart loops that look like application bugs.
Step 1: Give the model the context it cannot guess
The single most useful thing you can do is put your constraints in the prompt instead of hoping the model infers them. A good prompt for manifest generation includes:
- The exact Kubernetes version of the target cluster (for example, "Kubernetes 1.31").
- Whether the namespace enforces the Pod Security Standards
restrictedprofile. - The ingress controller or Gateway API implementation you actually run.
- Your conventions: required labels, naming, which registry images come from.
- An instruction to use only stable API versions and to flag anything it is unsure about rather than guessing.
Something like this works well:
Write a Deployment and Service for a stateless HTTP API.
Target: Kubernetes 1.31, namespace enforces Pod Security "restricted".
Image: registry.example.com/orders-api@sha256:<digest> listening on 8080.
Health endpoints: /healthz (process alive), /readyz (ready for traffic).
Requirements: 3 replicas, CPU request 250m, memory request and limit 256Mi,
run as non-root, read-only root filesystem, drop all capabilities.
Labels: app.kubernetes.io/name, app.kubernetes.io/part-of=orders.
Use only GA API versions. If a field is uncertain, add a YAML comment instead of guessing.
Pasting an existing, known-good manifest from your repo as a reference example also helps a lot. The model will copy its structure and conventions instead of averaging over the internet.
Step 2: Validate against real schemas for your version
Never trust generated YAML until a schema validator has read it. Two layers are worth having.
Offline schema validation
kubeconform validates manifests against the OpenAPI schemas for a specific Kubernetes version, which catches wrong API versions and misspelled or misplaced fields without needing cluster access. It fits naturally in CI:
kubeconform -strict -summary -kubernetes-version 1.31.0 manifests/
The -strict flag rejects properties that are not in the schema, which is exactly the class of error models tend to make. If you use custom resources, point kubeconform at schemas for those CRDs as well, or it will skip them.
For deprecated APIs specifically, a tool like Fairwinds' Pluto scans files and Helm releases and tells you which apiVersion values are deprecated or removed in a given target version. That is handy when you are upgrading the cluster and want to know which generated manifests will break next.
Server-side dry run
Offline schemas do not know about your admission controllers, policies, or CRD versions. A server-side dry run sends the object through the real API server, including validation and admission, without persisting it:
kubectl apply --dry-run=server -f manifests/
If your namespace enforces the restricted Pod Security profile, a non-compliant pod spec will be rejected here, which is far better than finding out during a deploy. When you are unsure what a field means, kubectl explain is a quick way to check the model's work against the cluster's own documentation:
kubectl explain deployment.spec.strategy.rollingUpdate
kubectl explain pod.spec.containers.securityContext
Step 3: Lock down the security context
This is where generated manifests most often fall short, so it is worth knowing what good looks like and checking for it explicitly. A container-level security context that satisfies the Pod Security Standards restricted profile looks like this:
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
A few things to watch when you add these settings to model output:
runAsNonRootonly checks; it does not change the user. If the image's default user is root, the pod will fail to start. Either build the image with a non-rootUSERor setrunAsUserto a non-zero UID.- A read-only root filesystem needs writable scratch space. Many apps write to
/tmpor a cache directory. Mount anemptyDirvolume at those paths instead of dropping the read-only setting. - Do not let the model add capabilities to "fix" an error. If something fails after dropping all capabilities, find out which one is truly needed. Binding to a port below 1024 is a common cause, and the simpler fix is usually to listen on a high port and let the Service map port 80 to it.
Enforcing this at the namespace level is the best backstop, because it catches every manifest regardless of who or what wrote it:
apiVersion: v1
kind: Namespace
metadata:
name: orders
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
Static analysis tools add another layer. kube-linter, Trivy (in its config scanning mode), and Checkov all flag missing limits, privileged containers, host path mounts, and similar issues. Running one of them in CI on every pull request means a generated manifest gets the same scrutiny as a hand-written one.
kube-linter lint manifests/
trivy config manifests/
Step 4: Fix the operational details models skip
Resources
Ask the model to include requests and limits, then replace its numbers with ones based on your own measurements. The model has no idea how much memory your service uses, so any value it picks is a placeholder. Setting the memory request equal to the memory limit is a common and predictable starting point; CPU limits are more debated because they can cause throttling, so follow whatever policy your team already uses.
Image references
Replace tags like latest with a specific version, and ideally an immutable digest (image@sha256:...). That way every replica runs the same bits, and a rollback actually rolls back. If you use a tool such as Renovate or Dependabot to bump image references, digests stay current without manual editing.
Probes
Readiness and liveness probes answer different questions, and generated manifests often blur them:
- Readiness decides whether the pod receives traffic. It can reasonably fail when a critical dependency is down.
- Liveness decides whether the kubelet restarts the container. It should check only that the process itself is healthy, never an external database or API, or a brief outage elsewhere will restart every pod at once.
- Startup probes give slow-booting apps time to initialize before liveness checks begin, which avoids restart loops during startup.
Selectors and labels
A Deployment's spec.selector is immutable once created in apps/v1. If the model renames labels on a later iteration and you apply the result over an existing Deployment, the API server will reject the change. Keep selectors small and stable (for example, just app.kubernetes.io/name), and put descriptive labels elsewhere in the pod template metadata.
Secrets
Models sometimes inline credentials into a Secret's data field and describe the base64 encoding as if it protects the value. It does not; base64 is an encoding, not encryption. Keep real secret values out of prompts and out of Git entirely. Reference Secrets by name in the manifest and populate them through whatever secret management your platform already uses.
Step 5: Diff before you apply
Once the manifest validates and passes your linters, look at what will actually change in the cluster:
kubectl diff -f manifests/
kubectl diff performs a server-side dry run and shows the difference between the live object and what you are about to apply. This is the moment to catch surprises: a replica count reset to 1, a removed environment variable, a selector change, or a Service port that no longer matches. If you deploy through a GitOps tool like Argo CD or Flux, its diff view serves the same purpose and should be part of review.
Roll out to a non-production namespace first and watch it settle:
kubectl rollout status deployment/orders-api -n orders-staging
kubectl get events -n orders-staging --sort-by=.lastTimestamp
Events are where scheduling failures, image pull errors, failed probes, and Pod Security rejections show up, and they often explain a problem faster than application logs.
A review checklist for generated manifests
- Every
apiVersionis GA and supported by your target cluster version. kubeconform -strictpasses for that version, including CRD schemas.kubectl apply --dry-run=serversucceeds against the real namespace.- The container security context runs as non-root, blocks privilege escalation, drops all capabilities, and uses the RuntimeDefault seccomp profile.
- Requests and limits are set from real measurements, not the model's guesses.
- Images are pinned to a version or digest, never
latest. - Liveness probes check only the process; readiness probes gate traffic.
- Selectors are minimal and unchanged from the live object.
- No secret values appear in the manifest, the prompt, or the repository.
kubectl diffoutput has been read by a human before applying.
Where LLMs genuinely help
None of this means you should stop using models for Kubernetes work. They are very good at the tedious parts: turning a description into a first draft, converting a Docker Compose file into Deployments and Services, explaining an unfamiliar field, or writing the boilerplate for a NetworkPolicy you then tighten by hand. They are also useful for reading kubectl describe output and suggesting why a pod is stuck in CrashLoopBackOff.
The pattern that works is the same one that works for Dockerfiles, Terraform, and CI workflows: let the model draft, let deterministic tools validate, and keep a person reading the diff. The model saves you typing. The validators, the admission policies, and your review are what keep the cluster safe.
One more tool worth knowing
If you're building something and want more of the right people finding it, Buyer Radar from RankReactor finds public posts on X and LinkedIn where people ask for what you sell. It scores each lead, links to the original post, and drafts a reply or email you can send yourself with one click. Nothing is sent automatically. Paid plans include it, alongside RankReactor's automated SEO articles and UGC videos.
Comments
Post a Comment