🏷️ Understand and use CoreDNS

🏷️ Understand and use CoreDNS#

CoreDNS

Kubernetes DNS resolution enables services and pods to communicate using human-readable names instead of IP addresses, simplifying networking in a dynamic environment where IP addresses frequently change. The system uses CoreDNS as the default DNS server, which is deployed as a set of pods in the kube-system namespace and handles all internal name resolution within the cluster. CoreDNS listens on port 53 and is responsible for translating service names into their corresponding ClusterIP addresses.

When a pod needs to resolve a service name, it first sends a DNS query to its local DNS resolver, which is configured via the /etc/resolv.conf file provisioned by the Kubelet. This file typically contains a nameserver entry pointing to the CoreDNS service IP (e.g., 10.10.0.10) and a list of search domains, such as default.svc.cluster.local, svc.cluster.local, and cluster.local. The default domain for the cluster is cluster.local, which is automatically appended to unqualified names to form a fully qualified domain name (FQDN).

For a service named my-service in the default namespace, the full DNS name is my-service.default.svc.cluster.local. When a pod performs a DNS lookup for my-service, the resolver first attempts to resolve it using the search paths: my-service.default.svc.cluster.local, then my-service.svc.cluster.local, and finally my-service.cluster.local. The ndots:5 option in the resolv.conf file determines when the search list is used; if a name contains fewer than five dots, the search domains are appended before a direct query is made.

Check DNS resolution#

 cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nettools
  labels:
    app: nettools
spec:
  containers:
  - name: nettools
    image: ubuntu
    command: [ "sleep" ]
    args: [ "infinity" ]
EOF

Check internal DNS resolution.

 kb exec -ti nettools -- bash
root@nettools:/# apt update && apt install dnsutils -y
# View DNS resolver configuration
root@nettools:/# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local guisam.lan
nameserver 10.96.0.10
options ndots:5
# Check that the responding DNS resolver server is indeed `10.96.0.10`
root@nettools:/# dig +noall +identify
;; Received 443 bytes from 10.96.0.10#53(10.96.0.10) in 7 ms

# Get the FQDN of DNS resolver server
root@nettools:/# dig -x 10.96.0.10 +noall +answer
10.0.96.10.in-addr.arpa. 30     IN      PTR     kube-dns.kube-system.svc.cluster.local.
# Check resolution to access a od in another namespace
root@nettools:/# curl -sI service-lab.low.svc.cluster.local. | awk 'NR==1'
HTTP/1.1 200 OK
root@nettools:/# curl -sI service-lab.low | awk 'NR==1'
HTTP/1.1 200 OK

Check kube-dns resources.

# Check kube-dns service kb get svc kube-dns -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   6d22h
# Get kube-dns service labels kb get svc kube-dns -n kube-system \
-o jsonpath='{.metadata.labels}' | jq
{
  "k8s-app": "kube-dns",
  "kubernetes.io/cluster-service": "true",
  "kubernetes.io/name": "CoreDNS"
}
# Get all resources labelled 'k8s-app:kube-dns' kb get all -l k8s-app=kube-dns -A
NAMESPACE     NAME                           READY   STATUS    RESTARTS      AGE
kube-system   pod/coredns-7669c76757-d2sqh   1/1     Running   1 (18m ago)   16h
kube-system   pod/coredns-7669c76757-g5clp   1/1     Running   1 (18m ago)   16h

NAMESPACE     NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-system   service/kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   6d22h

NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   2/2     2            2           6d22h

NAMESPACE     NAME                                 DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-66bc5c9577   0         0         0       6d21h
kube-system   replicaset.apps/coredns-674b8bbfcf   0         0         0       6d22h
kube-system   replicaset.apps/coredns-6d8c5bcbcd   0         0         0       17h
kube-system   replicaset.apps/coredns-7669c76757   2         2         2       16h

Find and check CoreDNS configuration.

# Get coredns mounted volumes kb get deploy coredns -n kube-system \
-o jsonpath='{.spec.template.spec.containers[].volumeMounts[]}' \
| jq
{
  "mountPath": "/etc/coredns",
  "name": "config-volume",
  "readOnly": true
}
# Find coredns configmap kb get deploy coredns -n kube-system \
-o jsonpath='{.spec.template.spec.volumes[]}' \
| jq
{
  "configMap": {
    "defaultMode": 420,
    "items": [
      {
        "key": "Corefile",
        "path": "Corefile"
      }
    ],
    "name": "coredns"
  },
  "name": "config-volume"
}
# Get coredns configmap kb get cm -n kube-system coredns -o jsonpath='{.data.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 {
       disable success cluster.local
       disable denial cluster.local
    }
    loop
    reload
    loadbalance
}

Update CoreDNS configuration to add a domain.

 kb edit cm -n kube-system coredns
ᐅ kb get cm -n kube-system coredns -o jsonpath='{.data.Corefile}' \
| awk 'NR<7'
.:53 {
    rewrite stop {
      name regex (.*)\.guisam\.io {1}.default.svc.cluster.local
      answer name (.*)\.default\.svc\.cluster\.local {1}.guisam.io
      }
    errors
ᐅ kb rollout restart deploy coredns -n kube-system
 kb exec -ti nettools -- bash
root@nettools:/# dig service-lab.default.svc.cluster.local +noall +answer
service-lab.default.svc.cluster.local. 30 IN A  10.103.93.171
root@nettools:/# dig service-lab.guisam.io +noall +answer
service-lab.guisam.io.  30      IN      A       10.103.93.171