Pod DNS policy in Kubernetes determines how pods resolve domain names.

Let’s see this in action. Imagine a pod that needs to talk to an external service, say api.example.com. By default, Kubernetes uses a cluster-wide DNS service, usually CoreDNS, to handle these lookups.

Here’s a simplified view of a pod.yaml that doesn’t specify a DNS policy:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app-container
    image: nginx

When my-app tries to resolve api.example.com, it will query the cluster’s CoreDNS service. CoreDNS, in turn, is configured to forward external DNS requests to upstream resolvers (like Google’s 8.8.8.8 or your cloud provider’s DNS).

The dnsPolicy field in a Pod’s spec controls this behavior. The most common policy is ClusterFirst.

apiVersion: v1
kind: Pod
metadata:
  name: my-app-clusterfirst
spec:
  containers:
  - name: app-container
    image: nginx
  dnsPolicy: ClusterFirst

With ClusterFirst, the pod first queries its cluster DNS service (CoreDNS). If the domain name isn’t found within the cluster’s DNS records (e.g., it’s not a service like my-service.my-namespace.svc.cluster.local), the request is then forwarded to the upstream nameservers configured for the node the pod is running on. This is the default behavior and what you get if you don’t specify dnsPolicy.

But what if you want a pod to only use the cluster DNS and never reach out to external resolvers? Or what if you want a pod to bypass cluster DNS entirely and use the node’s DNS directly? That’s where other policies come in.

The None policy is interesting. It tells Kubernetes to not configure DNS for the pod.

apiVersion: v1
kind: Pod
metadata:
  name: my-app-dns-none
spec:
  containers:
  - name: app-container
    image: nginx
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 1.1.1.1
      - 8.8.8.8
    searches:
      - my-namespace.svc.cluster.local
      - svc.cluster.local
    options:
      - name: ndots
        value: "2"

When dnsPolicy is None, the dnsConfig section becomes mandatory. You must explicitly define the nameservers, searches (search domains), and options for the pod. This gives you granular control, allowing you to, for example, point a pod directly at an external DNS server or a specific internal DNS server without involving CoreDNS at all.

Another policy is Default.

apiVersion: v1
kind: Pod
metadata:
  name: my-app-dns-default
spec:
  containers:
  - name: app-container
    image: nginx
  dnsPolicy: Default

This policy makes the pod inherit the DNS configuration of the node it’s running on. If the node is configured to use 1.1.1.1 for DNS, the pod will also use 1.1.1.1. This bypasses the cluster DNS entirely. It’s useful in scenarios where you have a specific node-level DNS setup you want pods to adhere to, or for testing.

The NoProxy policy is a bit of a niche case.

apiVersion: v1
kind: Pod
metadata:
  name: my-app-dns-noproxy
spec:
  containers:
  - name: app-container
    image: nginx
  dnsPolicy: NoProxy

With NoProxy, the pod still uses ClusterFirst as its base, meaning it will query CoreDNS first. However, if the DNS query is for a cluster-internal domain (like my-service.my-namespace.svc.cluster.local), it will not be forwarded to the node’s upstream resolvers. It effectively says "don’t try to resolve cluster services via external DNS, only use cluster DNS for those." For external domains, it behaves like ClusterFirst. This is rarely used directly, as ClusterFirst generally covers the desired behavior.

The ClusterFirstWithHostNet policy applies only to pods running with hostNetwork: true.

apiVersion: v1
kind: Pod
metadata:
  name: my-app-hostnet
spec:
  hostNetwork: true
  containers:
  - name: app-container
    image: nginx
  dnsPolicy: ClusterFirstWithHostNet

In this scenario, the pod shares the host’s network namespace. ClusterFirstWithHostNet ensures that cluster DNS is still queried for cluster-internal domains, but for external domains, it uses the host’s DNS resolver directly, bypassing the node’s resolv.conf in the traditional ClusterFirst forwarding mechanism.

The dnsConfig field is where you fine-tune resolution. The ndots option, for instance, is crucial. It specifies the threshold for adding the search domains. If the number of dots in a domain name is less than ndots, Kubernetes will append each entry in the searches list to the domain name and try to resolve it. For example, if ndots is 2 and you query my-service, Kubernetes will try my-service.my-namespace.svc.cluster.local, then my-service.svc.cluster.local, and finally my-service.cluster.local before giving up or forwarding. The default for ClusterFirst is typically 5.

When you set dnsPolicy to None and specify dnsConfig, you are essentially telling the pod to ignore all Kubernetes-provided DNS and use only what you’ve explicitly defined. This is powerful for isolating pods or directing them to very specific DNS infrastructure.

The searches list is populated automatically based on the namespace when dnsPolicy is ClusterFirst. For a pod in the default namespace, it might include default.svc.cluster.local, svc.cluster.local, and cluster.local. If the pod is in kube-system, it would include kube-system.svc.cluster.local, etc.

Understanding these policies allows you to manage how your pods perform name resolution, which is critical for network connectivity, service discovery, and security.

The next logical step is understanding how to configure the upstream DNS resolvers that CoreDNS itself uses.

Want structured learning?

Take the full Coredns course →