Configure pod count, resources, scheduling, and node isolation to prevent CoreDNS outages in unmanaged mode.
In unmanaged mode, CoreDNS availability and performance depend on pod count, resource limits, scheduling, and node distribution. Default settings suit small clusters; production workloads require tuning.
Potential impacts
Misconfigured or under-resourced CoreDNS leads to two categories of problems:
-
Availability: incorrect scheduling creates node- or zone-level single points of failure. Insufficient resources cause pod eviction and DNS outages.
-
Performance: resource contention on shared nodes increases response latency. High node load causes I/O packet loss and DNS request failures.
Adjust CoreDNS pod count
Because UDP lacks retransmission, scaling in or restarting CoreDNS — especially when IPVS defects cause packet loss — can trigger cluster-wide DNS resolution timeouts or failures lasting up to five minutes. See Troubleshooting DNS resolution issues.
Do not use horizontal pod autoscaling (HPA) or CronHPA for CoreDNS. Frequent scale-in causes resolution failures.
Assess DNS pressure
Before adjusting replica count, assess DNS pressure. Tools such as DNSPerf can measure DNS load.
If you cannot measure DNS pressure directly, use these guidelines:
-
Run at least 2 CoreDNS pods with resource limits of at least 1 core and 1 GB memory.
-
DNS resolution QPS scales linearly with CPU consumption. With NodeLocal DNSCache, each CPU core handles over 10,000 queries per second (QPS). Different workloads have widely varying QPS needs, so monitor the peak CPU usage of each CoreDNS pod; if any pod exceeds one core during business peak hours, scale out the replicas.
-
Without load data, start with 1 pod per 8 nodes as a baseline.
Scaling out only helps when nodes have sufficient resources. If nodes are low on memory, add nodes or increase per-node resources instead.
Once you know your target replica count, use automatic adjustment (recommended) or scale manually.
Configure automatic adjustment (recommended)
The cluster-proportional-autoscaler adjusts CoreDNS replicas based on cluster size. Unlike HPA, it does not rely on CPU metrics or perform disruptive scale-in. Default ratio: 1 pod per 8 nodes.
Replica count formula: replicas = max(ceil(cores × 1/coresPerReplica), ceil(nodes × 1/nodesPerReplica)). The min and max parameters cap the count at 2–100.
Deploy the autoscaler:
apiVersion: apps/v1
kind: Deployment
metadata:
name: dns-autoscaler
namespace: kube-system
labels:
k8s-app: dns-autoscaler
spec:
selector:
matchLabels:
k8s-app: dns-autoscaler
template:
metadata:
labels:
k8s-app: dns-autoscaler
spec:
serviceAccountName: admin
containers:
- name: autoscaler
image: registry.cn-hangzhou.aliyuncs.com/acs/cluster-proportional-autoscaler:1.8.4
resources:
requests:
cpu: "200m"
memory: "150Mi"
command:
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=dns-autoscaler
- --nodelabels=type!=virtual-kubelet
- --target=Deployment/coredns
- --default-params={"linear":{"coresPerReplica":64,"nodesPerReplica":8,"min":2,"max":100,"preventSinglePointFailure":true}}
- --logtostderr=true
- --v=9
Scale manually
To set a specific replica count:
kubectl scale --replicas=<target> deployment/coredns -n kube-system # Replace <target> with the target number of pods.
Adjust CoreDNS pod specifications
In an ACK Pro cluster, the default CoreDNS pod configuration is:
| Resource | Default limit |
|---|---|
| CPU | No limit |
| Memory | 2 GiB |
Set the CPU limit to 4096m (minimum 1024m) based on your observed peak usage.
Changing CoreDNS pod specifications restarts pods, which may cause brief DNS latency spikes or failures. Perform this during off-peak hours.
-
Log on to the ACK console . In the left navigation pane, click Clusters .
-
On the Clusters page, click the target cluster name. In the left navigation pane, click Add-ons.
-
On the Networking tab, find CoreDNS and click Configuration.

-
Modify the CoreDNS configuration and click OK.

Deploy on a dedicated node pool
A dedicated node pool isolates CoreDNS from other workloads and prevents resource contention.
Rescheduling CoreDNS pods restarts them, which may cause brief DNS latency spikes or failures. Perform this during off-peak hours.
Create a dedicated node pool
When creating the node pool, follow these guidelines:
-
CoreDNS is network-intensive, not compute-intensive. Use network-enhanced instances with a recommended size of 4 cores and 8 GB memory.
-
The node pool must have at least 2 nodes, since CoreDNS runs 2 pods by default.
-
Add a taint and label to prevent other pods from running on these nodes. For example, use
system-addon: system-addonas both the taint key-value pair and label, withEffectset toNoSchedule.
Schedule CoreDNS pods to the node pool
-
On the Add-ons page, find the CoreDNS card and click Configuration.
-
In the NodeSelector section, add the label of the dedicated node pool.
Do not delete existing NodeSelector labels.

-
In the Tolerations section, add a toleration that matches the node pool's taint.

-
Click OK, then verify that CoreDNS pods are running on the dedicated nodes:
kubectl -n kube-system get pod -o wide --show-labels | grep coredns
Use scheduling policies for high availability
To protect DNS availability, CoreDNS uses two scheduling policies by default:
-
Pod anti-affinity (node-level): prevents two CoreDNS pods from running on the same node. If a node fails, DNS remains available on other nodes.
-
Topology-aware scheduling (zone-level): distributes CoreDNS pods across availability zones, preventing zone-level single points of failure that pod anti-affinity alone cannot address.
These policies apply only during initial scheduling. If node or zone configurations change, find the coredns Deployment in the ACK console and click Redeploy.
Pod anti-affinity
CoreDNS uses a requiredDuringSchedulingIgnoredDuringExecution anti-affinity rule to prevent two CoreDNS pods from sharing a node. This requires at least 2 nodes with sufficient resources, excluding:
-
k8s.aliyun.com: true— nodes with node autoscaling enabled -
type: virtual-kubelet— virtual nodes -
alibabacloud.com/lingjun-worker: true— Lingjun nodes
The default affinity configuration is:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
# virtual nodes have this label
- key: type
operator: NotIn
values:
- virtual-kubelet
# lingjun worker nodes have this label
- key: alibabacloud.com/lingjun-worker
operator: NotIn
values:
- "true"
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
# autoscaled nodes have this label
- key: k8s.aliyun.com
operator: NotIn
values:
- "true"
weight: 100
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- kube-dns
topologyKey: kubernetes.io/hostname
Topology-aware scheduling
By default, CoreDNS uses topology-aware scheduling to spread pods across zones. The whenUnsatisfiable: DoNotSchedule setting enforces this — pods won't be scheduled if the zone balance condition can't be met.
For this to work reliably:
-
Your cluster must have nodes in at least 2 different zones, each with at least 1 node that has sufficient resources for CoreDNS.
-
All nodes must have the
topology.kubernetes.io/zonelabel (applied by default). Missing or inconsistent labels cause scheduling failures or uneven distribution. -
Upgrade your cluster to v1.27 or later and CoreDNS to v1.12.1.3 or later. Earlier cluster versions do not support matchLabelKeys, so a CoreDNS rolling update may end with pods unevenly distributed across zones and may even leave some zones uncovered. See the
matchLabelKeysconfiguration described below.
CoreDNS versions earlier than v1.12.1.3 use this topology spread constraint:
topologySpreadConstraints:
- labelSelector:
matchLabels:
k8s-app: kube-dns
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
The pod count difference between any two zones cannot exceed maxSkew (default 1).
The labelSelector counts pods from both new and old ReplicaSets, so to satisfy maxSkew=1, the scheduler favors zones with fewer total pods. After old pods terminate, new pods may concentrate in a few zones.
CoreDNS v1.12.1.3 and later fixes this with matchLabelKeys (Kubernetes v1.27+):
topologySpreadConstraints:
- labelSelector:
matchLabels:
k8s-app: kube-dns
matchLabelKeys:
- pod-template-hash
nodeTaintsPolicy: Honor
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
Adding matchLabelKeys: [pod-template-hash] scopes the constraint to the current ReplicaSet, so rolling updates distribute pods evenly across zones.