Skip to main content

Configure NodeLocal DNS Cache in a Managed Kubernetes cluster

To reduce the load on DNS in a Managed Kubernetes cluster and speed up response times from external and internal resources, you can use NodeLocal DNS Cache.

NodeLocal DNS Cache is a DNS query caching mechanism that runs on all Managed Kubernetes nodes and provides a local cache for the DNS resolver. When user pods send requests, they first pass through the local DNS cache. If these requests match previously saved records, additional requests to an external DNS server are avoided. This allows for reduced DNS request processing time and saves network traffic in the cluster.

Read more about NodeLocal DNS Cache in the Kubernetes documentation.

  1. Configure NodeLocal DNS Cache.
  2. Check the operation of NodeLocal DNS Cache.

Configure NodeLocal DNS Cache

  1. Create a nodelocaldns.yaml yaml file with the manifest:

    nodelocaldns.yaml file
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: node-local-dns
    namespace: kube-system
    labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: kube-dns-upstream
    namespace: kube-system
    labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "KubeDNSUpstream"
    spec:
    ports:
    - name: dns
    port: 53
    protocol: UDP
    targetPort: 53
    - name: dns-tcp
    port: 53
    protocol: TCP
    targetPort: 53
    selector:
    k8s-app: kube-dns
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: node-local-dns
    namespace: kube-system
    labels:
    addonmanager.kubernetes.io/mode: Reconcile
    data:
    Corefile: |
    cluster.local:53 {
    errors
    cache {
    success 9984 30
    denial 9984 5
    }
    reload
    loop
    bind 169.254.20.25 10.96.0.10
    forward . __PILLAR__CLUSTER__DNS__ {
    force_tcp
    }
    prometheus :9253
    health 169.254.20.25:8080
    }
    in-addr.arpa:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.25 10.96.0.10
    forward . __PILLAR__CLUSTER__DNS__ {
    force_tcp
    }
    prometheus :9253
    }
    ip6.arpa:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.25 10.96.0.10
    forward . __PILLAR__CLUSTER__DNS__ {
    force_tcp
    }
    prometheus :9253
    }
    .:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.25 10.96.0.10
    forward . __PILLAR__UPSTREAM__SERVERS__
    prometheus :9253
    }
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
    name: node-local-dns
    namespace: kube-system
    labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    spec:
    updateStrategy:
    rollingUpdate:
    maxUnavailable: 10%
    selector:
    matchLabels:
    k8s-app: kube-dns
    template:
    metadata:
    labels:
    k8s-app: kube-dns
    annotations:
    prometheus.io/port: "9253"
    prometheus.io/scrape: "true"
    spec:
    priorityClassName: system-node-critical
    serviceAccountName: node-local-dns
    hostNetwork: true
    dnsPolicy: Default # Do not use cluster DNS.
    tolerations:
    - key: "CriticalAddonsOnly"
    operator: "Exists"
    - effect: "NoExecute"
    operator: "Exists"
    - effect: "NoSchedule"
    operator: "Exists"
    containers:
    - name: node-cache
    image: registry.k8s.io/dns/k8s-dns-node-cache:1.22.20
    resources:
    requests:
    cpu: 25m
    memory: 5Mi
    args: [ "-localip", "169.254.20.25,10.96.0.10", "-conf", "/etc/Corefile", "-upstreamsvc", "kube-dns-upstream" ]
    securityContext:
    capabilities:
    add:
    - NET_ADMIN
    ports:
    - containerPort: 53
    name: dns
    protocol: UDP
    - containerPort: 53
    name: dns-tcp
    protocol: TCP
    - containerPort: 9253
    name: metrics
    protocol: TCP
    livenessProbe:
    httpGet:
    host: 169.254.20.25
    path: /health
    port: 8080
    initialDelaySeconds: 60
    timeoutSeconds: 5
    volumeMounts:
    - mountPath: /run/xtables.lock
    name: xtables-lock
    readOnly: false
    - name: config-volume
    mountPath: /etc/coredns
    - name: kube-dns-config
    mountPath: /etc/kube-dns
    volumes:
    - name: xtables-lock
    hostPath:
    path: /run/xtables.lock
    type: FileOrCreate
    - name: kube-dns-config
    configMap:
    name: kube-dns
    optional: true
    - name: config-volume
    configMap:
    name: node-local-dns
    items:
    - key: Corefile
    path: Corefile.base
  2. Apply the manifest:

    kubectl create -f nodelocaldns.yaml

    The list of created objects will appear in the response:

    serviceaccount/node-local-dns created
    service/kube-dns-upstream created
    configmap/node-local-dns created
    daemonset.apps/node-local-dns created

Check the operation of NodeLocal DNS Cache

  1. enable logging mode for NodeLocal DNS pods. In the nodelocaldns.yaml manifest, add the ConfigMap object line log:

    data:
    Corefile: |
    cluster.local:53 {
    log
    errors
    cache {
    success 9984 30
    denial 9984 5
    }
  2. Apply the manifest:

    kubectl apply -f nodelocaldns.yaml
  3. Start a pod with DNS testing utilities:

    kubectl apply -f https://k8s.io/examples/admin/dns/dnsutils.yaml

    The response will show confirmation that the pod has been created:

    pod/dnsutils created
  4. ensure the pod is in the Running status:

    kubectl get pods dnsutils
  5. Connect to the pod:

    kubectl exec -i -t dnsutils -- bash
  6. Execute a test domain request to the DNS server:

    dig @169.254.20.25 servercore.com

    The response will show that the request was successfully executed:

    ;; ANSWER SECTION:
    servercore.com. 30 IN A 85.119.149.3

    ;; Query time: 437 msec
    ;; SERVER: 169.254.20.25#53(169.254.20.25)
    ;; WHEN: Wed Sep 20 15:43:46 UTC 2023
    ;; MSG SIZE rcvd: 67
  7. Check the logs:

    kubectl logs --namespace=kube-system -l k8s-app=kube-dns -f

    in the response, A and AAAA DNS records with the NOERROR code:

    [INFO] 10.10.71.3:45929 - 55864 "A IN ru-2.cloud.api.selcloud.ru.kube-system.svc.cluster.local. udp 85 false 1232" NOERROR qr,aa,rd,ra 212 3.975488442s
    [INFO] 10.10.71.3:36099 - 21119 "AAAA IN ru-2.cloud.api.selcloud.ru.kube-system.svc.cluster.local. udp 85 false 1232" NOERROR qr,aa,rd 74 3.976010334s