🏷️ 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