Coredns延迟NodeLocalDNS解决之道

#作者:邓伟

文章目录

  • 问题列表
  • 问题分析:
  • 问题分析
  • 解决方案详情
  • 方案验证
  • 部署步骤
  • 验证结论
  • 回滚方案
  • 回滚验证
  • 注意事项
  • NodeLocalDNS介绍

问题列表

近来发现K8s频繁出现5s超时问题,业务反馈收到一定影响,问题包括:

  1. coredns解析报5s延迟
    如图
    在这里插入图片描述
  2. 优化配置后,延迟有所缓解,但仍然存在5s延迟情况。

问题分析:

通过进一步查看和分析,磐基dns解析组件为coredns,支持ipv4和ipv6解析,而linux 中 glibc 的 resolver 的缺省超时时间是 5s,而导致超时的原因是内核 conntrack 模块的 bug,详解分析:

https://www.weave.works/blog/racy-conntrack-and-dns-lookup-timeouts,详细说明如下

DNS client (glibc 或 musl libc) 会并发请求 A 和 AAAA 记录,跟 DNS Server 通信自然会先 connect (建立 fd),后面请求报文使用这个 fd 来发送,由于 UDP 是无状态协议, connect 时并不会发包,也就不会创建 conntrack 表项, 而并发请求的 A 和 AAAA 记录默认使用同一个 fd 发包,send 时各自发的包它们源 Port 相同(因为用的同一个 socket 发送),当并发发包时,两个包都还没有被插入 conntrack 表项,所以 netfilter 会为它们分别创建 conntrack 表项,而集群内请求 kube-dns 或 coredns 都是访问的 CLUSTER-IP,报文最终会被 DNAT 成一个 endpoint 的 POD IP,当两个包恰好又被 DNAT 成同一个 POD IP 时,它们的五元组就相同了,在最终插入的时候后面那个包就会被丢掉,如果 dns 的 pod 副本只有一个实例的情况就很容易发生(始终被 DNAT 成同一个 POD IP),现象就是 dns 请求超时,client 默认策略是等待 5s 自动重试,如果重试成功,我们看到的现象就是 dns 请求有 5s 的延时。

问题分析

通过进一步查看和分析发现:

在使用 DNS 客户端(如 glibc 或 musl libc)时,客户端会并发请求 A 记录和 AAAA 记录,并通过同一个 socket 文件描述符(fd)发送 UDP 报文。

由于 UDP 是无状态协议,connect 不会实际发包,因此初始时不会创建 conntrack 表项。当并发请求的 A 和 AAAA 记录使用同一个 fd 发送时,它们的源端口相同,且在发送时都未被插入 conntrack 表项,导致 netfilter 会为它们分别创建表项。

在 Kubernetes 集群中,DNS 请求访问 Cluster IP 后会被 DNAT 成具体的 Endpoint Pod IP。如果两个并发请求的包被 DNAT 成同一个 Pod IP,它们的五元组(源 IP、源端口、目标 IP、目标端口、协议)将完全相同,导致后一个包在插入 conntrack 表项时被丢弃。

当 DNS 服务的 Pod 只有一个实例时,这种情况尤为常见,最终表现为 DNS 请求超时。客户端默认会等待 5 秒后重试,若重试成功,则会观察到 5 秒的延迟

解决方案详情

针对于以上问题和分析,可选的解决具体方案和优缺点如下:

  1. 将client dns请求由udp转换为tcp,避免出现conntrack 引发的问题,但是性能明显下降;

  2. 避免相同五元组 DNS 请求的并发,即配置single-request-reopen 或single-request ,可以显著降低超时,但是改动较大影响面较广;

需要说明的是1和2:不支持 alpine 基础镜像的容器,因为 apline 底层使用的 musl libc 库并不支持这些 resolv.conf 选项,所以如果使用 alpine 基础镜像构建的应用,还是无法规避超时的问题。

  1. 本地 DNS 缓存,也即:本地 DNS 缓存以 DaemonSet 方式在每个节点部署一个使用 hostNetwork 的 Pod,创建一个网卡绑上本地 DNS 的 IP,本机的 Pod 的 DNS 请求路由到本地 DNS,然后取缓存或者继续使用 TCP 请求上游集群 DNS 解析 (由于使用 TCP,同一个 socket 只会做一遍三次握手,不存在并发创建 conntrack 表项,也就不会有 conntrack 冲突),也即:NodeLocalDNS,详见文末介绍。

综合分析优缺点以及实际影响面,从影响和改动成本以及长期稳定性等因素考虑,选择第3项解决此问题,可做到部署即生效(k8s集群为iptables模式)。

方案验证

针对以上提出的问题,本方案有以下内容组成如下:

  1. 部署NodeLocalDNS

按照官方提供的K8S部署配置((根据k8s版本选择,磐基为1.23))参见:https://github.com/kubernetes/kubernetes/blob/release-1.23/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml):
镜像地址:k8s.gcr.io/dns/k8s-dns-node-cache:1.21.1;
整理后完整内容为:

apiVersion: v1
kind: ServiceAccount
metadata:name: node-local-dnsnamespace: kube-systemlabels:kubernetes.io/cluster-service: "true"addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: v1
kind: Service
metadata:name: kube-dns-upstreamnamespace: kube-systemlabels:k8s-app: kube-dnskubernetes.io/cluster-service: "true"addonmanager.kubernetes.io/mode: Reconcilekubernetes.io/name: "KubeDNSUpstream"
spec:ports:- name: dnsport: 53protocol: UDPtargetPort: 53- name: dns-tcpport: 53protocol: TCPtargetPort: 53selector:k8s-app: kube-dns
---
apiVersion: v1
kind: ConfigMap
metadata:name: node-local-dnsnamespace: kube-systemlabels:addonmanager.kubernetes.io/mode: Reconcile
data:Corefile: |cluster.local:53 {errorscache {success 9984 30denial 9984 5}reloadloopbind 169.254.20.10 169.169.0.100forward . __PILLAR__CLUSTER__DNS__ {force_tcp}prometheus :9253health 169.254.20.10:<设定监控检查端口,确保不宿主机没占用>}in-addr.arpa:53 {errorscache 30reloadloopbind 169.254.20.10 169.169.0.100forward . __PILLAR__CLUSTER__DNS__ {force_tcp}prometheus :9253}ip6.arpa:53 {errorscache 30reloadloopbind 169.254.20.10 169.169.0.100forward . __PILLAR__CLUSTER__DNS__ {force_tcp}prometheus :9253}.:53 {errorscache 30reloadloopbind 169.254.20.10 169.169.0.100forward . __PILLAR__CLUSTER__DNS__prometheus :9253}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:name: node-local-dnsnamespace: kube-systemlabels:k8s-app: node-local-dnskubernetes.io/cluster-service: "true"addonmanager.kubernetes.io/mode: Reconcile
spec:updateStrategy:rollingUpdate:maxUnavailable: 10%selector:matchLabels:k8s-app: node-local-dnstemplate:metadata:labels:k8s-app: node-local-dnsannotations:prometheus.io/port: "9253"prometheus.io/scrape: "true"spec:priorityClassName: system-node-criticalserviceAccountName: node-local-dnshostNetwork: truednsPolicy: Default  # Don't use cluster DNS.tolerations:- key: "CriticalAddonsOnly"operator: "Exists"- effect: "NoExecute"operator: "Exists"- effect: "NoSchedule"operator: "Exists"containers:- name: node-cacheimage: <可拉取的image地址>resources:requests:cpu: 25mmemory: 5Miargs: [ "-localip", "169.254.20.10,169.169.0.100", "-conf", "/etc/Corefile", "-upstreamsvc", "kube-dns-upstream" ]securityContext:privileged: trueports:- containerPort: 53name: dnsprotocol: UDP- containerPort: 53name: dns-tcpprotocol: TCP- containerPort: 9253name: metricsprotocol: TCPlivenessProbe:httpGet:host: 169.254.20.10path: /healthport: <配置文件设置的健康检查端口>initialDelaySeconds: 60timeoutSeconds: 5volumeMounts:- mountPath: /run/xtables.lockname: xtables-lockreadOnly: false- name: config-volumemountPath: /etc/coredns- name: kube-dns-configmountPath: /etc/kube-dnsvolumes:- name: xtables-lockhostPath:path: /run/xtables.locktype: FileOrCreate- name: kube-dns-configconfigMap:name: kube-dnsoptional: true- name: config-volumeconfigMap:name: node-local-dnsitems:- key: Corefilepath: Corefile.base
---
# A headless service is a service with a service IP but instead of load-balancing it will return the IPs of our associated Pods.
# We use this to expose metrics to Prometheus.
apiVersion: v1
kind: Service
metadata:annotations:prometheus.io/port: "9253"prometheus.io/scrape: "true"labels:k8s-app: node-local-dnsname: node-local-dnsnamespace: kube-system
spec:clusterIP: Noneports:- name: metricsport: 9253targetPort: 9253selector:
k8s-app: node-local-dns

以上假设

  1. kube-dns服务的ip地址为:169.169.0.100,且保证pod 的nameserver为169.169.0.100,否则,请按kube-dns服务实际ip更改;
  2. 部署前请检查169.254.20.10有无被占用,如有,可跟换169.254.20.10/24网段其他未被占用的ip地址

部署步骤

  1. 确定image,ip以及端口后,将以上yaml保存为nodelocaldns.yaml(文件名可以自定义);

  2. 在磐基管理机上部署执行:
    kubectl apply -f nodelocaldns.yaml
    执行输出以下内容,则表示创建和部署成功成功:
    在这里插入图片描述
    在这里插入图片描述
    Node-cache 进程监听相应ip端口(53,9253,9353,28080),优先接收响应流量,进而代理coredns解析,起到被动缓存的作用
    在这里插入图片描述
    Pod node-local日志
    在这里插入图片描述
    在这里插入图片描述
    以上说明,nodelocaldns在当前宿主机正常监听169.169.0.100流量 ,即代理kube-dns的解析转发到新的kube-dns-upstream服务(代理coredns服务,详解配置文件)。

验证结论

正常接收dns域名解析请求:

在这里插入图片描述
在这里插入图片描述
性能验证,经过多轮,每轮至少5次压测脚本执行,平均以及99耗时已有明显提升:
在这里插入图片描述
至此 nodelocaldns部署完成,正常提供解析功能。

回滚方案

相对应地,如果正常下线nodelocaldns(不可强制下线),则可以执行:
kubectl delete -f nodelocaldns.yaml
在这里插入图片描述
下线成功:
在这里插入图片描述

回滚验证

执行上述回滚命令后,宿主机已无node-cache服务监听 169.169.0.100和169.254.20.10的相关端口了:
在这里插入图片描述
且 iptable kube-dns规则正常生效:
在这里插入图片描述
回滚后,原coredns正常解析:
在这里插入图片描述
表明:回滚完成,nodelocaldns已正常下线

注意事项

  1. 确保所用ip以及相应端口不被占用,以免端口或ip冲突,造成启动失败或者启动后运行异常;
  2. 确保镜像为官方拉取的镜像,并部署时可正常拉取;
  3. 资源使用最小配置(request):cpu 35m,memory 30Mi,最大限制(limit)根据实际情况可适当放宽;
  4. 确保执行正常部署和混滚命令,避免强制删除,并注意部署和回滚验证;
  5. 确保尽可能接入监控平台并配置,并配置报警
  6. 确保宿主机有足够的pod额度

NodeLocalDNS介绍

NodeLocal DNSCache 通过在集群节点上运行一个 DaemonSet 来提高 clusterDNS 性能和可靠性。
处于 ClusterFirst 的 DNS 模式下的 Pod 可以连接到 kube-dns 的 serviceIP 进行 DNS 查询。通过 kube-proxy 组件添加的 iptables 规则将其转换为 CoreDNS 端点。通过在每个集群节点上运行 DNS 缓存,NodeLocal DNSCache 可以缩短 DNS 查找的延迟时间、使 DNS 查找时间更加一致,以及减少发送到 kube-dns 的 DNS 查询次数,流程示意图如下:
在这里插入图片描述
参考链接
1、https://github.com/kubernetes/kubernetes/blob/release-1.23/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
2、https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/nodelocaldns/
3、案例:https://www.ctyun.cn/document/10025153/10110270
4、问题剖析:https://www.weave.works/blog/racy-conntrack-and-dns-lookup-timeouts
5、附件物料可咨询博主

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/25670.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apollo Cyber 学习笔记

目录 0 Introduction What Why Advantage 1 Example 2 Concept 3 Flow Chart 4 Module 4.1 Transport 4.1.1 Share Memory 4.1.1.1 Segment 4.1.1.1.1 State 4.1.1.1.2 Block 4.1.1.1.3 Common 4.1.1.2 Notifier 4.1.1.2.1 ConditionNotifier 4.1.1.2.2 Multi…

正浩创新内推:校招、社招EcoFlow社招内推码: FRQU1CY

EcoFlow社招内推码: FRQU1CY 投递链接: https://ecoflow.jobs.feishu.cn/s/Vo75bmlNr6c

FreeRTOS-中断管理

实验目的 创建一个队列及一个任务&#xff0c;按下按键 KEY1 触发中断&#xff0c;在中断服务函数里向队列里发送数据&#xff0c;任务则阻塞接 收队列数据。 实验代码 实验结果 这样就实现了&#xff0c;使用中断往队列的发送信息&#xff0c;用任务阻塞接收信息

【通俗讲解电子电路】——从零开始理解生活中的科技(一)

导言&#xff1a;电子电路为什么重要&#xff1f; ——看不见的“魔法”&#xff0c;如何驱动你的生活&#xff1f; 清晨&#xff0c;当你的手机闹钟响起时&#xff0c;你可能不会想到&#xff0c;是电子电路在精准控制着时间的跳动&#xff1b;当你用微波炉加热早餐时&#…

无人机与AI!

一、技术革新&#xff1a;AI赋能无人机智能化 自主导航与避障 AI通过深度学习与计算机视觉技术&#xff0c;使无人机能够在复杂环境中实时分析飞行路径、预测障碍物并自主调整路线。例如&#xff0c;微分智飞推出的P300无人机可在无GPS信号的环境下完成自主导航&#xff0c;利…

基因型—环境两向表数据分析——品种生态区划分

参考资料&#xff1a;农作物品种试验数据管理与分析 用于品种生态区划分的GGE双标图有两种功能图&#xff1a;试点向量功能图和“谁赢在哪里”功能图。双标图的具体模型基于SD定标和h加权和试点中心化的数据。本例中籽粒产量的GGE双标图仅解释了G和GE总变异的53.6%&#xff0c;…

【江科大STM32】TIM输出比较(学习笔记)

本章图片文字内容也为重要知识&#xff0c;请马住&#xff01; 输出比较简介 OC&#xff08;Output Compare&#xff09;输出比较输出比较可以通过比较CNT与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形…

在Linux上安装MySQL

1.下载Linux版MySQL安装包 https://downloads.mysql.com/archives/community/ 2. 上传MySQL安装包 &#xff08;FinalShell示例&#xff09; 3. 创建目录,并解压 mkdir mysqltar -xvf mysql-8.0.26-1.el7.x86_64.rpm-bundle.tar -C mysql4. 安装mysql的安装包 cd mysqlr…

MyBatis的关联映射

前言 在实际开发中&#xff0c;对数据库的操作通常会涉及多张表&#xff0c;MyBatis提供了关联映射&#xff0c;这些关联映射可以很好地处理表与表&#xff0c;对象与对象之间的的关联关系。 一对一查询 步骤&#xff1a; 先确定表的一对一关系确定好实体类&#xff0c;添加关…

智能AI替代专家系统(ES)、决策支持系统(DSS)?

文章目录 前言一、专家系统&#xff08;ES&#xff09;是什么&#xff1f;二、决策支持系统&#xff08;DSS&#xff09;是什么&#xff1f;1.决策支持系统定义2.决策系统的功能与特点3.决策支持系统的组成 三、专家系统&#xff08;ES&#xff09;与决策支持系统&#xff08;D…

C++学习之函数、指针、字符串

一.函数; 1.函数的定义和调用 2.函数的声明 3.函数的分类 4.函数的值传递 5.函数的分文件编写 //#define _CRT_SECURE_NO_WARNINGS //#include<stdio.h> //#include<string.h> //#include<stdlib.h> //#include "test.h" // // //int main() //{ …

C#-委托

Action 无返回值&#xff0c;多线程常用 Action<string> action1 (name) > Console.WriteLine($"hello {name}"); action1("tom"); Func 有返回值&#xff0c;扩展方法常用&#xff0c;最后一个参数是输出参数 Func<int, int, double>…

场景重建——Nerf场景重建

3DGS和Nerf的区别 一、概念二、3DGS区别三、相关工作三、Nerf相关工作3.1、Point-NeRF&#xff08;CVPR2022:Point-Based Neural Radiance Fileds&#xff09;3.2、Plenoxels(CVPR2022:Radiance Fields without Neural Networks)3.3、MARS: An Instance-aware, Modular and Rea…

java jar包内的jar包如何打补丁

问题描述&#xff1a; 主包&#xff1a;hisca.jar&#xff0c;解压后 BOOT-INFO/lib下有其他jar包 因为一个小bug&#xff0c;需要修改这个hisca包下BOOT-INF/lib下的子jar包service-hisca-impl-1.0.0.jar中的一个service类及xml文件 操作步骤&#xff1a; 1、主包jar -xvf …

一文读懂,外贸中的invoice是什么意思?如何制作?

在外贸领域&#xff0c;invoice 这一词汇频繁出现&#xff0c;它对于国际贸易的顺利进行起着至关紧要的作用。本文将深入剖析外贸中 invoice的具体含义、与商业发票的区别&#xff0c;以及其开具流程与注意事项&#xff0c;同时向大家推荐一款高效实用的发票制作工具 ——Zoho …

【论文笔记-TPAMI 2024】FreqFusion:用于密集图像预测的频率感知特征融合

Frequency-aware Feature Fusion for Dense Image Prediction 用于密集图像预测的频率感知特征融合 Abstract&#xff1a;密集图像预测任务要求具有强类别信息和高分辨率精确空间边界细节的特征。为了实现这一点&#xff0c;现代分层模型通常利用特征融合&#xff0c;直接添加…

DeepSeek 专家级操作手册详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;趣享先生的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&…

【Django自学】Django入门:如何使用django开发一个web项目(非常详细)

测试机器&#xff1a;windows11 x64 python版本&#xff1a;3.11 一、安装Django 安装步骤非常简单&#xff0c;使用pip安装就行 pip install django安装完成之后&#xff0c;python的 Scripts 文件夹下&#xff0c;会多一个 django-admin.exe (管理创建django项目的工具)。…

优云智算:借助强大镜像社区,开启AI算力新纪元!

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux网络编程 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ 目录 前言&#xff1a; 平台介绍&#xff1a; …

抖音生活服务加强探店内容治理,2024年达人违规率下降30%

发布 | 大力财经 2月27日&#xff0c;抖音生活服务发布《2024抖音生活服务消费者权益保护年度报告》&#xff08;以下简称“报告”&#xff09;。报告显示&#xff0c;过去一年&#xff0c;抖音生活服务针对消费者反感的虚假、夸张探店内容&#xff0c;开展了专项治理。通过一…