有奖捉虫:办公协同&微信生态&物联网文档专题 HOT

总述

DNS 作为 Kubernetes 集群中服务访问的第一环节,其稳定性和性能至关重要,如何以更优的方式配置和使用 DNS,涉及到方方面面,本文档将总结这些最佳实践。

选择最佳 CoreDNS 版本

下表列出了随各个版本 TKE 集群默认部署的 CoreDNS 版本:
TKE Version
CoreDNS version
v1.24
1.8.4
v1.22
1.8.4
v1.20
1.8.4
v1.18
1.7.0
v1.16
1.6.2
v1.14
1.6.2
由于历史原因,可能会有 v1.18 及以上版本的集群仍然部署 1.6.2 版本的 CoreDNS,如果当前 CoreDNS 版本不满足需求,可以按如下指引手动升级:

配置合适的 CoreDNS 副本数

1. TKE 默认设置 CoreDNS 副本数为2,且配置了 podAntiAffinity 使两副本部署在不同节点。
2. 针对节点数大于80的集群,建议安装 NodeLocal DNSCache,详情请参见 在 TKE 集群中使用 NodeLocal DNS Cache
3. 一般根据集群内业务访问 DNS 的 QPS 来确定 CoreDNS 合理的副本数,也可以根据节点数以及总核数来确定,在安装 NodeLocal DNSCache 后,建议 CoreDNS 最大副本数为10,可以按照如下方式配置: 副本数 = min ( max ( ceil (QPS/10000), ceil (集群节点数/8) ), 10 ) 示例:
集群节点数为10,DNS 服务请求 QPS 为22000,则副本数为3。
集群节点数为30,DNS 服务请求 QPS 为15000,则副本数为4。
集群节点数为100,DNS 服务请求 QPS 为50000,则副本数为10(已部署 NodeLocal DNSCache)。
4. 可以通过在控制台 安装 DNSAutoScaler 组件,来实现自动调整 CoreDNS 副本数(要注意提前配置好平滑升级),组件的默认配置如下:
data:
ladder: |-
{
"coresToReplicas":
[
[ 1, 1 ],
[ 128, 3 ],
[ 512,4 ],
],
"nodesToReplicas":
[
[ 1, 1 ],
[ 2, 2 ]
]
}

使用 NodeLocal DNSCache

在 TKE 集群中部署 NodeLocal DNSCache 可以提升服务发现的稳定性和性能,其通过在节点上作为 DaemonSet 运行 DNS 缓存代理来提高集群 DNS 性能。 关于更多 NodeLocal DNSCache 的介绍及如何在 TKE 集群中部署 NodeLocal DNSCache 的具体步骤,详情请参见 在 TKE 集群中使用 NodeLocal DNS Cache

配置 CoreDNS 平滑升级

当重启节点或者升级 CoreDNS 时,可能导致 CoreDNS 部分副本在一段时间不可用,可以通过以下配置,最大程度保证 DNS 服务整体的可用性,实现平滑升级。

配置会话保持

kube-proxy 为 iptables 模式,无需配置会话保持

iptables 模式下,kube-proxy 会在同步 iptables 规则后及时清理遗留的 conntrack 表项,不存在会话保持问题,无需配置。

kube-proxy 为 IPVS 模式,需要配置 IPVS UDP 协议的会话保持超时时间

IPVS 模式下,内核默认打开会话保持特性,这会导致在 CoreDNS 升级或重启期间,业务侧的 DNS 解析请求,在 5分钟 (300s) 内概率性超时。如果业务自身没有 UDP 服务,可以降低 IPVS UDP 协议的会话保持超时时间,以此来减少解析超时的持续时间。
1. 集群版本大于等于1.18,kube-proxy 提供参数--ipvs-udp-timeout,该参数默认值为5分钟 (300s) ,推荐配置为--ipvs-udp-timeout=10s,以便将解析超时的持续时间缩短为10s,请按如下方式配置 kube-proxy DaemonSet:
spec:
containers:
- args:
- --kubeconfig=/var/lib/kube-proxy/config
- --hostname-override=$(NODE_NAME)
- --v=2
- --proxy-mode=ipvs
- --ipvs-scheduler=rr
- --nodeport-addresses=$(HOST_IP)/32
- --ipvs-udp-timeout=10s
command:
- kube-proxy
name: kube-proxy
2. 集群版本小于等于1.16,kube-proxy 不支持该参数,可以使用ipvsadm工具批量在节点侧修改:
yum install -y ipvsadm
ipvsadm --set 900 120 10
3. 配置完成后,可以按如下方式验证:
ipvsadm -L --timeout
Timeout (tcp tcpfin udp): 900 120 10
注意:
在配置完成后,需要等待5分钟,再继续后面的步骤;如果业务有使用 UDP 服务,请 提交工单 来寻求帮助。

配置 CoreDNS 优雅退出

已经收到退出信号的副本,可以通过配置 lameduck 使其能在一段时间内继续提供服务,按如下方式配置 CoreDNS 的 configmap(仅展示 CoreDNS 1.6.2版本的部分配置,其它版本配置参见 手动升级 CoreDNS):
.:53 {
health {
lameduck 30s
}
kubernetes cluster.local. in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
}

配置 CoreDNS 服务就绪确认

新副本启动后,需确认其服务就绪,再加入 DNS 服务的后端列表。
1. 打开 ready 插件,按如下方式配置 CoreDNS 的 configmap(仅展示 CoreDNS 1.6.2版本的部分配置,其它版本配置参见 手动升级 CoreDNS):
.:53 {
ready
kubernetes cluster.local. in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
}
2. 为 CoreDNS 增加配置 ReadinessProbe:
readinessProbe:
failureThreshold: 5
httpGet:
path: /ready
port: 8181
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5

配置 CoreDNS 使用 UDP 访问上游 DNS

当 CoreDNS 需要与上游 DNS Server 通信时,它将默认使用客户端请求的协议(UDP 或者 TCP),而 TKE 中 CoreDNS 的上游默认为 VPC 内的 DNS 服务,该服务对 TCP 的支持在性能上比较有限,因此推荐做如下配置,显示指定 UDP(尤其在安装了 NodeLocal DNSCache 时):
.:53 {
forward . /etc/resolv.conf {
prefer_udp
}
}

配置 CoreDNS 过滤 HINFO 请求

VPC 内的 DNS 服务不支持 HINFO 类型的 DNS 请求,因此推荐做如下配置,在 CoreDNS 侧过滤此类请求(尤其在安装了 NodeLocal DNSCache 时):
.:53 {
template ANY HINFO . {
rcode NXDOMAIN
}
}

配置 CoreDNS 对 IPv6 类型的 AAAA 记录查询返回域名不存在

当业务不需要做 IPv6 的域名解析时,可以通过该配置降低通信成本:
.:53 {
template ANY AAAA {
rcode NXDOMAIN
}
}
注意:
IPv4/IPv6 双栈集群不能做此配置。

配置自定义域名解析

手动升级

升级到1.7.0

1. 编辑 coredns configmap:
kubectl edit cm coredns -n kube-system
修改为以下内容:
.:53 {
template ANY HINFO . {
rcode NXDOMAIN
}
errors
health {
lameduck 30s
}
ready
kubernetes cluster.local. in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
reload
loadbalance
}
2. 编辑 coredns deployment:
kubectl edit deployment coredns -n kube-system
替换镜像为:
image: ccr.ccs.tencentyun.com/tkeimages/coredns:1.7.0

升级到1.8.4

注意:
社区中 CoreDNS 1.7.0 版本是一个 backwards-incompatible release,在这个版本中删除了kubernetes插件的 upstreamresyncperiod 的option(详见社区社pr),如果用户需要从 1.7.0 以下的版本(例如 1.6.2 版本)升级到 1.8.4 版本,需要进行相关配置的兼容性修改。

CoreDNS 升级配置检查

CoreDNS 升级前,需要对 corefile 配置以及 CoreDNS 的 deployment 配置进行检查,详情如下。
corefile 配置检查:
kubernetes 插件兼容性检查
检查 kubernetes 插件是否设置了 upstream,如果设置 upstream,且未配置 server 参数,可以直接删除。



如果有设置 upstream server 参数,需要将 upstream server 参数迁移到 forward 插件部分。
检查 kubernetes 插件是否设置resyncperiod,如果设置,直接删除。
health 和 ready 插件检查
检查 health 插件的 lameduck 参数配置时间不要超过 30s。
检查是否配置 health 和 ready 插件,这两个插件是必选配置。
deployment 配置检查:
确认 coredns 的 deployment 中配置 livenessprobe,并和 corefile 文件的 health 端口配置保持一致。
确认 coredns 的 deployment 中配置 readinessprobe,并和 corefile 文件的 ready 端口配置保持一致。

CoreDNS 升级流程

完成 corefile 以及 deployment 配置检查后,可进行升级。
1. 编辑 coredns clusterrole:
kubectl edit clusterrole system:coredns
请在 1.6.2 版本 coredns 的 clusterrole 下增加以下内容:
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
旧版本1.6.2版本内容
新版本1.8.4内容
rules:
- apiGroups:
- '*'
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
rules:
- apiGroups:
- '*'
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
编辑 coredns configmap:
kubectl edit cm coredns -n kube-system
如果用户有自定义 corefile 配置,请按照上述检查注意事项修改,其中标准模板如下:
.:53 {
template ANY HINFO . {
rcode NXDOMAIN
}
errors
health {
lameduck 30s
}
ready
kubernetes cluster.local. in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
reload
loadbalance
}
2. 编辑 coredns deployment
kubectl edit deployment coredns -n kube-system
替换镜像为升级镜像如下:
image: ccr.ccs.tencentyun.com/tkeimages/coredns:1.8.4

升级后检查

确保 coredns pod running 且处于 ready 状态:
kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide
确保 coredns 无错误日志:
kubectl logs ${coredns-pod-name} -n kube-system | grep -i error
确保 coredns pod 可以正常解析内外部域名:
nslookup kubernetes.default.svc.cluster.local ${coredns-pod-ip}
nslookup www.qq.com ${coredns-pod-ip}

业务配置

除了 DNS 服务的最佳实践外,在业务侧,也可以做适当的优化配置,来提升 DNS 的使用体验。
1. 默认情况下,Kubernetes 集群中的域名解析往往需要经过多次请求才能解析到。查看 pod 内 的 /etc/resolv.conf 可以知道 ndots 选项默认为 5。例如,在 debug 命名空间查询 kubernetes.default.svc.cluster.local 这个 service:
域名中有 4 个 . ,小于 5,尝试拼接上第一个 search 进行查询,即kubernetes.default.svc.cluster.local.debug.svc.cluster.local ,查不到该域名。
继续尝试 kubernetes.default.svc.cluster.local.svc.cluster.local ,查不到该域名。
继续尝试 kubernetes.default.svc.cluster.local.cluster.local ,仍然查不到该域名。
尝试不加后缀,即 kubernetes.default.svc.cluster.local ,查询成功,返回响应的 ClusterIP。
2. 上面一个简单的 service 域名解析需要经过 4 轮解析才能成功,集群中充斥着大量无用的 DNS 请求。因此需要根据业务配置的访问方式来为其设置合理的 ndots 来降低查询次数:
spec:
dnsConfig:
options:
- name: ndots
value: "2"
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: diagnosis
3. 同时,可以优化业务访问服务的域名配置:
Pod 访问本命名空间的 Service,使用 <service-name> 访问。
Pod 访问其它命名空间的 Service,使用 <service-name>.<namespace-name> 访问。
Pod 访问外部域名,使用 FQDN 类型域名访问,在域名最后添加 . 以减少无效搜索。
4. glibc 的 resolver 库访问一个 name server 的超时时间默认为5秒,针对 /etc/resolv.conf 中列出的一组 name server,默认最多尝试(attempts)2次,如 /etc/resolv.conf 中配置两个 name server,当所有 name server 都不可用时,总超时时间为20秒,然而,这对于许多业务来说过于保守。可以根据业务实际需要,为 Pod 设置合理的 DNS 超时配置,以降低超时时间,避免 DNS 服务短时不可用导致业务吞吐量的显著下降,以下是一个示例:
spec:
dnsConfig:
options:
- name: timeout
value: "1"
- name: attempts
value: "2"
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: diagnosis

相关内容

配置介绍

errors 输出错误信息。
health 上报健康状态,用于配置健康检查,如 livenessProbe,默认监听 8080 端口,路径为 http://localhost:8080/health
注意:
如果有多 Server 块,health 只能配置一次,或者配置在不同端口。
com {
whoami
health :8080
}

net {
erratic
health :8081
}
lameduck 用于配置优雅退出的时间,实现方式是 hook 在 CoreDNS 收到退出信号时,在其中执行 sleep,以保证时限内可以继续提供服务。
ready 上报插件状态,用于配置服务就绪检查,如readinessProbe,默认监听 8181 端口,路径为http://localhost:8181/ready
kubernetes Kubernetes 插件,支持集群内服务解析。
prometheus metrics 数据接口,用于获取监控数据,路径为 http://localhost:9153/metrics
forward(proxy) 将无法处理的请求转发到上游 DNS 服务器。默认使用宿主机的 /etc/resolv.conf 配置。
根据 forward aaa bbb 的配置,内部会维护一个 udns 的列表 [aaa,bbb]
当有请求到来时,根据预设的策略(random|round_robin|sequential,默认 random)在列表 [aaa,bbb] 中找一个 udns 发请求,如果失败,则找出下一个 udns 进行尝试,同时针对失败的 udns 启动周期性的健康监测,直到其变为健康,停止健康监测。
在健康监测的过程中,如果连续几次(默认两次)监测失败,则将该 udns 状态置为 down,后面从列表中选 udns 时将跳过状态为 down 的 udns。
当所有的 udns 都 down 时,随机选一个 udns 做转发。 因此,可以认为 coredns 有在多个 upstream 间智能切换的能力,forward 列表里只要有一个可用的 udns,则请求可以成功。
cache DNS 缓存。
reload 热加载 Corefile,修改 ConfigMap 后,会在两分钟内加载新配置。
loadbalance 提供基于 DNS 的负载均衡功能,随机响应记录的顺序。

CoreDNS 资源占用

内存
CPU
主要取决于集群内 Pod 数和 Service 数。
受打开缓存大小的影响。
受 QPS 的影响。
以下数据来自于 CoreDNS 官方: MB required (default settings) = (Pods + Services) / 1000 + 54

CoreDNS in Kubernetes Memory Use


主要受 QPS 的影响。
以下数据来自于 CoreDNS 官方: 单副本 CoreDNS,运行节点规格:2 vCPUs, 7.5 GB memory。
Query Type
QPS
Avg Latency (ms)
Memory Delta (MB)
external
6733
12.02
+5
internal
33669
2.608
+5