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.

The setup and verification process for NodeLocal DNS Cache depends on the CNI (Container Network Interface) plugin used in the cluster: Calico or Cilium. You can check the CNI plugin in the cluster in the control panel: in the top menu, click ProductsManaged Kubernetes → cluster page → Settings tab → CNI.

  1. Configure NodeLocal DNS Cache.
  2. Verify NodeLocal DNS Cache operation.

1. Configure NodeLocal DNS Cache

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

    Файл nodelocaldns.yaml
    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 apply -f nodelocaldns.yaml

    The response will show a list of the created objects:

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

2. Verify NodeLocal DNS Cache operation

  1. Enable logging for NodeLocal DNS pods. To do this, in the nodelocaldns.yaml manifest, add the ConfigMap object, add the 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. Run a pod with DNS troubleshooting utilities:

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

    The response will confirm that the pod has been created:

    pod/dnsutils created
  4. Make sure the pod status is Running:

    kubectl get pods dnsutils
  5. Connect to the pod:

    kubectl exec -i -t dnsutils -- bash
  6. Run a test query to the DNS server:

    dig @169.254.20.25 servercore.com

    The response will show that the query was successful:

    ;; 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

    The response will show A and AAAA DNS records with the code NOERROR:

    [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