Kubernetes YAML Generator
Fill in a form or paste a Compose file, and get manifests the API server accepts.
Free preview.
- Free preview: the first lines of the YAML (up to 20) with every check result, and for pasted manifests every count with the first problems (up to 10).
- Locked until you unlock it: download and copy.
- Unlock: Pro pass, ₹179 for 30 days, a one-time payment that never renews.
Ways to unlock shows how to get the full result.
Printing this result is locked in the free preview.
Paste a compose.yaml or docker-compose.yml. Variables with a default (${TAG:-1.0}) take their default.
One or more manifests, separated by ---. Read as YAML 1.1, as Kubernetes reads it.
manifests.yaml
Checks
Converting from Compose
Before applying: kubectl apply --dry-run=server -f manifests.yaml lets your cluster check it; kubectl apply -f manifests.yaml creates it.
Locked in the free preview. Opens the ways to unlock this result.
Locked in the free preview. Batch runs unlock with a pass.
Locked in the free preview. Query results unlock with a pass.
About the Kubernetes YAML Generator
Describe your app once — image, ports, environment, CPU and memory, health checks — and get the Kubernetes objects around it: a Deployment, Job or CronJob, a Service, an Ingress with TLS, a ConfigMap and a Secret, a PersistentVolumeClaim, a HorizontalPodAutoscaler and the Namespace. Or paste a docker-compose.yml and get a Deployment and a Service for each service, claims for its named volumes, and a note for every setting Kubernetes has no equivalent for (depends_on, bind mounts, env_file, networks…).
Every result is checked the way the API server would check it: against JSON Schemas built from the Kubernetes 1.37 OpenAPI document (so a typo such as protocl or replicas: "3" is caught), and against Kubernetes’ own rules — names and labels, selectors that match their pods, ports, quantities such as 512m written for 512Mi, probes, CronJob schedules and time zones, removed API versions. Paste existing manifests to check them line by line. Nothing is uploaded: the schemas are part of the page.
How to use it
- Choose Form, From Compose or Check YAML. Load example fills in a realistic one.
- In the form, give the app a name and an image, list its ports (
http 8080) and environment (KEY=value), set CPU and memory, and tick the objects you need. A schedule is checked as you type, with its next runs in the time zone you pick. - Read the problems next to the YAML: each one names the field to change. Notes (blue) are advice; errors (red) are what the API server would refuse.
- With a pass, or once this YAML is unlocked, Copy it or Download
manifests.yaml; the free preview shows its first lines and locks both. Then runkubectl apply --dry-run=server -f manifests.yamlto let your cluster check it, andkubectl apply -f manifests.yamlto create it.
Examples
Name: web · Deployment · 2 replicas · image nginx:1.27 · port http 80 · requests 100m CPU, 128Mi · memory limit 256Mi · Service on port 80
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app.kubernetes.io/name: web
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: web
template:
…
containers:
- name: web
image: nginx:1.27
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
path: /
port: http
---
apiVersion: v1
kind: Service
…
ports:
- name: http
port: 80
targetPort: httpThe Service selects the pods by app.kubernetes.io/name and sends traffic to the port by name, so changing the container port later needs no change to the Service.
web:
image: ghcr.io/acme/shop-web:2.4.1
ports: ["8080:3000"]
deploy:
resources:
limits: { cpus: "0.5", memory: 512M }
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 15scontainers:
- name: web
image: ghcr.io/acme/shop-web:2.4.1
ports:
- containerPort: 3000
resources:
limits:
cpu: 500m
memory: 512Mi
readinessProbe:
exec:
command: [wget, -qO-, http://localhost:3000/health]
periodSeconds: 15
…
kind: Service
ports:
- port: 8080
targetPort: 3000Compose’s 512M means 512 × 1,024 × 1,024 bytes, so it becomes 512Mi. The healthcheck becomes a readiness probe, because Docker does not restart an unhealthy container either.
In the container “web” of a Deployment:
resources:
requests:
memory: 512m
cpu: "2"
limits:
cpu: "1"
env:
- name: DEBUG
value: noError: Container “web”: the cpu request (2) is above its limit (1); a request must be less than or equal to the limit.
Error: Expected a string, got boolean false.
Warning: Container “web”: memory request “512m” means 512 thousandths of a byte (“m” is milli). Did you mean 512Mi?
Warning: "no" is the boolean false in YAML 1.1 (used here), but the string "no" in YAML 1.2. Quote it ("no") if you mean the text.Each problem comes with its line and column; Show selects it in your text.
What the check covers
- Structure against the bundled schemas (Kubernetes 1.37): unknown fields with a “did you mean”, wrong types, missing required fields, and API versions Kubernetes no longer serves (
extensions/v1beta1,batch/v1beta1CronJob,autoscaling/v2beta2and others from the deprecation guide). - Names and labels as in Kubernetes’ own code: RFC 1123 names, Service names, label keys and values, port names of up to 15 characters, environment variable names (object names, labels).
- Values: quantities and requests above limits, probes, ports and NodePorts, Ingress paths and path types, Secret data that is not base64, the 1 MiB limit of ConfigMaps and Secrets.
- CronJobs with the same parser Kubernetes uses: five fields, Sunday is 0 (not 7), no seconds, no
TZ=in the schedule, names of at most 52 characters (CronJob). - Links between objects in one file: a Service whose selector matches no pod template, a targetPort no container has, an Ingress pointing to a port the Service lacks, an autoscaler whose pods set no CPU request.
How Compose settings are converted
image,command→args,entrypoint→command,environment,working_dir,user(numeric IDs),cap_add/cap_drop,read_only,privileged,extra_hosts,stop_grace_period,platform(node selector) anddeploy.replicascarry over.portsandexpose→ container ports and a Service (published ports keep their published number as the Service port). A service with neither still gets a Service when another one connects to it byname:port, as inDATABASE_URL: postgres://app@db:5432/shop: in Compose that works without ports, in Kubernetes only through a Service.deploy.resourcesandmem_limit/cpus→ limits and requests.- Named volumes → PersistentVolumeClaims;
tmpfs→ an in-memoryemptyDir; bind mounts → an empty folder, with the command to put the files in a ConfigMap instead. secretsandconfigs→ Secret and ConfigMap volumes mounted where Compose mounts them, with thekubectl createcommand for each;env_file→ anenvFromConfigMap with its command.${VAR:-default}takes its default; other variables are listed, because Kubernetes does not fill them in.depends_on,networks,links,logging,ulimitsand the like are listed with what to do instead.
Before you apply
kubectl apply --dry-run=server -f manifests.yamlasks your own cluster, with its version, admission policies (Pod Security, quotas) and custom resources, to check everything without changing anything;kubectl diff -f manifests.yamlshows what would change.- Secrets in YAML are only base64-encoded. Create real ones with
kubectl create secret generic …, or use Sealed Secrets or External Secrets, and keep the values out of git. - Pin image versions (
nginx:1.27, or a digest) so every node runs the same image and rollbacks work.
Limitations
- The form writes one container per pod and Deployments, Jobs and CronJobs; for StatefulSets, DaemonSets, sidecars or init containers, edit the YAML and check it under Check YAML.
- Custom resources (cert-manager, Argo, Istio…) are read but not checked against a schema; they appear as unknown kinds.
- The schemas are those of Kubernetes 1.37: a field added recently may not exist on an older cluster. Cluster-side checks — admission policies, quotas, existing objects — need
kubectl apply --dry-run=server. - Compose features with no Kubernetes equivalent are listed, not converted, and
env_file,secretsandconfigsfiles cannot be read here: run thekubectl createcommands shown.
Privacy
Everything happens in your browser. What you enter or open here is not uploaded or stored by MySmartCoPilot.
Frequently asked questions
What do I get without a pass?
Without a pass, Kubernetes YAML Generator shows the first lines of the YAML (up to 20) with every check result, and for pasted manifests every count with the first problems (up to 10). Until you unlock it, the result can’t be downloaded or copied. A Pro, Premium or Ultimate pass, a one-time payment that never renews, unlocks the full result. The pricing page lists the passes and their prices.
Is this like kompose?
For Compose files, yes: services become Deployments and Services and named volumes become PersistentVolumeClaims. The difference is that every unconverted setting is explained with what to use instead, values are translated (Compose 512M → 512Mi, 0.5 CPUs → 500m), and the result is checked against the Kubernetes schemas and rules before you see it — all in the browser.
Why is "no" (or "8080") quoted in the YAML?
Kubernetes reads YAML 1.1, where unquoted yes, no, on and off are booleans and 8080 is a number. Environment variable values, labels and annotations must be strings, so the generator quotes such values; the checker flags unquoted ones in pasted YAML.
What is the difference between requests and limits?
Requests are what the scheduler reserves on a node for the container; limits are the most it may use. A container above its memory limit is stopped, and above its CPU limit it is slowed down. A request may not be larger than its limit. CPU is counted in cores (0.5 or 500m), memory in bytes with suffixes (128Mi, 1Gi).
Which time zone does a CronJob use?
Without spec.timeZone, the local time zone of the kube-controller-manager, which is often UTC. Set an IANA name such as Europe/Berlin or Asia/Kolkata to run in local time; TZ= inside the schedule is not accepted.
Is my Compose file or YAML sent anywhere?
No. The page converts and checks everything in your browser with the schemas built into it; nothing is uploaded and no cluster is contacted.