kubeasz 集群 DNS 部署实战:CoreDNS 与 NodeLocal DNSCache 架构解析
【免费下载链接】kubeasz使用Ansible脚本安装K8S集群,介绍组件交互原理,方便直接,不受国内网络环境影响项目地址: https://gitcode.com/GitHub_Trending/ku/kubeasz
导读
DNS 是 Kubernetes 集群中必须最先部署的基础组件,它为集群中的 Pod 提供集群服务名(SVC)与 Pod hostname 的域名解析能力。本文以 kubeasz 项目为实践载体,系统讲解其内置的 CoreDNS 与 NodeLocal DNSCache 两级 DNS 架构:先说明组件在集群中的作用与选型背景,再给出集成安装、手动部署与验证的完整命令,随后结合仓库中的配置模板与 Ansible 任务源码逐层剖析 Corefile 配置、关键变量与 ipvs/iptables 两种模式的差异,最后列出实战中常见的排错案例,帮助读者在 kubeasz 安装的集群中快速落地并排查集群 DNS 问题。
一、集群 DNS 的角色与选型
在 kubeasz 集群中,DNS 承担两个核心解析任务:
- 集群服务名 SVC 解析:如
nginx.default.svc.cluster.local解析为对应 Service 的 ClusterIP; - Pod hostname 解析:通过 headless service 场景下的 pod 记录,或
pods insecure模式下的 hostname 解析。
kubeasz 目前推荐并默认部署CoreDNS作为集群 DNS 的实现(历史版本曾基于 kube-dns + dnsmasq + sidecar 三容器方案,对应模板保留在 kubedns.yaml.j2 中作为兼容与迁移参考)。同时,kubeasz 默认启用NodeLocal DNSCache,在集群每个节点上运行一个 DNS 缓存 DaemonSet,以提升 clusterDNS 的查询性能与可靠性。官方测试表明:相比纯 CoreDNS 方案,nodelocaldns + coredns组合能够大幅降低 DNS 查询 timeout 的频次,提升服务稳定性。
说明:原文档中引用的官方 nodelocaldns 说明链接(kubernetes.io 官方文档)可在阅读本文后按需自行检索;本文后续内容均以仓库内实际模板与变量为准。
二、安装集群 DNS:三种方式
kubeasz 已将 CoreDNS 与 NodeLocal DNSCache 自动集成进安装流程,无需单独手工部署。配置模板位于roles/cluster-addon/templates/dns/目录(coredns.yaml.j2、nodelocaldns-ipvs.yaml.j2、nodelocaldns-iptables.yaml.j2、kubedns.yaml.j2)。
1. 随集群一键安装(推荐)
假设集群名为xxxx,在执行ezctl setup全流程安装时,DNS 组件会在第 07 步(集群插件安装)自动完成部署:
# 一键安装整个集群(含 DNS) ezctl setup xxxx all2. 分步安装
如果集群已就绪,只想单独执行插件安装步骤:
# 只执行第 07 步:安装集群插件(含 coredns、nodelocaldns) ezctl setup xxxx 073. 手动安装
kubeasz 在渲染阶段会把模板生成到集群目录{{ cluster_dir }}/yml/下(默认/etc/kubeasz/clusters/xxxx/yml/)。可手动应用生成好的清单文件:
kubectl apply -f /etc/kubeasz/clusters/xxxx/yml/coredns.yaml kubectl apply -f /etc/kubeasz/clusters/xxxx/yml/nodelocaldns.yaml4. 安装背后的自动化逻辑(源码视角)
从 roles/cluster-addon/tasks/main.yml 可以看到插件的幂等控制方式:
- 先执行
kubectl get pod --all-namespaces并注册变量pod_info; - 只有当
pod_info中未出现corednsPod 时才import_tasks: coredns.yml; - 只有当未出现
node-local-dnsPod 时才import_tasks: nodelocaldns.yml。
而在 coredns.yml 与 nodelocaldns.yml 中,实际执行的是:
# coredns.yml 核心动作 template: src=dns/coredns.yaml.j2 dest={{ cluster_dir }}/yml/coredns.yaml shell: "{{ base_dir }}/bin/kubectl apply -f {{ cluster_dir }}/yml/coredns.yaml"两个任务都用when:条件分别受控于配置项:
dns_install == "yes":是否安装 CoreDNS(默认开启,见 example/config.yml 中dns_install: "yes");ENABLE_LOCAL_DNS_CACHE|bool:是否启用 NodeLocal DNSCache(默认true)。
此外,nodelocaldns 模板会依据PROXY_MODE自动二选一:
PROXY_MODE == 'ipvs'→ 渲染nodelocaldns-ipvs.yaml.j2;PROXY_MODE in ["iptables", "nftables"]→ 渲染nodelocaldns-iptables.yaml.j2。
两者差异详见下文“四、NodeLocal DNSCache 部署解析”。
三、CoreDNS 部署解析
1. 关键变量与 DNS 服务地址
kubeasz 的 DNS 服务 ClusterIP 并非手工指定,而是由 roles/cluster-addon/vars/main.yml 依据SERVICE_CIDR自动推导,取 Service 网段内第二个可用地址:
CLUSTER_DNS_SVC_IP: "{{ SERVICE_CIDR.split('.')[0] }}.{{ SERVICE_CIDR.split('.')[1] }}.{{ SERVICE_CIDR.split('.')[2] }}.{{ SERVICE_CIDR.split('.')[3]|regex_replace('/.*', '')|int + 2 }}"以默认配置SERVICE_CIDR="10.68.0.0/16"为例,计算得到CLUSTER_DNS_SVC_IP=10.68.0.2——这也解释了后文验证中 Pod 的resolv.conf里nameserver 10.68.0.2的来源。
其余相关默认值定义在 example/config.yml:
| 配置项 | 默认值 | 说明 |
|---|---|---|
dns_install | "yes" | 是否安装 CoreDNS |
corednsVer | "__coredns__" | CoreDNS 镜像版本(ezdown 渲染时替换为实际版本号) |
ENABLE_LOCAL_DNS_CACHE | true | 是否启用 NodeLocal DNSCache |
dnsNodeCacheVer | "__dns_node_cache__" | NodeLocal DNSCache 镜像版本 |
LOCAL_DNS_CACHE | "169.254.20.10" | 节点本地 DNS 监听地址(链路本地地址) |
CLUSTER_DNS_DOMAIN | "cluster.local" | 集群 DNS 域名后缀(见 hosts.allinone) |
版本号占位符
__coredns__、__dns_node_cache__会在ezdown -D离线下载镜像时被替换为真实版本,这是 kubeasz 离线安装机制的一部分(详见 07-install_cluster_addon.md)。
2. Corefile 核心配置解读
coredns.yaml.j2 中的 ConfigMap 定义了 CoreDNS 的核心行为:
.:53 { errors health { lameduck 5s } ready kubernetes {{ CLUSTER_DNS_DOMAIN }} in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf { max_concurrent 1000 } cache 30 reload loadbalance }逐项说明:
kubernetes cluster.local in-addr.arpa ip6.arpa:接入 Kubernetes API,负责集群域与反向域解析;pods insecure:启用 Pod 记录解析(不做 IP 校验);fallthrough in-addr.arpa ip6.arpa:反向解析不命中时放行给下一插件;ttl 30:集群内记录 TTL 30 秒。
forward . /etc/resolv.conf:集群域之外的请求转发给节点/etc/resolv.conf中的上游 DNS(即“默认集成节点 DNS 解析”的实现),max_concurrent 1000限制并发转发数;cache 30:普通记录缓存 30 秒;prometheus :9153:暴露 Prometheus 指标;health/ready:就绪与健康检查端点;loadbalance:对多 A 记录做随机负载均衡。
3. Deployment 与 Service 关键点
- Service 名称为
kube-dns(clusterIP: {{ CLUSTER_DNS_SVC_IP }},即 10.68.0.2),端口 53 UDP/TCP 与 9153 metrics。命名沿用kube-dns是为了兼容旧式 Pod 中写死的kube-dns.kube-system.svc服务名。 - Pod 标签
k8s-app: kube-dns,被 Service selector 选中,这也是 nodelocaldns 中kube-dns-upstreamService 依赖的标签。 - Deployment 关键配置:
replicas: 1、RollingUpdate 策略;priorityClassName: system-cluster-critical,保证在资源紧张时优先调度;podAntiAffinity尽量将副本分散到不同节点;- 容器镜像为
easzlab.io.local:5000/easzlab/coredns:{{ corednsVer }}(离线仓库地址,IfNotPresent); - 资源请求
cpu: 100m / memory: 70Mi,上限memory: 500Mi; - 健康检查:liveness 探测
/health(8080)、readiness 探测/ready(8181); - 安全加固:
seccompProfile: RuntimeDefault、allowPrivilegeEscalation: false、仅保留NET_BIND_SERVICE能力、readOnlyRootFilesystem: true。
四、NodeLocal DNSCache 部署解析
NodeLocal DNSCache 以 DaemonSet 方式在每个节点运行k8s-dns-node-cache,监听链路本地地址169.254.20.10,作为 Pod 侧 DNS 请求的第一跳缓存,只有未命中的请求才通过force_tcp转发给 CoreDNS,从而显著减少 DNS timeout。
1. 两种模板的差异(ipvs vs iptables/nftables)
从 nodelocaldns-ipvs.yaml.j2 与 nodelocaldns-iptables.yaml.j2 对比可见:
| 对比项 | ipvs 模式 | iptables/nftables 模式 |
|---|---|---|
Corefilebind | 仅{{ LOCAL_DNS_CACHE }} | {{ LOCAL_DNS_CACHE }} {{ CLUSTER_DNS_SVC_IP }}(同时绑定 DNS Service IP) |
| 集群域转发目标 | forward . {{ CLUSTER_DNS_SVC_IP }}(显式指定) | forward . __PILLAR__CLUSTER__DNS__(占位符由启动参数注入) |
启动参数-localip | {{ LOCAL_DNS_CACHE }} | {{ LOCAL_DNS_CACHE }},{{ CLUSTER_DNS_SVC_IP }} |
原因:iptables/nftables 模式下,nodelocaldns 需要同时劫持(bind)原kube-dnsService 的 ClusterIP,才能把原本发往10.68.0.2的请求接管到本地缓存;而 ipvs 模式则通过 ipvs 规则天然实现,因此只需绑定本地地址。
2. Corefile 缓存策略
以 ipvs 模板为例:
{{ CLUSTER_DNS_DOMAIN }}:53 { errors cache { success 9984 30 denial 9984 10 } reload loop bind {{ LOCAL_DNS_CACHE }} forward . {{ CLUSTER_DNS_SVC_IP }} { force_tcp } prometheus :9253 health {{ LOCAL_DNS_CACHE }}:8099 }- 集群域请求:命中缓存则直接返回(成功记录缓存 9984 条/30 秒,否定记录 9984 条/10 秒);未命中则
force_tcp用TCP转发给 CoreDNS,避免 UDP 大包分片与超时问题; in-addr.arpa/ip6.arpa:反向域同样走本地缓存与 TCP 转发;.(根域):转发给上游 DNS(__PILLAR__UPSTREAM__SERVERS__),即节点上游;- metrics 端口
9253,health 端口8099。
3. DaemonSet 关键配置
hostNetwork: true+dnsPolicy: Default,直连节点网络,不依赖集群 DNS;priorityClassName: system-node-critical;- tolerations 容忍
CriticalAddonsOnly、NoExecute、NoSchedule,保证所有节点(含控制面)都能调度; - 需要
NET_ADMIN能力以写入 iptables/ipvs 规则; - 挂载宿主机
/run/xtables.lock以避免并发修改 iptables 时锁冲突; - 提供 headless Service
node-local-dns(clusterIP: None)暴露 9253 端口给 Prometheus 抓取指标。
4. 与 kubelet 的衔接(重要前提)
NodeLocal DNSCache 要真正生效,还需将 kubelet 的--cluster-dns指向169.254.20.10,并配置--cluster-domain为cluster.local。在 kubeasz 中,这一衔接由 kubelet-config.yaml.j2 完成;验证时 Pod 内resolv.conf的nameserver即应指向169.254.20.10(见下文验证章节,若仍为10.68.0.2,则说明 kubelet 未配置 local dns 地址或配置未生效)。
五、验证 DNS 服务
1. 创建测试服务
kubectl run nginx --image=nginx --expose --port=80确认服务已就绪:
kubectl get pod | grep nginx nginx-7cbc4b4d9c-fl46v 1/1 Running 0 1m kubectl get svc | grep nginx nginx ClusterIP 10.68.33.167 <none> 80/TCP 1m2. 在测试 Pod 内验证解析
kubectl run test --rm -it --image=alpine /bin/sh If you don't see a command prompt, try pressing enter. / # cat /etc/resolv.conf nameserver 10.68.0.2 search default.svc.cluster.local. svc.cluster.local. cluster.local. options ndots:5 # 测试集群内部服务解析 / # nslookup nginx.default.svc.cluster.local Server: 10.68.0.2 Address 1: 10.68.0.2 kube-dns.kube-system.svc.cluster.local Name: nginx Address 1: 10.68.33.167 nginx.default.svc.cluster.local / # nslookup kubernetes.default.svc.cluster.local Server: 10.68.0.2 Address 1: 10.68.0.2 kube-dns.kube-system.svc.cluster.local Name: kubernetes Address 1: 10.68.0.1 kubernetes.default.svc.cluster.local # 测试外部域名的解析,默认集成node的dns解析 / # nslookup www.baidu.com Server: 10.68.0.2 Address 1: 10.68.0.2 kube-dns.kube-system.svc.cluster.local Name: www.baidu.com Address 1: 180.97.33.108 Address 2: 180.97.33.107 / #输出要点解读:
resolv.conf中nameserver 10.68.0.2为集群 DNS Service IP,search域与ndots:5由 kubelet 注入;- 集群内部名解析返回 ClusterIP:
nginx → 10.68.33.167、kubernetes → 10.68.0.1(apiserver 集群 IP); - 外部域名(
www.baidu.com)由 CoreDNS 的forward . /etc/resolv.conf转发至节点上游 DNS 完成解析,多个 A 记录经loadbalance插件随机返回。
若集群启用了 NodeLocal DNSCache 且 kubelet 正确指向
169.254.20.10,上述测试中的nameserver应显示为169.254.20.10,解析结果不变。
六、实战排错案例
案例 1:calico 网络下 DNS Pod CrashLoopBackOff(原文档 Note1)
使用 calico 作为网络插件时,安装集群后直接安装 DNS 组件可能出现如下故障:calico 分配 Pod 地址时会从网段的第一个地址(网络地址)开始分配,导致kube-dnsPod 恰好拿到与网络地址冲突的 IP,出现CrashLoopBackOff。
故障现象:
$ kubectl get pod --all-namespaces -o wide NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE default busy-5cc98488d4-s894w 1/1 Running 0 28m 172.20.24.193 192.168.97.24 kube-system calico-kube-controllers-6597d9c664-nq9hn 1/1 Running 0 1h 192.168.97.24 192.168.97.24 kube-system calico-node-f8gnf 2/2 Running 0 1h 192.168.97.24 192.168.97.24 kube-system kube-dns-69bf9d5cc9-c68mw 0/3 CrashLoopBackOff 27 31m 172.20.24.192 192.168.97.24解决办法(临时):删除该 Pod,让其自动重建并获取后续可用 IP:
$ kubectl delete pod -n kube-system kube-dns-69bf9d5cc9-c68mw案例 2:busybox 内 nslookup 解析异常(原文档 Note2)
使用kubectl run test -it --rm --image=busybox /bin/sh进行解析测试可能会失败——busybox 内置的 nslookup 程序存在已知 bug(例如对SRV记录、搜索域拼接等处理不正确)。因此推荐使用 alpine 镜像(如上文验证章节所示)进行 DNS 解析验证,或改用nslookup之外的dig、getent hosts等方式交叉确认。
案例 3:Pod 无法解析(排查路径)
当业务 Pod 报 “could not resolve host” 时,按以下顺序排查:
kubectl get pod -n kube-system -o wide | grep -E 'coredns|node-local-dns':确认两组 Pod 均 Running;- 查看 Pod
resolv.conf:nameserver是否为169.254.20.10(启用 nodelocaldns)或10.68.0.2(纯 coredns),search域是否包含cluster.local; - 在集群内直接用
nslookup测试集群域与外部域,判断是 CoreDNS 不可达还是上游转发失败; - 若为 CoreDNS 异常,
kubectl logs -n kube-system <coredns-pod>查看forward错误日志,并确认kube-dnsService 的clusterIP与CLUSTER_DNS_SVC_IP一致。
七、小结
在 kubeasz 集群中,DNS 采用“CoreDNS(集群级解析)+ NodeLocal DNSCache(节点级缓存)”两级架构:
- CoreDNS 通过
kubernetes插件解析集群服务与 Pod 记录,通过forward插件代理外部域名; - NodeLocal DNSCache 以 DaemonSet 在每个节点缓存并 TCP 转发请求,显著降低 DNS timeout 频次,提升稳定性;
- 部署完全融入
ezctl setup自动化流程,由dns_install与ENABLE_LOCAL_DNS_CACHE两个开关控制,模板按PROXY_MODE自动选择 ipvs 或 iptables/nftables 变体; - 关键配置点集中在 roles/cluster-addon/templates/dns/、roles/cluster-addon/vars/main.yml 与 example/config.yml,Kubelet 侧衔接见 kubelet-config.yaml.j2。
掌握上述部署与验证方法后,即可在 kubeasz 集群中快速交付一个稳定、可观测、可排障的集群 DNS 服务。
【免费下载链接】kubeasz使用Ansible脚本安装K8S集群,介绍组件交互原理,方便直接,不受国内网络环境影响项目地址: https://gitcode.com/GitHub_Trending/ku/kubeasz
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考