Warning: this is not a recommended approach. This is solely to exempt worker nodes from running kube-dns, so that if they die, kube-dns does not die with them.
Because of the taints on the etcd and controlplane nodes, we need to add tolerations to the kube-dns Deployment:
kubectl -n kube-system patch deploy/kube-dns -p '{"spec":{"template":{"spec":{"tolerations":[{"key":"node-role.kubernetes.io/controlplane","effect":"NoSchedule","value":"true"},{"key":"node-role.kubernetes.io/etcd","effect":"NoExecute","value":"true"}]}}}}'
Secondly, we want to add node affinity to the deployment to make sure it is preferred to be scheduled to controlplane nodes (weight: 100) and possibly on etcd nodes (weight: 1), with a requirement not to land on worker nodes.
kubectl -n kube-system patch deploy/kube-dns -p '{"spec":{"template":{"spec":{"affinity":{"nodeAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"preference":{"matchExpressions":[{"key":"node-role.kubernetes.io/etcd","operator":"Exists"}]},"weight":1},{"preference":{"matchExpressions":[{"key":"node-role.kubernetes.io/controlplane","operator":"Exists"}]},"weight":100}],"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"node-role.kubernetes.io/worker","operator":"DoesNotExist"}]}]}}}}}}}'
kubectl -n kube-system patch deploy/kube-dns -p '{"spec":{"template":{"spec":{"tolerations":[{"key":"CriticalAddonsOnly","operator":"Exists"}]}}}}'
kubectl -n kube-system patch deploy/kube-dns --type json -p '[{ "op": "remove", "path": "/spec/template/spec/affinity/nodeAffinity" }]'