Kubernetes Manifest Generator
Fill a guided form, get schema-validated Deployment, Service and Ingress YAML — entirely on this device.
No constraint warnings.
Outputs are schema-tested against Kubernetes v1.33.1 (recorded 2026-08-18).
Share links carry only the structure — preset, Service type, ConfigMap and probe toggles. Names, images, hosts and env values never ride.
Press ? for shortcuts
Do it offline:$ kubectl create deployment web --image=nginx:1.27 --replicas=2 --dry-run=client -o yaml
How to use it
- Pick the object chain: Deployment alone, Deployment + Service, or Deployment + Service + Ingress — the on-page cards follow the preset.
- Name the app and set the image with a tag or digest; the name becomes every object's name, the app label and the selector.
- Set replicas and the container ports, then add env rows — a toggle carries them in a ConfigMap through envFrom instead of inline values.
- Optionally add HTTP probes, resource requests and limits in Kubernetes quantities, the Service type and port, and the Ingress host and path.
- Press Generate manifests, then copy or download each card — or all of them as one manifests.yaml — and apply with kubectl.
Fill a guided form and get Deployment, Service and Ingress YAML whose wiring actually lines up: the selector matches the pod labels, the Service targets the right container port, the Ingress routes to the Service it names. Field rules follow the Kubernetes documentation, and every output shape this form can produce is schema-tested against Kubernetes v1.33 in CI. Everything runs on this device — no cluster, no upload.
How it works
Generation runs in two phases. Validation collects every finding in one pass — a bad name never hides a bad port — and each field rule carries its kubernetes.io citation: object names are DNS-1123 labels, Ingress hosts are RFC 1123 with one leading wildcard label allowed, label keys take an optional DNS-subdomain prefix, env names never start with a digit. Refusals block emission; advisories, like an untagged image, ride the constraint strip beside finished cards.
The selector is the contract the whole chain hangs on. This generator writes the minimal form: the Deployment's selector matches exactly one label pair, app set to your name, and the pod template carries that same pair. Extra labels you add land on object metadata and the pod template only — never in the selector — because a selector is immutable after create, and every label in it must keep matching the template forever. The Service reuses the same single pair, so the pods a Deployment manages are exactly the pods its Service routes to.
Ports chain through three names that read alike and mean different things. containerPort is what the process listens on; the Service's port is what clients call; targetPort is how the Service finds the container — here it is always your first container port. The Ingress never sees a pod: its backend names the Service and the Service's own port number, which is why an Ingress card only exists in the preset that also emits the Service it routes to. Paths are matched as pathType Prefix, the documented choice that covers subpaths.
Resource fields parse as real Kubernetes quantities through the same shared quantity engine the resource calculator on this site uses — decimal cpu like 0.5 normalizes to 500m, binary memory like 128Mi stays binary, and a limit below its request is refused because the API server refuses it. Env values that look credential-shaped draw a warning naming the key, never echoing the value, and the page points at a Secret instead — a ConfigMap is plaintext by design.
The schema claim is specific: CI executes every output shape this form can reach and validates each object against the frozen v1.33.1 strict schemas (additionalProperties: false), so an emitted key that Kubernetes does not define fails the build, not your cluster. The page itself validates nothing at runtime — for YAML you have edited afterwards, the Kubernetes YAML validator on this site does that job in your browser.
Examples
Deployment only: web on nginx:1.27, 2 replicasapiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 8080
The same shape kubectl create deployment prints, plus the explicit containerPort. Name, app label and selector are one string on purpose — the selector must match the template labels, and it cannot be edited after create.
Deployment + ClusterIP Service, 80 to 8080apiVersion: v1
kind: Service
metadata:
name: web
labels:
app: web
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 8080
protocol: TCP
Clients inside the cluster call web:80; the Service forwards to targetPort 8080, the first container port. ClusterIP is the default type — reachable inside the cluster only.
Full chain: Ingress for web.example.comapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
labels:
app: web
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
The backend names the Service and its port number — never a pod. pathType Prefix matches / and everything under it; the ingressClassName picks which controller answers, and leaving it empty falls back to the cluster's default class.
Edge: NodePort for a lab without a load balancerapiVersion: v1
kind: Service
metadata:
name: web
labels:
app: web
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
protocol: TCP
No nodePort field rides on purpose: the control plane assigns one from its configured range, by default 30000–32767, and every node then answers on it. Pin one manually only when you must, inside that range.
ConfigMap env plus resources, cpu written as 0.5apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: web-config
resources:
requests:
cpu: 500m
memory: 128Mi
limits:
memory: 256Mi
cpu 0.5 normalized to 500m through the shared quantity parser — same value, canonical spelling. The env rows moved into a web-config ConfigMap card and the container references it with envFrom; empty resource fields are simply omitted.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
An untagged image means :latest
Leave the tag off and the kubelet resolves :latest with an Always pull policy, so two pods can run different builds of the same reference. The images documentation advises pinning; this form warns on untagged references and accepts digests, which pin hardest.
Selectors are immutable — and minimal here
apps/v1 refuses selector edits after create, so the generator keeps the selector to one pair, app: your-name, and never copies your extra labels into it. Labels you add stay on metadata and the pod template, where they remain free to change without orphaning a ReplicaSet.
NodePort's default range is 30000–32767
The apiserver assigns NodePorts from --service-node-port-range, which defaults to 30000–32767 — that is why a fresh NodePort Service answers on a high port, not on 80. LoadBalancer goes one step further and needs a controller to provision the address; on bare metal without one it sits pending forever.
Probes ship as bare httpGet on purpose
Both probes call the same path on your first container port and inherit the documented defaults — checks every 10 seconds, 3 failures to act, 1 second timeout. Those numbers belong in your file only once you have reason to change them; the probes documentation walks each knob.
Common errors
Name `Web_App` is not a valid DNS-1123 label — lowercase letters, digits and hyphens, starting and ending with a letter or digit, at most 63 characters.- Object names become DNS entries — web.default.svc.cluster.local — so uppercase and underscores are out. web-app is the usual rewrite.
Ingress host `Web.example.com` is not a valid RFC 1123 host — lowercase DNS labels separated by dots (one leading `*.` wildcard label is allowed).- Hosts follow DNS rules: lowercase, digits and hyphens per label. A wildcard is legal only as the entire first label, *.example.com — never in the middle.
Container port `70000` must be a whole number between 1 and 65535.- TCP ports are 16-bit. The same band applies to the Service port; the two are validated separately so the message names the field you actually mistyped.
`nginx` has no tag or digest — Kubernetes will pull `:latest`, which the images documentation advises against relying on in production.- The cards still generate — an untagged reference is legal — but what :latest points at changes under you. Registry ports never trip this check: localhost:5000/web is untagged, localhost:5000/web:2 is not.
The env value of `AWS_ACCESS_KEY_ID` looks like a credential — put it in a Secret and reference it, instead of a ConfigMap or plain env; nothing typed here is a secret store.- ConfigMaps and pod specs are plaintext to anyone who can read them. The warning names the key, never repeats the value — and share links from this page structurally exclude every typed value anyway.
FAQ
How do I apply the generated files?
Save the cards — or the combined manifests.yaml download — and run kubectl apply -f against the file or the folder. The cards are ordered so one apply works in one pass: the ConfigMap comes before the Deployment that references it through envFrom.
Why can I define only one container?
A deliberate v1 law of this generator: one Deployment, one container. Sidecars, init containers and multi-container pods are real, but they multiply every field this form guides — add them by editing the generated file, which is exactly what the file is for.
What is the difference between port, targetPort and containerPort?
containerPort documents what the process listens on. The Service's port is the number clients call. targetPort is where the Service sends traffic — here always the first container port. So 80 to 8080 means: call web:80, land on the container's 8080.
Which API versions do the cards use?
apps/v1 for the Deployment, v1 for the Service and ConfigMap, networking.k8s.io/v1 for the Ingress — the stable versions every supported cluster serves. CI validates every reachable output against the Kubernetes v1.33 strict schemas, so the emitted fields are ones the API actually defines.
Does this page talk to my cluster or validate at runtime?
Neither. The form, the engine and the YAML never leave this device — nothing is uploaded and no kubectl runs anywhere. Validation here is CI-side schema testing plus the field rules; for YAML you edit afterwards, the Kubernetes YAML validator on this site checks it in your browser, and kubectl apply --dry-run=server asks your real API server.
Should env values go in a ConfigMap or a Secret?
ConfigMaps are for plain configuration — log levels, feature flags, URLs. Anything credential-shaped belongs in a Secret and gets referenced, which is why a token-looking value here draws a warning that points at the Kubernetes Secret tool on this site instead of storing anything.
Can I pin a NodePort number or add TLS here?
Not in this form. A NodePort Service is emitted without a nodePort so the control plane assigns one from its range, and TLS on the Ingress needs a certificate Secret that only your cluster can hold — add spec.tls and a nodePort by editing the file once the certificate exists.
Keyboard shortcuts
- /
- Focus the app name (outside any field).
- ⌘/Ctrl + Enter
- Generate the manifests from the current form.
- ⌘/Ctrl + S
- Download every object as manifests.yaml.
- ⌘/Ctrl + C
- With no text selected, copy all generated YAML.
- ⌘/Ctrl + Shift + C
- Force the copy while a selection is active.
- t
- Cycle the site theme (inactive while typing in a field).
- ? or ⌘/Ctrl + /
- Show the shortcut overlay.
- Esc
- Dismiss the topmost dialog.