CoreDNS provides in-cluster DNS for every pod in your cluster. It runs as a Deployment in `kube-system` behind the `kube-dns` service, resolving cluster-internal queries and forwarding external requests to upstream resolvers. This page explains how CoreDNS resolves names, how to resolve private names through your own resolvers, why the API endpoint name must resolve publicly, how `ndots` lookups impact query performance, and how Syself Autopilot manages and scales the deployment. For CoreDNS itself, see the [CoreDNS docs](https://coredns.io/manual/toc/). ## In-cluster resolution and forwarding CoreDNS answers two kinds of in-cluster names: - **Service names.** `my-svc.my-namespace.svc.cluster.local` resolves to the Service's cluster IP. `cluster.local` is the cluster's DNS suffix, set by `serviceDomain` when the cluster is created. The full naming scheme is in the [Kubernetes DNS for Services and Pods](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) reference. - **Pod-backed names.** A headless Service (`clusterIP: None`) resolves to the individual pod IPs behind it, which is how StatefulSets get stable per-pod names. Any query outside the cluster domain such as a public endpoint or internal network address is forwarded to the node's upstream resolver. You configure these resolvers using the `dnsServers` cluster variable. It sets the node's resolver and the kubelet's resolver file, which CoreDNS inherits. ## Resolve private names through the cluster's upstream To resolve private hostnames, such as on-premises databases or VPC resources, set `dnsServers` on the `Cluster` object to your internal name servers: ```yaml vars title="cluster.yaml" spec: topology: variables: - name: dnsServers value: ["10.100.0.53"] ``` Because CoreDNS is managed by Syself Autopilot, per-zone techniques that require a Corefile edit, such as a stub-domain `forward` block for one internal zone, are not available. All non-cluster DNS traffic routes through the servers in `dnsServers`. Point `dnsServers` at a DNS resolver that can serve both internal and external zones such as an on-premises nameserver reached over your VPN. See [Connect to on-prem or another VPC](/docs/hetzner/apalla/network/egress/connect-to-on-prem-or-vpc). This resolver must answer queries for your private domains directly and recursively forward all other requests to the public internet. ## The API endpoint must resolve publicly The cluster's API endpoint name is where split DNS matters most. That name must resolve to the control-plane load balancer from **Syself's side**, not only from your own machine, because the controllers that manage your cluster connect through the same name. > [!WARNING] > Never give the API endpoint a name that only you can resolve, an `/etc/hosts` entry, or a split-horizon view that answers differently inside your own network. If the name does not resolve to the load balancer from the management side, the cluster never finishes provisioning and the control plane remains unavailable. Publish a real, public `A` record for the endpoint name. See [Serve IPv6 clients](/docs/hetzner/apalla/network/load-balancing/serve-ipv6) for the endpoint DNS setup. Restricting who may reach the API is a separate concern from resolving its name; that is the allowlist's responsibility, not DNS's. See [KubeGate: restrict API server access](/docs/hetzner/apalla/security/restrict-api-server-access). ## How ndots affects lookup performance By default, Kubernetes configures `/etc/resolv.conf` inside pods with `ndots: 5`. If a queried domain contains fewer than five dots, the resolver appends each local search domain (`.svc.cluster.local`, `svc.cluster.local`, `cluster.local`) before attempting the name as written. Looking up an external endpoint such as `api.example.com` (which has only two dots) therefore sends `api.example.com..svc.cluster.local`, `api.example.com.svc.cluster.local`, and `api.example.com.cluster.local` first, each returning NXDOMAIN, before the resolver finally queries `api.example.com` against upstream DNS. To eliminate this query overhead on high-throughput workloads, configure the pod specification directly: - **Use fully qualified domain names (FQDN):** Append a trailing dot (`api.example.com.`) to external names to bypass the search list. - **Lower `ndots`:** Set a custom `ndots` value (for example, `ndots: 2`) in the pod's [`dnsConfig`](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config). ## How Syself scales CoreDNS CoreDNS sits on the path of nearly every connection, so its replica count must grow with the cluster. Syself Autopilot runs the [cluster-proportional-autoscaler](https://github.com/kubernetes-sigs/cluster-proportional-autoscaler) against the CoreDNS Deployment and sizes it from the cluster's node and core counts: | Setting | Value | Effect | | --------------------------- | ----- | ----------------------------------------------------------- | | `nodesPerReplica` | 8 | one CoreDNS replica for every 8 nodes | | `coresPerReplica` | 256 | one replica for every 256 vCPUs across the cluster | | `preventSinglePointFailure` | true | at least 2 replicas once the cluster has more than one node | The autoscaler takes the higher of the node-based and core-based counts, so CoreDNS scales up as you add nodes and back down as you remove them. You do not set a replica count, and you do not edit the Corefile. Both are reconciled by the platform, and a manual change is overwritten on the next reconciliation. ## Where to go next - [Automate DNS records with external-dns](/docs/hetzner/apalla/network/dns-certs/automatic-dns-with-external-dns) - [Diagnose pod DNS resolution](/docs/hetzner/apalla/network/debug/diagnose-pod-dns-resolution)