• 作者:老汪软件技巧
  • 发表时间: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排查工具/排查过程有了更加清晰的了解。