如何确定CoreDNS中lameduck参数的合适取值?
CoreDNS
lameduck 参数作用说明与配置建议 为什么滚动重启需要延迟关闭?
很多人对K8s Pod终止的流量切走速度有误解:当K8s决定终止一个旧CoreDNS Pod时,动作不是原子的——从Pod收到SIGTERM信号,到所有节点的kube-proxy/CNI插件把这个PodIP从kube-dns服务的后端列表里剔除、更新完全部转发规则,再到上层客户端不再往这个旧IP发请求,中间存在不可消除的时间差。
如果没有配置lameduck,CoreDNS收到SIGTERM会立刻停止监听53端口、退出进程,这段时间差里的请求会直接失败:
- 新发送到旧Pod的DNS请求会直接收到连接拒绝,客户端报解析失败
- 已经被旧Pod接收、正在处理(比如查询缓存、转发到上游DNS、遍历stub域配置)的在途请求会直接中断
lameduck的逻辑不是傻等,它触发后的动作顺序是:
- 立刻把
/health健康检查接口标记为不健康,K8s控制面检测到后会立刻将该Pod从Service Endpoint列表中摘除 - 进程不退出,继续处理完所有已经接收的请求,也不再接收新的长连接请求
- 等配置的时长走完,才真正关闭进程退出
相当于给流量切换留了足够的缓冲窗口,避免滚动更新、Pod驱逐、配置热加载等场景下的随机DNS解析报错。
如何选择合适的lameduck时长?
核心参考四个维度就够:
- 集群Endpoint同步时延:100节点以内的小集群,kube-proxy/CNI同步转发规则的时延普遍在1-3s;千节点以上的大规模集群,Endpoint更新传播到所有节点的耗时可能到3-8s,时长首先要覆盖这个同步窗口
- CoreDNS请求P99时延:如果你的CoreDNS配置了跨地域上游DNS、多stub域转发,P99请求时延可能到2-3s,要留够时间处理完所有在途请求;如果只做集群内Service解析,P99时延基本在100ms以内,这部分预留量可以很小
- 滚动更新效率容忍度:
lameduck设置过长会直接拉长滚动更新总耗时,比如单副本等待30s的话,10副本集群滚动更新至少要多花5分钟,需要平衡可用性和运维效率 - 客户端DNS重试配置:Linux默认
resolv.conf的DNS超时是5s、重试2次,只要lameduck窗口覆盖第一次规则同步的延迟,就算少量丢包客户端也能自动重试,不需要过度拉长时长
配置建议
- 100节点以内的中小集群,默认的
5s完全够用,不需要调整 - 千节点以上大集群、或者使用了跨可用区部署的场景,可以调到
10s-15s,不建议超过20s,避免滚动更新耗时过长 - 不要把
lameduck设为0,等于关闭优雅退出逻辑,滚动更新时大概率会出现随机的DNS解析失败尖刺,问题非常隐蔽难排查 - 如果是用DaemonSet模式在每个节点跑CoreDNS、配合节点本地DNS缓存的架构,可以适当把时长降到
3s,因为同节点的流量切换时延更低
实际应用场景示例
- 滚动更新版本场景:之前有个50节点的集群,最初把
lameduck设为0,每次CoreDNS版本更新时,监控都会出现持续1-2s的DNS错误率尖刺,大概占总请求量的0.3%-0.5%,业务侧偶尔报调用第三方接口域名解析失败,改回默认5s配置后尖刺完全消失 - 节点缩容/驱逐场景:用DaemonSet部署CoreDNS的集群,节点下线前会先驱逐上面的Pod,配置
lameduck后,旧CoreDNS Pod先标记不健康,等同节点上的业务Pod已经把DNS请求切到其他可用实例后再退出,不会出现节点下线时同节点业务批量解析失败的问题 - 配置热加载场景:修改Corefile后CoreDNS会自动重载配置、重启进程,
lameduck可以保证旧进程处理完所有在途请求再退出,整个热加载过程对业务无感知,不会丢请求
内容的提问来源于stack exchange,提问作者anonymous user
相关产品推荐
相关产品推荐

