COREDNS-KUBERNETES(7)
π COREDNS-KUBERNETES(7) π
ok bestie, welcome to the coredns-kubernetes manual page β this is the CoreDNS Plugins one, page COREDNS-KUBERNETES(7), and it's genuinely a lot, so grab a lil snack π. It's giving "big manpage energy" and honestly? we're gonna get through it together. no cap.
πΈ NAME πΈ
kubernetes β enables reading zone data from a Kubernetes cluster. that's the whole vibe. it reads zones, from k8s. iconic behavior honestly π
β¨ DESCRIPTION β¨
so this plugin implements the Kubernetes DNS-Based Service Discovery Specification β literally this spec right here: β¨https://github.com/kubernetes/dns/blob/master/docs/specification.mdβ© π¦
CoreDNS running the kubernetes plugin can be used as a replacement for kube-dns in a kubernetes cluster. yes, like the replacement. main character energy fr. if you wanna know how to actually deploy CoreDNS in Kubernetes, the deployment repo has you covered β see β¨https://github.com/coredns/deploymentβ© and more specifically β¨https://github.com/coredns/deployment/tree/master/kubernetesβ© π
and listen β stubDomains and upstreamNameservers β¨https://kubernetes.io/blog/2017/04/configuring-private-dns-zones-upstream-nameservers-kubernetes/β© are implemented via the forward plugin. the examples further down show you exactly how. iykyk π
π important vibe check: this plugin can only be used once per Server Block. one. singular. don't try it twice, she will not allow it.
π¦ SYNTAX π¦
kubernetes [ZONES...]
if you specify only the plugin (no args, no nothing), the kubernetes plugin will default to the zone specified in the server's block. it'll handle all queries in that zone and connect to Kubernetes in-cluster. it will not provide PTR records for services, and it will not provide A records for pods. just so we're clear on the defaults β¨
if *ZONES* is used, it specifies all the zones the plugin should be authoritative for.
kubernetes [ZONES...] {
endpoint URL
tls CERT KEY CACERT
kubeconfig KUBECONFIG [CONTEXT]
apiserver_qps QPS
apiserver_burst BURST
apiserver_max_inflight MAX
namespaces NAMESPACE...
labels EXPRESSION
pods POD-MODE
endpoint_pod_names
ttl TTL
noendpoints
fallthrough [ZONES...]
ignore empty_service
multicluster [ZONES...]
startup_timeout DURATION
}
endpointβ specifies theURLfor a remote k8s API endpoint. if you omit it, she connects to k8s in-cluster using the cluster service account. needstlsfor clusters with authentication. β οΈ this option is ignored ifkubeconfigis set.tlsCERTKEYCACERTβ these are the TLS cert, key and CA cert file names for a remote k8s connection. π this option is ignored if you're connecting in-cluster (i.e.endpointis not specified).kubeconfigKUBECONFIG[CONTEXT] β authenticates the connection to a remote k8s cluster using a kubeconfig file. [CONTEXT] is optional β if it's not set, then the current context specified inkubeconfigwill be used. it supports TLS, username and password, or token-based authentication. this option is ignored if omitted. π«Ά and note: the cluster address in thekubeconfigis given preference.apiserver_qpsQPSβ sets the maximum queries per second (QPS) rate limit for requests. this lets you control the rate at which the plugin sends requests to the API server so you don't, like, overwhelm it π nobody wants that.apiserver_burstBURSTβ sets the maximum burst size for requests. this allows temporary spikes in request rate up to this value, even if it exceeds the QPS limit. lil treat for your traffic spikes πapiserver_max_inflightMAXβ sets the maximum number of concurrent in-flight requests. this caps the total number of simultaneous requests the plugin can make to the API server. total adult behavior.namespacesNAMESPACE[NAMESPACE...] β only exposes the k8s namespaces listed. if this option is omitted, all namespaces are exposed. generous queen πnamespace_labelsEXPRESSIONβ only expose the records for Kubernetes namespaces that match this label selector. the label selector syntax is described in the Kubernetes User Guide - Labels β¨https://kubernetes.io/docs/user-guide/labels/β©. an example that only exposes namespaces labeled as"istio-injection=enabled", would use:labels istio-injection=enabled. (yes, that's what it says β copy it as written π)labelsEXPRESSIONβ only exposes the records for Kubernetes objects that match this label selector. the label selector syntax is described in the Kubernetes User Guide - Labels β¨https://kubernetes.io/docs/user-guide/labels/β©. an example that only exposes objects labeled as"application=nginx"in the"staging"or"qa"environments, would use:labels environment in (staging, qa),application=nginx. slay, filtered β¨podsPOD-MODEβ sets the mode for handling IP-based pod A records, e.g.1-2-3-4.ns.pod.cluster.local. in A 1.2.3.4. this option is provided to facilitate use of SSL certs when connecting directly to pods. valid values forPOD-MODE:disabled: Default. do not process pod requests, always returningNXDOMAIN. πinsecure: always return an A record with IP from request (without checking k8s). β οΈ this option is vulnerable to abuse if used maliciously in conjunction with wildcard SSL certs. this option is provided for backward compatibility withkube-dns.verified: return an A record if there exists a pod in same namespace with matching IP. this option requires substantially more memory than ininsecuremode, since it will maintain a watch on all pods. π«Ά highkey the careful one.
endpoint_pod_namesβ uses the pod name of the pod targeted by the endpoint as the endpoint name in A records, e.g.,endpoint-name.my-service.namespace.svc.cluster.local. in A 1.2.3.4. by default, theendpoint-namename selection is as follows: use the hostname of the endpoint, or if hostname is not set, use the dashed form of the endpoint IP address (e.g.,1-2-3-4.my-service.namespace.svc.cluster.local.). if this directive is included, then name selection for endpoints changes as follows: use the hostname of the endpoint, or if hostname is not set, use the pod name of the pod targeted by the endpoint. if there is no pod targeted by the endpoint or pod name is longer than63, use the dashed IP address form. lots of rules but likeβ¦ consistent rules πttlβ allows you to set a custom TTL for responses. the default is5seconds. the minimum TTL allowed is0seconds, and the maximum is capped at3600seconds. setting TTL to0will prevent records from being cached π (yes, deliberately).noendpointsβ will turn off the serving of endpoint records by disabling the watch on endpoints. all endpoint queries and headless service queries will result in anNXDOMAIN. π₯²fallthrough[ZONES...] β if a query for a record in the zones for which the plugin is authoritative results inNXDOMAIN, normally that is what the response will be. however, if you specify this option, the query will instead be passed on down the plugin chain, which can include another plugin to handle the query. if [ZONES...] is omitted, then fallthrough happens for all zones for which the plugin is authoritative. if specific zones are listed (for examplein-addr.arpaandip6.arpa), then only queries for those zones will be subject to fallthrough. so specific, so chic β¨ignore empty_serviceβ returnsNXDOMAINfor services without any ready endpoint addresses (e.g., ready pods). this allows the querying pod to continue searching for the service in the search path. the search path could, for example, include another Kubernetes cluster. π₯multicluster[ZONES...] β defines the multicluster zones as defined by Multi-Cluster Services API (MCS-API). specifying this option is generally paired with the installation of an MCS-API implementation and theServiceImportandServiceExportCRDs. β οΈ the plugin MUST be authoritative for the zones listed here.startup_timeoutDURATIONβ specifies theDURATIONvalue that limits the time to wait for informer cache synced when the kubernetes plugin starts. if not specified, the default timeout will be5s. β°
enabling zone transfer is done by using the transfer plugin. π§
π STARTUP π
when CoreDNS starts with the kubernetes plugin enabled, it will delay serving DNS for up to 5 seconds until it can connect to the Kubernetes API and synchronize all object watches. π΄ if this cannot happen within 5 seconds, then CoreDNS will start serving DNS while the kubernetes plugin continues to try to connect and synchronize all object watches. CoreDNS will answer SERVFAIL to any request made for a Kubernetes record that has not yet been synchronized. π so if you see SERVFAILs on startup, that's literally why.
you can also determine how long to wait by specifying startup_timeout. your rules, your timeline π«Ά
π¦ MONITORING KUBERNETES ENDPOINTS π¦
the kubernetes plugin watches Endpoints via the discovery.EndpointSlices API. that's the whole section. she's short but she ate π
β READY β
this plugin reports readiness to the ready plugin. this will happen after it has synced to the Kubernetes API. so if ready says not ready, it's not being shady, it's just still syncing π
π PTR RECORDS π
this plugin creates PTR records for every Pod selected by a Service. and here's the twist: if a given Pod is selected by more than one Service, a separate PTR record will exist for each Service selecting it. so yes, multiple records. one per Service. no merging happening here, bestie π
π EXAMPLES π
ok this is the part where it gets fun.
handle all queries in the cluster.local zone. connect to Kubernetes in-cluster. also handle all in-addr.arpa PTR requests for 10.0.0.0/17. verify the existence of pods when answering pod requests.
10.0.0.0/17 cluster.local {
kubernetes {
pods verified
}
}
or you can selectively expose some namespaces:
kubernetes cluster.local {
namespaces test staging
}
connect to Kubernetes with CoreDNS running outside the cluster:
kubernetes cluster.local {
endpoint https://k8s-endpoint:8443
tls cert key cacert
}
configure multicluster:
kubernetes cluster.local clusterset.local {
multicluster clusterset.local
}
ok periodt, those are the examples β¨
π§ STUBDOMAINS AND UPSTREAMNAMESERVERS π§
here we use the forward plugin to implement a stubDomain that forwards example.local to the nameserver 10.100.0.10:53. also configured is an upstreamNameserver 8.8.8.8:53 that will be used for resolving names that do not fall in cluster.local or example.local. cute, right? π¦
cluster.local:53 {
kubernetes cluster.local
}
example.local {
forward . 10.100.0.10:53
}
. {
forward . 8.8.8.8:53
}
the configuration above represents the following Kube-DNS stubDomains and upstreamNameservers configuration:
stubDomains: |
{βexample.localβ: [β10.100.0.10:53β]}
upstreamNameservers: |
[β8.8.8.8:53β]
(yes those are curly quotes in there, that's how it's written, don't come for me π)
β¨ AUTOPATH β¨
Okay bestie, so the kubernetes plugin can team up with the autopath plugin and honestly? it's giving power duo. Turning this on unlocks server-side domain search path completion in Kubernetes clusters β like, the server does the search-path glow-up for you instead of making the client do all that work. π
β οΈ But listen β pods must be set to verified for this to function properly. No cap. And on top of that: the remote IP address in the DNS packet that CoreDNS receives has to literally be the IP address of the Pod that sent the request. Both things. Not optional. π
cluster.local {
autopath @kubernetes
kubernetes {
pods verified
}
}
π METADATA π
If the metadata plugin is also enabled, the kubernetes plugin will publish the following metadata for you. It's a whole little info drop:
kubernetes/endpointβ the endpoint name in the querykubernetes/kindβ the resource kind (podorsvc) in the querykubernetes/namespaceβ the namespace in the querykubernetes/port-nameβ the port name in an SRV querykubernetes/protocolβ the protocol in an SRV querykubernetes/serviceβ the service name in the querykubernetes/client-namespaceβ the client pod's namespace (there are requirements below, keep reading π)kubernetes/client-pod-nameβ the client pod's name (same, requirements below)kubernetes/client-label/<label key>β a label on the client pod (yep, requirements below)
So here's the vibe with those last three β kubernetes/client-namespace, kubernetes/client-pod-name, and kubernetes/client-label/<label key> β they work by reconciling the client IP address in the DNS request packet to a known pod IP address. Which means, sadly, you need all of this:
pods verifiedmode must be enabled- the remote IP address in the DNS packet received by CoreDNS must be the IP address of the Pod that sent the request
That's it. That's the whole requirement list. But it's required required. π«Ά
π₯ METRICS π₯
If monitoring is enabled (via the prometheus plugin, iykyk) then these metrics get exported for you:
coredns_kubernetes_dns_programming_duration_seconds{service_kind}β exports the DNS programming latency SLI. This metric has theservice_kindlabel, which identifies the kind of the kubernetes service. It may take one of three values:cluster_ipheadless_with_selectorheadless_without_selector
Then we've got the client-level metrics, and these ones are all about monitoring apiserver request latency & status codes. Quick vocab check: verb identifies the apiserver request type, and host denotes the apiserver endpoint. Slay, now the list:
coredns_kubernetes_rest_client_request_duration_seconds{verb, host}β captures apiserver request latency perceived by client, grouped byverbandhost.coredns_kubernetes_rest_client_rate_limiter_duration_seconds{verb, host}β captures apiserver request latency contributed by client side rate limiter, grouped byverb&host.coredns_kubernetes_rest_client_requests_total{method, code, host}β captures total apiserver requests, grouped bymethod,status_code&host.
Obsessed with a well-labeled metric, honestly. ππ
π BUGS π
Not me having to tell you this, but: the duration metric does not yet support the headless_without_selector service kind. That's the whole bug. It's fine. We're fine. π
π SEE ALSO π
Peep the autopath plugin if you wanna enable search path optimizations. And use the transfer plugin to enable outgoing zone transfers. Go forth and configure, bestie. π¦
That's the whole page, babes β sourced from CoreDNS, dated October 2026, filed under COREDNS-KUBERNETES(7). Now go forth and resolve some names, you absolute main character. ππβ¨
π¦ where this page comes from
- opensuse-leap 16.0: coredns-extras 1.15.0-bp160.1.1 Β· Apache-2.0 AND MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms