Skip to content

NodeLocalDNS#

NodeLocalDNS runs a local DNS caching agent on each node in the MKE cluster, improving performance by caching DNS responses locally and reducing latency compared to resolving external DNS records through a centralized CoreDNS service.

NodeLocalDNS is supported on both the iptables dataplane and the Calico eBPF dataplane. The configuration is the same for both, though the way DNS queries reach the local cache differs, as do the operational characteristics. Refer to NodeLocalDNS on the Calico eBPF dataplane for more information.

NodeLocalDNS network requirements#

NodeLocalDNS requires the Calico CNI provider. The supported combinations of CNI provider and kube-proxy configuration are detiled below:

CNI provider kube-proxy Supported
Calico, iptables dataplane Enabled, iptables mode Yes
Calico, eBPF dataplane Disabled, or enabled in iptables mode Yes
Calico, iptables dataplane Disabled No
Calico, any dataplane Enabled, ipvs, nftables, or userspace mode No
Any provider other than Calico Any No

Configurations that are not supported are rejected by mkectl and by the MKE admission webhooks, with one of the following messages:

  • NodeLocalDNS is only supported when CNI provider is Calico
  • NodeLocalDNS requires kube-proxy to be enabled, unless Calico runs the eBPF dataplane (linuxDataplane: BPF)
  • NodeLocalDNS is only supported when kube-proxy runs in the Iptables mode

In addition, MKE rejects the configuration if an instance of NodeLocalDNS that MKE does not manage is already present in the cluster.

Note

Support for NodeLocalDNS with the Calico eBPF dataplane is available in MKE 4.2.1 and later, and only for parent and standalone clusters. The Calico eBPF dataplane is not supported on child clusters.

NodeLocalDNS Configuration#

NodeLocalDNS is configured through the spec.nodeLocalDNS section of the mke4.yaml configuration file. The function is disabled by default, and thus to enable NodeLocalDNS, you must set the spec.nodeLocalDNS.enabled parameter to true.

NodeLocalDNS example configuration:

nodeLocalDNS:
    enabled: false
    nodeLocalConfigPersist: false
    resources:
      requests: {}
Parameter                                    Description                                    Default Equivalent MKE 3 parameter
enabled Enables the NodeLocalDNS service in the cluster.

Valid values: true, false
false [cluster_config.node_local_dns]
nodeLocalConfigPersist Retains the NodeLocalDNS configmap. false [cluster_config.node_local_dns_config_persist]
resources.requests.cpu Specifies the minimum CPU to guarantee for the NodeLocalDNS container. 25m N/A
resources.requests.memory Specifies the minimum memory to guarantee for the NodeLocalDNS container. 5Mi N/A

The address that the local cache serves is the kube-dns ClusterIP, which MKE derives from the cluster service CIDR set in spec.network.serviceCIDR. On a cluster that uses the default service CIDR, 10.96.0.0/12, the derived address is 10.96.0.10. There is no configuration parameter for this address.

To configure NodeLocalDNS:

  1. Obtain the default mke4.yaml configuration file:

    mkectl init
    
  2. In the mke4.yaml configuration file, add the nodeLocalDNS section under spec and set the enabled parameter to true, as nodelocalDNS is disabled by default.

  3. Apply the configuration:

    mkectl apply -f mke4.yaml
    
  4. Verify the successful deployment of NodeLocalDNS in the cluster:

    kubectl get all,configmap -n kube-system | grep node
    

    Example output:

    pod/node-local-dns-7z5k9              1/1     Running   0          4m23s
    pod/node-local-dns-8wgzc              1/1     Running   0          4m23s
    pod/node-local-dns-xnr7q              1/1     Running   0          4m23s
    service/node-local-dns                                       ClusterIP   None            <none>        9253/TCP                       4m24s
    daemonset.apps/node-local-dns   3         3         3       3            3           kubernetes.io/os=linux   4m24s
    configmap/node-local-dns                                         1      4m47s
    

NodeLocalDNS on the Calico eBPF dataplane#

On the iptables dataplane, kube-proxy programs the rules that send pod DNS queries for the kube-dns ClusterIP to the local cache on the node. The Calico eBPF dataplane has no kube-proxy, and connect-time load balancing resolves the kube-dns ClusterIP at the socket layer, so the queries never reach the local cache.

To make interception work, the kube-dns ClusterIP must be excluded from eBPF NAT, through the Calico Felix bpfExcludeCIDRsFromNAT setting. MKE manages this exclusion for you, adding the address when NodeLocalDNS is enabled and removing it when NodeLocalDNS is disabled. For background information, refer to the Tigera article, Optimizing Kubernetes DNS with NodeLocal DNSCache and Calico eBPF.

Warning

Do not manually add or remove the kube-dns ClusterIP in bpfExcludeCIDRsFromNAT. MKE sequences this exclusion against the node-local-dns DaemonSet. If the exclusion is in place while the local cache is not serving, DNS queries to the kube-dns ClusterIP have no destination and cluster DNS fails.

Enable NodeLocalDNS on an eBPF cluster#

You enable NodeLocalDNS the same way as on any other cluster, as described in NodeLocalDNS Configuration. Set spec.nodeLocalDNS.enabled to true in the mke4.yaml configuration file and run the mkectl apply command. No Calico or Felix configuration is required, and you do not need to change the values.yaml file that you provide for Calico.

spec:
  network:
    kubeProxy:
      disabled: true
    providers:
      - provider: calico
        enabled: true
        extraConfig:
          "values.yaml": |
            installation:
              calicoNetwork:
                linuxDataplane: BPF
            defaultFelixConfiguration:
              enabled: true
  nodeLocalDNS:
    enabled: true

Info

The spec.network.kubeProxy.disabled parameter can be left at its default or set to true. Both are accepted on an eBPF cluster.

During mkectl apply, two phases manage the eBPF NAT exclusion:

  • Apply NodeLocalDNS BPF DNS exclusion

    Runs when you enable NodeLocalDNS. Waits until the node-local-dns DaemonSet is Ready on every Linux node, then adds the kube-dns ClusterIP to bpfExcludeCIDRsFromNAT.

  • Remove NodeLocalDNS BPF DNS exclusion

    Runs when you disable NodeLocalDNS. Removes the kube-dns ClusterIP from bpfExcludeCIDRsFromNAT before MKE 4 removes the node-local-dns DaemonSet.

Because of this sequencing, you can enable or disable NodeLocalDNS in a single mkectl apply run.

Verify the eBPF NAT exclusion#

A Ready node-local-dns DaemonSet does not on its own confirm that the local cache is serving DNS on an eBPF cluster. Verify that MKE has excluded the kube-dns ClusterIP from eBPF NAT:

kubectl get felixconfiguration default -o jsonpath='{.spec.bpfExcludeCIDRsFromNAT}'

The output must contain the ClusterIP of the kube-dns Service as a /32, for example ["10.96.0.10/32"].

Operational considerations#

Review the following behavior before you enable NodeLocalDNS on an eBPF cluster:

  • There is no fallback to CoreDNS.

    On the iptables dataplane, kube-proxy provides a path to CoreDNS if the local cache stops serving. On the eBPF dataplane there is no such path. If the node-local-dns pod on a node stops serving, DNS resolution fails for all pods on that node until the pod recovers, typically within two minutes for a routine pod replacement. A pod that cannot recover leaves DNS unavailable on that node indefinitely. Pods on all other nodes are unaffected.

  • Enabling NodeLocalDNS briefly interrupts DNS on each node.

    DNS resolution can be unavailable on a node for up to approximately 45 seconds while the node cache pod starts. The switchover to the local cache that follows is not disruptive, and disabling NodeLocalDNS does not interrupt DNS resolution.

  • Changing spec.nodeLocalDNS.enabled cannot be combined with an upgrade.

    On an eBPF cluster, changing the parameter in the same operation that changes the MKE version is rejected, because the upgrade flow does not perform the sequencing described above. Complete the upgrade first, then change the parameter in a separate mkectl apply.

  • Your own eBPF NAT exclusions are preserved.

    Values that you set through defaultFelixConfiguration.bpfExcludeCIDRsFromNAT in the Calico values.yaml file are combined with the kube-dns ClusterIP that MKE manages, rather than replacing it. Do not include the kube-dns ClusterIP among them, as MKE adds and removes that address on its own schedule.