From Dockerfile to Your First Kubernetes Deployment With AI
Shipping an app to Kubernetes the first time means a pile of YAML. Here's how I use AI to scaffold a sane Deployment, Service, and config split safely.
- #kubernetes
- #deployment
- #yaml
- #ai
- #beginner
The gap between “I have a working Docker image” and “my app runs on Kubernetes” is a pile of YAML that nobody enjoys writing the first time. You need a Deployment, a Service, probably an Ingress, a ConfigMap, maybe a Secret, and every one of them has fields you’ll get subtly wrong — the selector that doesn’t match the labels, the probe path that returns 404, the port that’s named in one place and numbered in another.
This is one of the best uses of an AI copilot I know. It has scaffolded thousands of these manifests and produces a reasonable first draft in seconds. But “reasonable first draft” is the operative phrase. The model is a fast junior engineer who’s never seen your app, so it scaffolds and you correct. You never apply generated manifests to a real cluster without reading every line.
Describe the app, not the YAML
Don’t ask for “a Kubernetes Deployment.” Describe what the app actually is and let the model translate:
I have a Node.js HTTP API in the image
registry.example.com/api:1.4.0. It listens on port 8080, has a/healthzendpoint, readsDATABASE_URLfrom the environment, and should run 3 replicas. Generate a Deployment, Service, and the ConfigMap/Secret split for its config. Include resource requests, probes, and a non-root securityContext by default.
The specifics in that prompt — the health endpoint, the port, the config split — are what turn a generic template into something close to usable. A typical Deployment comes back like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: "api"
labels:
app: "api"
spec:
replicas: 3
selector:
matchLabels:
app: "api"
template:
metadata:
labels:
app: "api"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: "api"
image: "registry.example.com/api:1.4.0"
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: "/healthz"
port: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
Check the three things beginners get wrong
Before I trust anything, I check the joints — the places where two objects have to agree:
- Selector and labels match. The Deployment’s
selector.matchLabelsmust equal the pod template’slabels, and the Service’sselectormust match too. A mismatch means a Service with no endpoints and a confusing “connection refused.” - Probe path is real. The model guesses
/healthzor/health. Confirm your app actually serves it, or the readiness probe fails forever and the pod never gets traffic. - Ports line up.
containerPort, the ServicetargetPort, and what the app actually binds to all have to be the same number.
I ask the model to self-audit these explicitly:
Verify the labels, selectors, and ports are consistent across all three manifests, and list any place they don’t match.
It’s good at catching its own inconsistencies when you point it at them.
Pro Tip: Have the model add a readinessProbe AND a separate livenessProbe, but make the liveness probe more forgiving (higher failureThreshold, longer initialDelaySeconds). A too-aggressive liveness probe restarts a healthy-but-slow pod in a loop — the most common self-inflicted CrashLoop for first-timers.
Keep secrets out of the manifest and the prompt
The model will cheerfully template your DATABASE_URL straight into a manifest if you let it. Don’t. Ask for the structure with a placeholder, and never paste the real connection string into the chat:
apiVersion: v1
kind: Secret
metadata:
name: "api-secrets"
type: Opaque
stringData:
DATABASE_URL: "REPLACE_ME" # set via sealed-secrets / external-secrets
Real secrets go in through a sealed-secrets controller, the external secrets operator, or kubectl create secret from a vault — never committed, never sent to a model. The AI helps you with the shape; the values are yours alone.
Validate offline before the cluster ever sees it
Generated YAML should pass a dry run before it touches a real API server. This is offline and safe:
kubectl apply -f manifests/ --dry-run=server -o yaml
A server dry run runs admission and validation without persisting anything, so it catches schema errors, policy rejections, and bad field types. I paste any errors back to the model:
kubectl —dry-run returned this error. What field is wrong and how do I fix it?
This loop — generate, dry-run, fix — is where most of the iteration happens, all without changing cluster state.
The first real apply is a human, in a sandbox
When the manifests dry-run clean and I’ve read every line, I apply them — to a sandbox namespace or a dev cluster first, never straight to prod:
kubectl apply -f manifests/ -n dev
kubectl rollout status deploy/api -n dev
kubectl get pods,svc,endpoints -n dev
I check that the Service actually has endpoints (the selector worked) and the pods reach Ready (the probe path was right). The AI never runs kubectl apply and never gets cluster credentials — it generates text, a human reads it, dry-runs it, and applies it to a safe namespace first. Generated YAML is a draft until a person has read and validated it.
If you want to move from raw manifests toward something reusable, packaging this into a chart and then reviewing the Helm chart with AI is the natural next step.
Get the rollout strategy right the first time
The default Deployment strategy is RollingUpdate, which is usually what you want, but the defaults around it bite first-timers. With maxUnavailable: 25% and only 3 replicas, a rollout can briefly drop to 2 healthy pods, and if your readiness probe is slow, real traffic hits pods that aren’t ready. I ask the model to make the strategy explicit and explain the trade-off:
Add an explicit RollingUpdate strategy to this Deployment for 3 replicas. Explain what maxSurge and maxUnavailable do, and pick values that never drop below 2 ready pods during a rollout.
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
maxUnavailable: 0 with maxSurge: 1 means Kubernetes always brings up a new pod and waits for it to be ready before retiring an old one — zero capacity dip, at the cost of one extra pod’s worth of resources during the rollout. For a first production service that’s almost always the right call, and it’s the kind of nuance the model explains well once you ask for the reasoning instead of just the YAML.
Don’t forget the boring availability fields
The manifests that run for years differ from first-draft manifests in a few unglamorous fields, and the model will add them if you ask but won’t volunteer them all. I run a final pass:
Review these manifests for production-readiness. Check for: a PodDisruptionBudget, anti-affinity so replicas don’t all land on one node, a terminationGracePeriodSeconds that matches how long the app takes to drain, and resource limits, not just requests.
A PodDisruptionBudget keeps a node drain from taking all your replicas at once; pod anti-affinity stops all three replicas landing on a single node that then reboots. These aren’t first-deploy blockers, but they’re the difference between “it runs” and “it survives a Tuesday maintenance window,” and surfacing them early saves a later incident.
Conclusion
The first trip from Dockerfile to running pod is mostly boilerplate, and boilerplate is exactly what AI scaffolds well. It gives you a Deployment, Service, and config split in seconds with sane defaults — probes, requests, non-root. Your job is to check the joints where objects must agree, keep secrets out of both the manifest and the prompt, dry-run everything offline, and do the first real apply by hand in a sandbox. Treat the output as a draft from a fast junior, and you get a strong head start without shipping a guess to prod.
Beginner-friendly prompts for this live in the prompt library, and the full Kubernetes and Helm guides cover what comes after your first deploy.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.