(注:自 Kubernetes 1.11 起,CoreDNS 已取代 KubeDNS 成为默认 DNS 服务)
什么是 CoreDNS?#
CoreDNS 是 Kubernetes 集群中的核心 DNS 服务,它为集群内的所有 Pod 和 Service 提供名称解析功能。简单来说,CoreDNS 是 Kubernetes 服务发现机制的基石,它将 Service 名称(如 my-service.default.svc.cluster.local)解析为对应的 ClusterIP,使得应用无需硬编码 IP 地址即可相互发现和通信。
作为云原生计算基金会 (CNCF) 毕业项目,CoreDNS 以其插件化架构、高性能和灵活性成为现代 Kubernetes 集群的标准 DNS 解决方案。没有 CoreDNS,微服务架构将难以实现,因为服务将无法通过名称相互发现。
CoreDNS 在 Kubernetes 中的核心角色#
1. 服务发现的"目录管理员"#
- 为每个 Service 创建 DNS 记录
- 支持 A 记录(IPv4)、AAAA 记录(IPv6)和 SRV 记录
- 自动生成层次化域名:
<service>.<namespace>.svc.<cluster-domain>
2. 服务解析的"翻译官"#
- 将逻辑服务名称转换为实际 IP 地址
- 为 Headless Service 提供 Pod IP 列表(而非 ClusterIP)
- 支持服务端口发现(SRV 记录)
3. 集群网络的"连接器"#
- 集成外部 DNS 服务(如公司内部 DNS 或云 DNS)
- 为 Pod 提供默认搜索域,简化名称查询
- 处理跨命名空间的服务发现
CoreDNS 的架构与工作原理#
1. CoreDNS 组件架构#
graph LR A[Pod] -->|DNS 查询| B(CoreDNS Pod) B --> C[插件链] C --> D[kubernetes 插件] C --> E[forward 插件] C --> F[cache 插件] D -->|查询| G[API Server] E -->|转发| H[上游 DNS] F -->|缓存结果| I[内存缓存]
CoreDNS 采用插件链架构,请求按顺序通过多个插件处理:
- kubernetes 插件:处理集群内部 Service 和 Pod 的 DNS 查询
- forward 插件:将外部域名查询转发到上游 DNS 服务器
- cache 插件:缓存查询结果,提高性能
- autopath 插件:优化 Pod 的 DNS 查询路径
- prometheus 插件:暴露监控指标
2. DNS 查询流程#
当 Pod 查询 my-service.default.svc.cluster.local 时:
- Pod 的 DNS 请求发送到 CoreDNS 服务(通常为 10.96.0.10)
- CoreDNS 检查查询是否匹配集群域(cluster.local)
- kubernetes 插件向 API Server 查询 Service 信息
- 获取 Service 的 ClusterIP 或 Endpoint IP 列表
- 返回 DNS 响应(A 记录或 SRV 记录)
- 结果被 cache 插件缓存,以加速后续相同查询
3. DNS 记录类型与示例#
| 记录类型 | 示例 | 解析结果 | 用途 |
|---|---|---|---|
| A 记录 | my-service.default.svc.cluster.local | 10.96.45.10 | Service ClusterIP |
| A 记录 (Headless) | my-headless-svc.default.svc.cluster.local | 10.244.1.5, 10.244.2.6 | 直接返回 Pod IP |
| SRV 记录 | _http._tcp.my-service.default.svc.cluster.local | 80 my-service.default.svc.cluster.local | 服务端口发现 |
| PTR 记录 | 10.244.1.5 | 10-244-1-5.my-pod.default.pod.cluster.local | 反向 DNS 查找 |
CoreDNS 的配置与部署#
1. Corefile 配置#
CoreDNS 使用名为 Corefile 的配置文件,定义插件链和行为:
# CoreDNS 配置示例 (/etc/coredns/Corefile)
.:53 {
errors # 错误日志
health { # 健康检查端点
lameduck 5s
}
ready # 就绪检查端点
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure # 允许 Pod 反向查找
fallthrough in-addr.arpa ip6.arpa # 未匹配时继续处理
ttl 30 # 缓存 TTL
}
prometheus :9153 # 指标端口
forward . /etc/resolv.conf { # 转发外部查询
max_concurrent 1000
}
cache 30 # 缓存所有记录 30 秒
loop # 检测转发循环
reload # 自动重载配置
loadbalance # 负载均衡 DNS 响应
}2. 关键配置参数#
| 参数 | 说明 | 推荐值 |
|---|---|---|
| pods | Pod DNS 模式 | insecure (允许 Pod 反向查找) |
| ttl | DNS 记录 TTL | 30s (平衡性能与更新速度) |
| cache | 缓存时间 | 30s |
| max_concurrent | 最大并发转发查询 | 1000 |
| fallthrough | 未匹配时继续处理 | in-addr.arpa ip6.arpa |
| lameduck | 健康检查延迟 | 5s |
3. 部署清单示例#
# CoreDNS Deployment 示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: kube-dns
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
spec:
serviceAccountName: coredns
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
nodeSelector:
kubernetes.io/os: linux
containers:
- name: coredns
image: coredns/coredns:1.8.6
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
args: [ "-conf", "/etc/coredns/Corefile" ]
volumeMounts:
- name: config-volume
mountPath: /etc/coredns
readOnly: true
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8181
initialDelaySeconds: 10
timeoutSeconds: 3
periodSeconds: 10
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
---
# CoreDNS Service 示例
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
annotations:
prometheus.io/port: "9153"
prometheus.io/scrape: "true"
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.96.0.10 # 通常为 kube-apiserver 配置中的 clusterDNS
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
- name: metrics
port: 9153
protocol: TCPCoreDNS 的高级功能#
1. 自定义 DNS 策略#
Pod 可以通过 dnsPolicy 字段定制 DNS 行为:
apiVersion: v1
kind: Pod
metadata:
name: custom-dns
spec:
dnsPolicy: "None" # 忽略集群 DNS 设置
dnsConfig:
nameservers:
- 1.1.1.1
- 8.8.8.8
searches:
- ns1.svc.cluster.local
- my-namespace.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "5"
- name: timeout
value: "2"- Default:继承节点的 DNS 配置
- ClusterFirst(默认):使用集群 DNS,回退到上游 DNS
- ClusterFirstWithHostNet:HostNetwork Pod 的 ClusterFirst
- None:完全自定义 DNS 配置
2. 高级插件扩展#
| 插件 | 功能 | 使用场景 |
|---|---|---|
| rewrite | 重写 DNS 查询和响应 | 兼容旧版应用,重定向查询 |
| template | 基于模板生成响应 | 动态生成 DNS 记录 |
| k8s_external | 处理外部服务 | 暴露集群服务到外部 DNS |
| file | 从区域文件提供 DNS | 静态 DNS 记录 |
| log | 详细查询日志 | 调试和审计 |
| whoami | 返回客户端信息 | 调试客户端连接 |
示例:重写规则(兼容旧版 DNS 名称)
.:53 {
kubernetes cluster.local in-addr.arpa ip6.arpa
rewrite name exact legacy-app.default.svc.cluster.local my-app.default.svc.cluster.local
forward . /etc/resolv.conf
cache 30
}3. 自动路径优化 (Autopath)#
CoreDNS 的 autopath 插件显著提高 DNS 查询效率:
传统查询流程(无 autopath):
1. my-service (失败)
2. my-service.default.svc.cluster.local (成功)优化后流程(有 autopath):
1. my-service.default.pod.cluster.local (由 Pod IP 推断的搜索域)
2. my-service.default.svc.cluster.local (成功)- 减少 50%+ 的 DNS 查询
- 降低 CoreDNS 负载
- 加快应用启动时间
CoreDNS 与其它组件的关系#
1. 与 kube-proxy 和 Service#
graph LR A[Pod] -->|查询 my-service| B(CoreDNS) B -->|返回 10.96.45.10| A A -->|连接 10.96.45.10:80| C[kube-proxy] C -->|路由到| D[Pod 1] C -->|路由到| E[Pod 2] C -->|路由到| F[Pod 3]
- CoreDNS 负责名称→IP 解析
- kube-proxy 负责 IP→Pod 负载均衡
- 两者协同实现完整服务发现
2. 与 kubelet#
- kubelet 配置每个 Pod 的
/etc/resolv.conf - 设置 nameserver 为 CoreDNS Service IP
- 配置搜索域(search domains)和选项(如 ndots)
典型 /etc/resolv.conf:
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:53. 与外部 DNS 系统集成#
graph LR A[Pod] -->|内部查询| B(CoreDNS) A -->|外部查询 example.com| B B -->|内部域 cluster.local| C[kubernetes 插件] B -->|外部域 example.com| D[forward 插件] D --> E[上游 DNS 8.8.8.8] D --> F[企业 DNS 10.0.0.10]
- 支持条件转发(基于域名)
- 可配置多个上游 DNS 服务器
- 支持 DNS over TLS (DoT) 和 DNS over HTTPS (DoH)
CoreDNS 的监控与故障排除#
1. 关键监控指标#
| 指标 | 说明 | 健康阈值 |
|---|---|---|
| 请求率 | 每秒 DNS 查询数 | 根据集群规模而定 |
| 错误率 | 失败查询比例 | < 1% |
| 延迟 | DNS 响应时间 P99 | < 100ms |
| 缓存命中率 | 缓存响应比例 | > 80% |
| 内存使用 | 每实例内存消耗 | < 100Mi/1000 请求/秒 |
Prometheus 查询示例:
# 错误率
sum(rate(coredns_dns_request_errors_total[5m])) / sum(rate(coredns_dns_requests_total[5m]))
# P99 延迟
histogram_quantile(0.99, sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le))
# 缓存命中率
sum(rate(coredns_cache_hits_total[5m])) / (sum(rate(coredns_cache_hits_total[5m])) + sum(rate(coredns_cache_misses_total[5m])))2. 常用诊断命令#
# 检查 CoreDNS Pod 状态
kubectl get pods -n kube-system -l k8s-app=kube-dns
# 检查 CoreDNS 日志
kubectl logs -n kube-system -l k8s-app=kube-dns
# 从测试 Pod 查询 DNS
kubectl run -it --rm --restart=Never --image=busybox:1.28 dns-test -- nslookup kubernetes.default
# 检查 CoreDNS 配置
kubectl get configmap -n kube-system coredns -o yaml
# 检查指标
curl http://<coredns-pod-ip>:9153/metrics
# 检查 DNS 配置
kubectl exec <pod-name> -- cat /etc/resolv.conf
# 高级调试(启用详细日志)
kubectl edit configmap -n kube-system coredns
# 添加 log 插件到 Corefile3. 常见问题与解决方案#
| 问题现象 | 可能原因 | 诊断命令 | 解决方案 |
|---|---|---|---|
| DNS 解析超时 | CoreDNS 资源不足 | kubectl top pods -n kube-system | 增加 CPU/内存限制 |
| 间歇性解析失败 | 节点 DNS 配置冲突 | cat /etc/resolv.conf (节点上) | 修复节点 resolv.conf |
| 无法解析外部域名 | 上游 DNS 配置错误 | kubectl exec <pod> -- nslookup google.com | 检查 forward 插件配置 |
| SRV 记录缺失 | 未正确配置端口 | kubectl get svc <service> -o yaml | 确保 Service 有命名端口 |
| 高延迟 | 缓存未命中率高 | curl http://<coredns-pod>:9153/metrics | grep cache | 增加缓存 TTL |
| DNS 污染 | 重复部署 CoreDNS | kubectl get svc -n kube-system kube-dns | 清理重复部署 |
最佳实践#
资源规划:
resources: requests: cpu: "100m" memory: "70Mi" limits: cpu: "200m" memory: "170Mi"- 每 1000 个 Pod 预留 0.25 CPU 和 100Mi 内存
- 根据查询模式调整(突发查询需要更多 CPU)
高可用配置:
- 部署至少 2 个副本,分布在不同节点
- 配置 PodDisruptionBudget 防止同时驱逐
- 使用反亲和性避免单点故障
affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: k8s-app operator: In values: ["kube-dns"] topologyKey: "kubernetes.io/hostname"性能优化:
- 启用 autopath 减少查询次数
- 适当增加缓存 TTL(30-60 秒)
- 为频繁访问的服务设置更长 TTL
- 限制最大并发查询防止拒绝服务
安全加固:
- 限制 CoreDNS 权限(最小权限 ServiceAccount)
- 禁用不必要的插件(如 whoami 仅在调试时启用)
- 配置只读根文件系统
- 限制 Pod 到必要的命名空间
多集群 DNS 策略:
- 为不同环境(dev/staging/prod)使用不同集群域
- 通过 stubDomains 配置跨集群服务发现
- 使用 CoreDNS federation 插件(实验性)实现全局服务发现
可观察性增强:
- 集成 Prometheus 和 Grafana 仪表板
- 配置详细错误日志(仅在调试时)
- 设置 DNS 查询延迟和错误率告警
- 采样记录慢查询
一个简单类比#
想象 Kubernetes 集群是一座庞大的智能城市:
- CoreDNS 是城市的中央查询服务中心(类似电话簿+导航系统)
- Service 是城市中的公共服务设施(如"中央医院"、“消防局”)
- Pod 是设施内的具体服务窗口(如"中央医院-急诊室"、“中央医院-门诊”)
- DNS 查询 是市民的服务请求(“我需要去医院”)
中央查询服务中心(CoreDNS)的工作方式:
- 接收请求:市民(Pod)询问"中央医院在哪里?"
- 查询数据库:服务中心查询城市数据库(API Server)
- 提供地址:返回"中央医院位于第5区,坐标10.96.45.10"
- 智能路由:如果是急诊,直接提供最近的急诊窗口地址(Headless Service)
- 外部查询:对于"国家图书馆"等外部设施,转接给国家级查询中心(上游 DNS)
当城市扩张时(新服务部署):
- 无需通知每个市民新设施位置
- 市民只需记住设施名称
- 查询服务中心自动更新数据库
- 所有查询立即指向正确位置
CoreDNS 作为 Kubernetes 服务发现的核心,是微服务架构得以实现的隐形支柱。它将复杂的网络位置抽象为简单的名称,使开发者能够专注于业务逻辑而非网络细节。通过合理配置和监控 CoreDNS,可以显著提升集群的服务发现效率和可靠性,为大规模分布式应用提供坚实基础。
在云原生世界中,CoreDNS 不仅是 DNS 服务器,更是连接所有服务的神经系统。随着服务网格(如 Istio)和多集群架构的普及,CoreDNS 的角色将更加关键,成为连接混合云和多云环境的统一服务发现层。掌握 CoreDNS 的工作原理和优化技巧,是构建生产级 Kubernetes 集群的必备技能。