A capital letter
Resource names are DNS labels, so My-Service is rejected at apply time
My-Service
Paste manifests, or names one per line, and find out which of the naming rules applies to each one and exactly which character breaks it. A dot is fine on a ConfigMap and refused on a Service, a Service name has to start with a letter, and a CronJob runs out of room at 52 characters for a reason nothing in the manifest mentions.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Validate. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
Resource names are DNS labels, so My-Service is rejected at apply time
My-Service
The segment limit, which bites when a generated name adds a suffix
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Most resource names are DNS labels: lowercase alphanumerics and hyphens only. An underscore is the most common rejection.
Instead:Lowercase with hyphens. Convert underscores when translating from Docker Compose service names.
Some kinds use a DNS subdomain, which allows dots, and some use a DNS label, which does not. A name valid for one is rejected for another.
Instead:Check against the kind you are actually creating.
Controllers append suffixes. A Deployment name becomes a ReplicaSet name plus a hash, which becomes a Pod name plus another, and the limit applies at each step.
Instead:Leave roughly 15 characters of headroom.
Every name field in what you paste, against the rule for that field rather than one rule for all of them, plus the lower limits a controller imposes on some kinds without saying so.
Most names are an RFC 1123 subdomain: 253 characters of lowercase letters, digits, hyphens and dots. A Namespace is an RFC 1123 label: 63 characters and no dots anywhere in it. A Service is an RFC 1035 label, which adds one restriction on top of that, a leading letter, so 1st-api names a Deployment and is rejected as a Service. Paste manifests and the kind is read from each document. Paste a bare list and write a line as service/api to get the exact rule.
Container names, init container names and volume names are all DNS labels, as is metadata.namespace, so my_app is a legal ConfigMap name and an illegal container name in the same file. A port name is a rule of its own, an IANA service name: 15 characters of lowercase letters, digits and hyphens, at least one letter, no two hyphens in a row and none at either end, which makes http-metrics-endpoint too long and 8080 wrong twice over, since YAML reads it as a number where the field is a string and there is no letter in it. All of them are read out of a Deployment, StatefulSet, DaemonSet or Job template, out of a CronJob's jobTemplate, out of a bare Pod, and off a Service's ports.
A CronJob stops at 52 because each run's Job is named after it plus the minutes since the epoch. A Job name is accepted at 253 and then copied into the job-name label on every pod, where 63 is the ceiling, so the Job sits at zero completions with the reason only in its events. A Deployment past 46 characters still runs, and its pod names stop containing the whole name because the generator truncates the base to 58. A DaemonSet is 57, a StatefulSet is 63 less the width of its highest ordinal, read from spec.replicas when the manifest states it, and a Pod past 63 keeps its name in kubectl and loses it in its own hostname.
The server truncates the base to 58 characters and appends 5 random ones, so base plus 5 characters is what has to be valid, and that is what gets checked, against the rule for the kind. A base ending in a hyphen passes, because 5 characters follow it, while the same string in metadata.name is rejected. A base of 1st- is fine on a Pod and a failure on a Service. An object carrying only generateName has no name to measure and the verdict says so, rather than putting a green tick over an empty table, and the generated sample is kept out of the table because it is not a name you wrote. The limits above are applied to the generated name as well, so a CronJob base of 55 characters is reported here exactly as the same string in metadata.name would be, and the fix names the budget the base has left rather than the budget the finished name has.
The usual paste has two problems together, a capital and an underscore, so all of them are reported with a caret under the character rather than one per round trip. A corrected form is offered only when it is mechanical and only after it has been validated: My_API becomes my-api. A Service name starting with a digit gets no suggestion, because prefixing or reordering it changes what the name means.
A name with no kind attached is checked against the subdomain rule and then told which kinds it would fail: a dot rules out a Service and a Namespace, a leading digit rules out a Service, 64 characters rules out a Service, a Namespace and a Job. If the YAML does not parse, every name: line is still checked and the report says the per-kind rules were skipped. What it cannot see either way: whether the name is already taken in that namespace, and whether anything else still points at the old one.
There is no single Kubernetes naming rule. The API server validates each field with one of a handful of functions, and which one it reaches for depends on the kind and the field rather than on anything visible in the manifest. When it refuses, it prints the regex at you. When a controller has quietly lowered the limit instead, it says nothing at all: the object is created and the thing it generates is what breaks.
These are the patterns the API server applies, quoted as it writes them. The only difference between the first two is the dot, and the only difference between the last two is that an RFC 1035 label has to begin with a letter. That is the whole of it, and it accounts for nearly every naming rejection.
RFC 1123 subdomain 253 characters
[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
RFC 1123 label 63 characters
[a-z0-9]([-a-z0-9]*[a-z0-9])?
RFC 1035 label 63 characters
[a-z]([-a-z0-9]*[a-z0-9])? The subdomain rule is the default and covers the great majority of objects, which is why most names feel unrestricted. The exceptions are the two that end up in DNS on their own: a Namespace name and a Service name both become a single DNS label. Inside a pod spec the label rule applies again, so the fields you write next to each other in one file are not held to the same standard.
RFC 1123 subdomain Deployment, ConfigMap, Secret,
Ingress, PVC, Job, CronJob, Pod, Node
RFC 1123 label Namespace, metadata.namespace,
container names, volume names
RFC 1035 label Service
IANA service name port names, 15 characters A dot is part of the subdomain alphabet and is not part of a label, so the same string is fine on a ConfigMap and refused on a Service. This is the one that catches people copying a hostname into a name field, and the message from the API server names the regex rather than the dot.
configmap/api.internal valid
secret/api.internal valid
service/api.internal rejected, position 4 is a dot
namespace/api.internal rejected, position 4 is a dot
a Service name is one DNS label, and there
are no dots inside a DNS label RFC 1035 requires a leading letter, and a Service name is the only place Kubernetes still applies it. So a Deployment called 1st-api applies cleanly and the Service in front of it does not, from the same file, in the same apply.
deployment/1st-api valid
service/1st-api rejected at position 1
no correction is suggested for this one: a
prefix or a reordering changes the name This is the half nothing warns about. The field accepts the name, the object is created, and a controller then builds another object's name out of it and runs out of room. A CronJob is the only one of these the API server enforces up front. The rest are silent, and two of them fail in a way that never mentions the name.
CronJob 52 run Job is <name>-<minutes since epoch>
enforced at apply time
Job 63 pods carry the name in the job-name
label, so the pods are rejected and
the Job sits at 0 completions
Deployment 46 pods are <name>-<hash>-<5 chars>, the
base is truncated to 58, so the pod
name stops containing the whole name
DaemonSet 57 pods are <name>-<5 chars>
StatefulSet 63 minus 1 minus the ordinal width, since
each pod name is a DNS label of its own
Pod 63 the hostname is the name, truncated The server truncates the base to 58 characters and appends 5 random ones, so the result is always 63 characters or fewer and always ends in a letter or a digit. What has to be valid is therefore the base plus 5 characters, not the base, and that is the string checked here against the rule for the kind. Three consequences you can see in the report: a base ending in a hyphen passes where the same string in metadata.name is rejected, a base starting with a digit passes on a Pod and fails on a Service, and the lower limit a controller imposes is measured against the generated name too, so a 55 character CronJob base is reported at the 60 characters it becomes. That last one is the hardest to catch by eye, because no length in the manifest says 60. There is also a trap that has nothing to do with validity, so it is reported on every generateName either way: kubectl apply needs a name to diff against and fails with "resource name may not be empty". kubectl create works, and so does a Job created from a CronJob.
generateName: worker- checked as worker-abcde
verdict No name to check, 1 note on this object
generateName: -bad checked as -badabcde
verdict No name to check, and 1 thing that will
still cause a failure
reason "-" cannot start a piece of the name
name: worker- rejected, "-" cannot end
a piece of the name
CronJob, 55 character base becomes 60 characters
verdict No name to check, and 1 thing that will
still cause a failure
reason past the 52 a CronJob really has
fix shorten the base to 47 or fewer
kubectl apply resource name may not be empty
kubectl create fine Kubernetes bounds a subdomain name at 253 in total and says nothing about the pieces between the dots. DNS bounds each piece at 63 octets. A name can therefore be created and then fail to resolve the moment anything turns it into a hostname, which is reported separately here because the object exists either way.
<64 characters>.example.com
total length 76, under the 253 limit
first piece 64 characters, over the DNS 63
accepted by the API server, unresolvable No object name allows an underscore, and three things sitting right next to object names do: a label value, a ConfigMap or Secret key, and an environment variable name. So the character is legal in most of a manifest and illegal in the one field people reach for first. Uppercase is the same story: legal in a label value, never in a name.
my_app as a container name rejected
my_app as a ConfigMap key valid
my_app as a label value valid
MY_APP as an env var name valid Only the text. It does not know whether the name is already taken in the namespace, since that needs the cluster, and it does not know what else references the name you are about to change: a Service selector, an Ingress backend, a PVC claimName, a kustomize patch. Those are the reason a rename is not free, and they are not visible in the file being checked. For full schema validation against a specific cluster version, kubeconform is the right tool.
checked the characters, the length, and the
rule for the field the name sits in
not checked uniqueness in the namespace
every other object naming this one