Istio dns 原理详解
文章目录
问题背景
在之前使用 ServiceEntry 和 EnvoyFilter 来接入 dubbo 服务到 istio 中时,最开始一直疑惑,当 consumer 端使用 ServiceEntry 中的 host 去访问,但 EnvoyFilter 中直接使用的是 addresses 和端口来进行过滤器匹配的,下发的 envoy 配置中也是用的 ip+port,ServiceEntry 并不会生成 service,那 host 到 ip 是如何转换的呢?
具体的例子参考 手动接入 dubbo 到 istio,设置的 ServiceEntry 如下:
|
|
envoy 端收到的配置中:
|
|
DNS 逻辑
Kubernetes 中 DNS 逻辑
Kubernetes 的 DNS 实现基于 CoreDNS,是一种轻量级的 DNS 服务器。Kubernetes 中每个 service 会配置一个 DNS 名称和 cluster ip,DNS 名称格式为:
|
|
在 pods 中查 DNS 服务器的配置/etc/resolv.conf 为:
|
|
nameserver 指向 kube-dns 的 cluster ip,即 pod 先通过请求 dns 文件中配置 dns 服务器,由 dns 服务器做域名解析转换成对应的 cluster ip,然后通过 cluster ip 去访问。
Istio 中 DNS 测试
当在 Istio 设置了前面提到的 ServiceEntry 后,用 nslookup 测试解析过程,发现仍然是去 dns 文件中的服务器请求的:
|
|
ServiceEntry 没有生成对应的 service,在 kubernetes 的 coredns 中应该是没有信息的,为啥还是会去 coredns 请求的呢?istio 中 envoy 会劫持流量,难道是被 envoy 转到 istio 去获取的? 为了验证此想法,在 pods 外面也测试了下 dns 解析结果:
|
|
可以发现,kubernetes 原生的 service 可以找到,ServiceEntry 中的 host 没有找到,因此确定不是去 coredns 解析的。
ISTIO_META_DNS_CAPTURE 配置
Istio 可以捕获 DNS 请求,以提高网格的性能和可用性。 当 Istio 代理 DNS 时,所有来自应用程序的 DNS 请求将会被重定向到 Sidecar,因为 Sidecar 存储了域名到 IP 地址的映射。如果请求被 Sidecar 处理,它将直接给应用返回响应,避免了对上游 DNS 服务器的往返。反之,请求将按照标准的/etc/resolv.conf DNS 配置向上游转发。Istio 的 DNS 有以下两个作用:
- ServiceEntry 地址可以被解析,而不需要自定义 DNS 服务配置
- 减少了 kube-dns 的负载,并且提高了性能
Istio 是通过“ISTIO_META_DNS_CAPTURE”配置来开启 DNS 代理的,如下所示:
|
|
在 consumer 的 pod 描述中可以看到,在 init 容器 istio-init 和 sidecar 容器 istio-proxy 中都设置了 ISTIO_META_DNS_CAPTURE 环境变量,通过这两个容器来使 dns 生效的。
|
|
查看 iptables 规则:
|
|
其中有涉及到 dns 规则或者端口的有:
- OUTPUT 链中的第 2 条:udp 协议,端口为 53,且 UID 为 1337(Envoy 代理用户),表示 envoy 发出的 dns 流量,则直接返回,把流量发送到任意目的地址。
- OUTPUT 链中的第 3 条:udp 协议,端口为 53,且 GID 为 1337(Envoy 代理组),表示 envoy 发出的 dns 流量,则直接返回,把流量发送到任意目的地址。
- OUTPUT 链中的第 4 条:udp 协议,端口为 53,目的 ip 为 kube-dns 的地址,表示应用容器发出的 dns 请求,则转发到本地 15053。
- ISTIO_OUTPUT 链中的第 8 条:tcp 协议,端口为 53,目的 ip 为 kube-dns 的地址,表示应用容器发出的 dns 请求,则转发到本地 15053。
源码分析
istio-iptables dns 源码
istio-iptables 是 istio 用在代理的 init 容器中,用来初始化 iptables 规则。对于 dns 捕获来说,也就是设置规则捕获 dns 相关的流量。 下面代码中获取了环境变量中 dns 捕获标识,初始化启动配置:
|
|
在 Run 函数中,如果设置了 dns 代理,则设置为:
|
|
这里只展示了部分 dns 相关代码,其他涉及 dns iptables 规则的代码和上面类似,比如像 udp 的 dns 规则、针对用户组的 dns 规则。
istio-agent dns 源码
istio-agent 跟上面一样,也是从环境变量获取值,然后写到 Agent 的配置结构体里:
|
|
在 Agent 的启动函数 Run 里面,调用 initLocalDNSServer 来开启 dns 服务器:
|
|
通过 NewLocalDNSServer 创建 dns 服务器,里面持有 dns 下游服务器配置,通过 StartDNS 启动 tcp 和 udp 的 dns 代理:
|
|
上面 lookupTable 是本地的域名缓存,从 initXdsProxy 函数中可以看到域名信息是通过 xds 获取的,然后更新到 lookupTable 的:
|
|
istio-discovery dns 源码
获取域名信息的服务发现类型是 nds,nds 在 istio-discovery 中对应的 Generate 实现如下:
|
|
上面的 Generate 最终会调用到 BuildNameTable 函数,生成一个域名和关联 ip 的表格,提供给代理解析 dns 使用:
|
|
参考
文章作者 yefengzhichen
上次更新 2023-03-29