- 作者:老汪软件技巧
- 发表时间:2024-09-28 21:01
- 浏览量:
前言
在现公司,之前给部门推荐过边缘云架构以及openyurt等一系列方案,部门也很给力,现在正在使用阿里云的AckEdge进行边缘云架构的落地。
在落地过程中,肯定会遇到很多架构性以及k8s网络的问题,今天(2024-9-27)就遇到了一个DNS问题。索性一次性的将K8S下云原生的DNS原理分析一波。
理论知识
首先需要解释一下什么是openyurt,ackedge。那么介绍openyurt,ackedge之前,简单说明下什么是边缘云:
在边缘云计算中,"云"、"边"和"端"分别扮演着不同的角色和功能:
云(Cloud):
○ 在边缘云中,"云"通常指的是中心数据中心或云数据中心,它提供了存储、计算、网络等基础设施服务。这些服务可以用来支持边缘设备和边缘节点的工作,例如提供数据分析、模型训练、数据存储等功能。
○ 云还负责管理边缘计算资源的分配和调度,以确保边缘计算节点能够高效地执行任务,并与中心数据中心或云数据中心进行协作。
边(Edge):
○ "边"通常指的是边缘计算节点,它位于物理世界中更接近数据源头或消费者的位置。边缘节点可以是部署在边缘设备上的小型计算设备,也可以是边缘网关或基站等中间节点。
○ 边缘节点负责处理和存储数据,并执行一些简单的计算任务,例如数据过滤、数据预处理、实时数据分析等。这样可以降低数据传输到中心数据中心或云数据中心的延迟,并减轻网络带宽的压力。
端(Endpoint):
○ "端"通常指的是边缘设备,它是数据生成源头或数据消费者,例如传感器、摄像头、智能手机等。端设备负责收集和生成数据,并将数据传输给边缘节点或中心数据中心进行处理和分析。
○ 在边缘云中,端设备可以通过边缘节点来与云进行通信,并利用云提供的服务来实现更复杂的数据处理和分析任务。同时,端设备也可以从云中获取数据和模型,并根据需要进行相应的操作和反馈。
边缘云的实现方式有很多种,但我的经验全是kubernetes模式下,所以后面都为kubernetes的相关分析
架构选择
多集群模式:在云,边采用独立的kubernetes集群,集群间独立。(在前公司sangfor采用)
大集群模式:云,边端同为一个kubernetes集群,工作节点划分为Cloud,Edge两种节点类型。
cloud:表明与kubernetes控制面部署在一起,即云上工作集群,跟kubernetes的node差别不大。Edge:边缘上的工作节点,每个边缘机房部署若干台,特点:可实现边缘自治,允许与中心节点网络断联情况下,正常执行。(现公司采用)
而openyurt为阿里开源的边缘云框架,ackedge为openyurt的收费版本。 对应的华为云开源了kubeedge也为边缘云框架。
问题
在开发过程中,将服务部署到边缘节点上后,测试发现服务在访问内部域名服务的时候,pod无法解析内部域名报错:
dial tcp: lookup a.xxx.com on 172.17.0.10:53. no such
相信经常访问不到域名服务的同学已经发现,这是dns无法解析导致的问题。在虚拟机/实体机上非常好处理:
配置/etc/hosts。配置/etc/resolve.conf,查看里面是否包含内部DNS服务器。将内部域名转化为具体服务的IP。
以上三种方式就能解决。
但现在是kubernetes时代下,第一个问题:pod内部通常情况下,域名通过CoreDNS获取。
请注意:我说的是通常情况下,在编写kubernetes manifest时,一般情况下都不会改变pod的dnsPolicy。
dnsPolicy:
那么这个问题,已经找到了第一个点:不符合集群域后缀,会转发给上游DNS服务器。从coredns日志中,也能查看到:
从日志中可以查看到,coredns在查询记录时,会默认在域名后面先添加.alpha01.svc.cluster.local. 进行查询,然后,每次将前面的一个字段去掉继续查询:.... 。** **从性能的考虑,这样会非常耗费性能。
从日志中查看到最后一条记录:udp 35 false 512" NXDOMAIN qr,rd,ra 118 0.207400241s ,表明没有查询到域名记录,稍微解释下日志的重要字段:
qr,rd,ra:查询标志,qr 表示这是一个响应,rd 表示请求是递归的,ra 表示可用递归。
0.207400241s:处理请求所花费的时间
而记录A, AAAA分别代表:IPv4,Ipv6。
查询到这里又发现一个有趣的现象:DNS解析一段时间好,一段时间不好。 这个现象引起了一个边缘云架构service特征的排查。
service
在同一个kubernetes集群内,pod间通过svc进行访问。
注:service只是iptables或者ipvs的一条映射记录,是无法使用ping进行探测的。
有这么一个服务A,在每个边缘云节点都需要部署,按照之前的逻辑我们使用deployment的情况,那么无法保证每个边缘云节点都部署,当然也可以使用:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: alibabacloud.com/nodepool-id
operator: In
values:
- np646de94ce1714cb59a95e80e4a49f0cf
topologySpreadConstraints:
- maxSkew: 1
topologyKey: alibabacloud.com/nodepool-id
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: A
来确保每个边缘云节点都部署了个服务。说实话topologySpreadConstraints这个我没见过。所以我采用的使用直接使用ackEdge的YurtAppSet 自定义资源,它可以确保每个nodePool都部署一个相同的deployment。 那么什么是nodePool:
在边缘云架构下,不可能每个机房只放一台node作为工作节点,这样缺少容错性,所以ackEdge提供了NodePool,可以将多台机器放到一个NodePool里作为一个节点池。
但是这里还有一个问题,每个节点池中都有一个相同的deployment,那么在编写services的时候,Selector会将所有节点都作为Endpoints,引发一个问题:
画板
这样肯定不是我们想要的。是不是可以每个node都编写不同的svc,不同的Selector?可以,但是运维成本非常大,每个服务A都需要进行动态的拼接访问的SVC,这样太low了。
ackEdge在nodePool基础上提供了services的注解,让同个nodepool内部闭环。
annotation Keyannotation Value说明
openyurt.io/topologyKeys
kubernetes.io/hostname
限制Service只能被本节点访问。
openyurt.io/topologyKeys
kubernetes.io/zone或openyurt.io/nodepool
限制Service只能被本节点池的节点访问。ACK Edge集群版本如果大于等于1.18,推荐您使用openyurt.io/nodepool。
会不会是路由到其他节点CoreDns?
接下来,通过使用两个工具来分析pod内部具体访问了哪个coredns:nslookup和tcpdump;
在宿主机上,执行: tcpdump -i any -nn port domain and host 172.17.5.163 ;
在pod内部持续使用:watch -d "nslookup " ;其中172.17.5.163为pod的ip地址。
注:只有宿主机上才能获取到coredns对应的后端。
tcpdump port domain:说明只抓取DNS报文
抓包截图如下:
其中192.168.0.10:53为coredns的svc,172.17.5.159:53为coredns的后端。持续watch的情况下,发现只有本NodePool节点的coredns进行回报。查看coredns的services配置文件发现:
所以不是这个问题。
会不会是configmap的配置问题?
这里可以看到forward章节说明:可转发到宿主机的/etc/resolv.conf中所定义的上游服务器,内部perfer_udp表明coredns优先使用UDP进行发包。
coredns中没有定义,说明forward上面的章节都无法匹配,然后从/etc/resolv.conf定义的服务器进行DNS解析,查看/etc/resolv.conf:
nameserver 127.0.0.53
options edns0 trust-ad
这个域名服务器看上去怪怪的,但是127.0.0 还是能说明可能是本机的某个服务监听的:
netstat -anlpt |grep 127.0.0.53
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 35957/systemd-resol
systemd-resol又是个什么服务?
systemd-resolved 是一个由 systemd 提供的网络名称解析服务。它的主要功能是处理 DNS 查询,并提供名称解析服务
那么也就说明coredns的上游请求的为systemd-resolved服务?而kubelet.yml中resolvConf也配置成了/run/systemd/resolve/resolv.conf。而这个文件正式systemd-resolved生成的动态DNS配置文件,这个文件中显示:
nameserver 10.53.136.xxxxx
nameserver 10.53.136.2xxxx
nameserver 223.5.5.5
# Too many DNS servers configured, the following entries may be ignored.
nameserver 223.6.6.6
上面两个为机房侧内部DNS域名,而下面两个为阿里云域名服务器。那么,有没有一种可能:在请求的时候,一下请求的为内部域名,而过一阵由请求了阿里云DNS服务器?通过阿里云DNS服务器解析:
nslookup: a.xxxxx.com 223.5.5.5
Server: 223.5.5.5
Address: 223.5.5.5#53
** server can't find a.xxxxxx.com: NXDOMAIN
从现象来看,满足我们的猜想。
如何确定DNS服务具体是哪一个?
通过在宿主机上抓包:
tcpdump -i any -nn port domain |grep a.xxxx
通过持续抓包发现,在无法解析情况下,报文如下:
终于定位到了问题了。只要将/run/systemd/resolve/resolv.conf文件中的阿里云DNS服务器删除即可。
但是删除重启systemd-resolved后,又出现了现象,查看/run/systemd/resolve/resolv.conf又存在了阿里云DNS服务器。
同运维交流后,需要在ubuntu环境下需要在网卡中删除内置nameserver, 再使用 netplan apply 生效。
为什么一下好一下不好?
使用dig命令,我们来查看DNS解析路径:
dig @172.17.5.159 a.xxx.com
;; ANSWER SECTION:
a.xxxxx.com. 6 IN A 10.53.33.38
6表明了缓存时间时间,发现每次查到数字都为30,那么也就说明查询到后缓存30s。而后面没有查询到的情况下,显示如下:
;; AUTHORITY SECTION:
xxxxx.com. 21 IN SOA dns3.hichina.com. hostmaster.hichina.com. 2024090313 3600 1200 86400 600
从顶级域名下也缓存了30秒左右。
总结
通过这一次的排查,对于coredns以及DNS排查工具/排查过程有了更加清晰的了解。