Skip to content

CoreDNS in Kubernetes

Overview

CoreDNS is the default DNS server in Kubernetes. It provides:

  • Service discovery via DNS
  • Pod DNS resolution
  • External DNS forwarding

CoreDNS Architecture

┌─────────────────────────────────────────────────────────────┐
│                       CoreDNS Pod                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Corefile (ConfigMap: coredns)                      │   │
│  │  ├── kubernetes plugin (cluster DNS)                │   │
│  │  ├── forward plugin (external DNS)                  │   │
│  │  └── other plugins (cache, loop, etc.)              │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘


              kube-dns Service (10.96.0.10:53)

           ┌───────────────┼───────────────┐
           ▼               ▼               ▼
        Pod DNS        Service DNS     External DNS

CoreDNS Components

ComponentLocation
Deploymentkube-system/coredns
ConfigMapkube-system/coredns
Servicekube-system/kube-dns
bash
# Check CoreDNS deployment
kubectl get deployment coredns -n kube-system

# Check CoreDNS pods
kubectl get pods -n kube-system -l k8s-app=kube-dns

# Check CoreDNS service
kubectl get svc kube-dns -n kube-system

CKA Focus: What to Change, How to Change, What Changes

What You Typically Change

ChangeWhereWhy it matters (CKA)
Upstream DNSforward plugin in CorefileFix external name resolution issues
Custom DNS entrieshosts or rewrite pluginMap hostnames for debugging or internal names
Cluster domainkubernetes plugin zoneRequired when cluster domain is not cluster.local
Caching behaviorcache pluginReduce latency or fix stale records
Pod resolution modepods setting in kubernetes pluginControls pod DNS record behavior

How to Change (Safe Flow)

  1. Edit the ConfigMap (Corefile).
  2. Ensure reload plugin exists (auto-reloads CoreDNS).
  3. Validate CoreDNS pods become Ready.
  4. Test DNS from a pod.
bash
# Edit the CoreDNS config
kubectl -n kube-system edit configmap coredns

# Or apply a YAML change
kubectl -n kube-system apply -f coredns.yaml

# If reload plugin is missing or you want to force it
kubectl -n kube-system rollout restart deployment coredns

# Validate pods
kubectl -n kube-system get pods -l k8s-app=kube-dns

What Changes When You Modify CoreDNS

ChangeImmediate effectHow to verify
Corefile editsReloaded in-place (if reload plugin present)kubectl logs -n kube-system deployment/coredns
Restart CoreDNSShort DNS outage (seconds)kubectl get pods -n kube-system
Forward target changeExternal name resolution changeskubectl exec ... -- nslookup google.com
Hosts entriesCluster DNS responses for that namekubectl exec ... -- nslookup custom.example.com

CKA-Style Checklist

  • Confirm DNS service IP: kubectl get svc kube-dns -n kube-system
  • Confirm CoreDNS endpoints: kubectl get endpoints kube-dns -n kube-system
  • Confirm pods Ready: kubectl get pods -n kube-system -l k8s-app=kube-dns
  • Test within a pod using nslookup or dig


DNS Records in Kubernetes

Service DNS Names

TypeFormat
ClusterIP<service>.<namespace>.svc.cluster.local
Headless<pod-name>.<service>.<namespace>.svc.cluster.local
Shorthand<service> (same namespace) or <service>.<namespace>

Examples:

bash
# Full FQDN
nginx-svc.default.svc.cluster.local

# Short form (same namespace)
nginx-svc

# Short form (different namespace)
nginx-svc.production

Pod DNS Names

ScenarioFormat
Default<pod-ip-dashed>.<namespace>.pod.cluster.local
Headless Service<pod-name>.<service>.<namespace>.svc.cluster.local
hostname/subdomain<hostname>.<subdomain>.<namespace>.svc.cluster.local

Example:

bash
# Pod IP: 10.244.1.5
10-244-1-5.default.pod.cluster.local

Corefile Configuration

The CoreDNS configuration is stored in ConfigMap:

bash
kubectl get configmap coredns -n kube-system -o yaml

Default Corefile

.:53 {
    errors
    health {
       lameduck 5s
    }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
       pods insecure
       fallthrough in-addr.arpa ip6.arpa
       ttl 30
    }
    prometheus :9153
    forward . /etc/resolv.conf {
       max_concurrent 1000
    }
    cache 30
    loop
    reload
    loadbalance
}

Corefile Plugins

PluginPurpose
errorsLog errors to stdout
healthHealth check endpoint (:8080/health)
readyReadiness endpoint (:8181/ready)
kubernetesServe DNS for cluster resources
prometheusMetrics endpoint (:9153/metrics)
forwardForward non-cluster DNS to upstream
cacheCache DNS responses
loopDetect forwarding loops
reloadAuto-reload Corefile changes
loadbalanceRound-robin A/AAAA records

Pod DNS Configuration

dnsPolicy Options

PolicyDescription
ClusterFirstUse CoreDNS, fallback to node DNS (default)
DefaultUse node's DNS settings
ClusterFirstWithHostNetFor hostNetwork pods
NoneUse custom dnsConfig only
yaml
apiVersion: v1
kind: Pod
metadata:
  name: dns-custom
spec:
  dnsPolicy: ClusterFirst  # default
  containers:
  - name: app
    image: nginx

Custom DNS Config

yaml
apiVersion: v1
kind: Pod
metadata:
  name: custom-dns
spec:
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
    - 8.8.8.8
    - 8.8.4.4
    searches:
    - my.dns.search.suffix
    options:
    - name: ndots
      value: "2"
  containers:
  - name: app
    image: nginx

Headless Service DNS

For StatefulSets with headless service:

yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
spec:
  clusterIP: None  # Headless
  selector:
    app: mysql
  ports:
  - port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-headless  # Links to headless service
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0

DNS records created:

mysql-0.mysql-headless.default.svc.cluster.local
mysql-1.mysql-headless.default.svc.cluster.local
mysql-2.mysql-headless.default.svc.cluster.local

Custom DNS Entries (Stub Domains)

Forward specific domains to custom DNS:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        # ... existing config ...
        forward . /etc/resolv.conf
    }
    # Custom domain
    example.com:53 {
        forward . 10.0.0.10
    }

Troubleshooting DNS

Test DNS from Pod

bash
# Run a debug pod
kubectl run dnsutils --image=registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3 --restart=Never -- sleep infinity

# Test DNS resolution
kubectl exec dnsutils -- nslookup kubernetes
kubectl exec dnsutils -- nslookup nginx-svc.default.svc.cluster.local

# Check /etc/resolv.conf
kubectl exec dnsutils -- cat /etc/resolv.conf

Check CoreDNS Logs

bash
kubectl logs -n kube-system -l k8s-app=kube-dns

Check CoreDNS Config

bash
kubectl get configmap coredns -n kube-system -o yaml

Common Issues

IssueCauseSolution
DNS not resolvingCoreDNS pods not runningCheck kubectl get pods -n kube-system
TimeoutNetwork policy blockingCheck NetworkPolicies
Wrong IP returnedStale cacheRestart CoreDNS pods
Pod can't resolve externalForward plugin misconfiguredCheck Corefile

DNS Debug Commands

bash
# Check if CoreDNS service exists
kubectl get svc kube-dns -n kube-system

# Check endpoints
kubectl get endpoints kube-dns -n kube-system

# Check pod resolv.conf
kubectl exec <pod> -- cat /etc/resolv.conf

# Full DNS test
kubectl run test --rm -it --image=busybox --restart=Never -- nslookup kubernetes.default

Modify CoreDNS

Add Custom Hosts

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        ready
        hosts {
            10.0.0.1 custom.example.com
            fallthrough
        }
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
        }
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }

Apply Changes

After modifying ConfigMap:

bash
# CoreDNS auto-reloads (reload plugin)
# Or restart pods
kubectl rollout restart deployment coredns -n kube-system

Useful Commands

bash
# Check CoreDNS status
kubectl get pods -n kube-system -l k8s-app=kube-dns

# View Corefile
kubectl get cm coredns -n kube-system -o jsonpath='{.data.Corefile}'

# Check DNS service IP
kubectl get svc kube-dns -n kube-system -o jsonpath='{.spec.clusterIP}'

# Test DNS resolution
kubectl run test --rm -it --image=busybox --restart=Never -- nslookup kubernetes

# Check CoreDNS logs
kubectl logs -n kube-system deployment/coredns

# Describe CoreDNS deployment
kubectl describe deployment coredns -n kube-system

Kubernetes DNS — Deep Dive Notes (CKA)

1) DNS Architecture (High-Level)

Core components

  • CoreDNS: Cluster DNS server
  • kubelet: Injects DNS config into Pods
  • Service / Endpoints / EndpointSlices: Source of truth for DNS records

Flow

Pod → /etc/resolv.conf → CoreDNS → API Server (watch) → Answer

2) Pod DNS Configuration

Typical /etc/resolv.conf

nameserver 10.96.0.10
search <ns>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Implications

  • Short names expand using search domains.
  • ndots:5 means names with < 5 dots are treated as relative.
  • FQDNs avoid search-path latency.

3) DNS Zones

ZonePurpose
cluster.localCluster root
svc.cluster.localServices
pod.cluster.localPod IP mapping

4) Service DNS (ClusterIP)

FQDN

<service>.<namespace>.svc.cluster.local

Resolution

  • DNS returns Service ClusterIP.
  • kube-proxy does load balancing to Pods.

Flow

Client → Service IP → kube-proxy → Pod

Key point: DNS does not know Pod IPs for ClusterIP services.


5) Headless Service DNS

Condition

spec:
  clusterIP: None

FQDN

<service>.<namespace>.svc.cluster.local

Resolution

  • DNS returns Pod IPs directly (A records).
  • No Service IP, no kube-proxy.

Flow

Client → DNS → Pod IP (client-side decision)

6) Pod DNS via Service (Stable Identity)

Required fields

spec:
  hostname: <pod-name>
  subdomain: <service-name>

FQDN

<pod>.<service>.<namespace>.svc.cluster.local

Resolution

  • DNS returns that Pod IP.
  • Name remains stable even if IP changes.

7) Pod IP DNS (IP-Based)

FQDN

<ip-with-dashes>.<namespace>.pod.cluster.local

Example

1-2-3-4.kube-system.pod.cluster.local → 1.2.3.4

Characteristics

  • DNS-only transformation.
  • Rare in production, but tested in CKA/CKS.

8) EndpointSlices and DNS

CoreDNS watches:

  • Services
  • EndpointSlices (preferred)
  • Endpoints (legacy)
  • Pods (for Pod DNS)

Mapping

  • ClusterIP Service → ClusterIP
  • Headless Service → EndpointSlice addresses
  • Pod DNS → Pod metadata

9) SRV Records (Named Ports)

_<port-name>._<protocol>.<service>.<namespace>.svc.cluster.local

Example

_http._tcp.department.lima-workload.svc.cluster.local

Returns port + target hostname, used by service discovery-aware apps.


10) Failure Modes & Debugging

Commands

nslookup <fqdn>
dig <fqdn>
kubectl get svc
kubectl get endpointslice
kubectl describe svc

Common issues

  • Service selector mismatch
  • No endpoints (DNS exists, but no A records)
  • Wrong namespace
  • Missing hostname/subdomain for Pod DNS

11) CoreDNS — Deep Dive

What it is

  • DNS server in Go
  • Deployment (usually 2 replicas)
  • Runs in kube-system

Data sources: Watches Services, EndpointSlices, Pods, Namespaces (event-driven).

Typical Corefile

.:53 {
    errors
    health
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
    }
    forward . /etc/resolv.conf
    cache 30
    loop
    reload
}

pods insecure meaning

Allows *.pod.cluster.local without verifying Pod existence.


12) DNS Resolution Decision Tree (Mental Model)

Is it *.svc.cluster.local?
 ├─ Service with ClusterIP → Service IP
 └─ Service with clusterIP: None → Pod IPs

Is it <pod>.<svc>.<ns>.svc.cluster.local?
 └─ Pod hostname + subdomain → Pod IP

Is it *.pod.cluster.local?
 └─ IP reconstruction → Literal IP

13) CKA Exam Cheat Sheet

  • Prefer FQDN in tests.
  • Headless Service → Pod IPs.
  • Service DNS → Service IP.
  • Stable Pod DNS → hostname + subdomain.
  • .pod.cluster.localDNS-only IP mapping.
  • CoreDNS is the primary DNS component to debug.

14) Key Takeaway

Kubernetes DNS is data-driven:

  • CoreDNS answers using API objects.
  • Services abstract Pods unless headless.
  • Pod identity is opt-in.
  • kube-proxy is only involved for Service IPs.

Released under the MIT License.