k8s ndots 理解与配置优化

[TOC]

/etc/resolv.conf

这个文件是 linux 里的一个配置文件,做 dns 解析用的

https://linux.die.net/man/5/resolv.conf

在 k8s pod 里长这个样子,pod 里面执行 cat /etc/resolv.conf

nameserver 172.23.0.10
search backend.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5

其中 nameserver 就是 corednsservice (也就是 kube-dns) 的 ip (虚拟ip,也叫 vip)
search 是搜索顺序, backend 是pod所在命名空间
options 是一些选项

ndots 含义

ndots 意思就是 点号. (dot) 的个数
ndots: 5 就是 5个点号

5个点号 的意思就是说
对于一个 域名, 如果不是完全限定名(即某个域名不是以. 结尾, a.com 不是, a.com. 是)
且点号数量少于5个, 那么就按照 search 的顺序,依次解析
如果点号大于或者等于5, 直接解析

如上面的 search 配置项表达的解析顺序就是

  1. backend.svc.cluster.local
  2. svc.cluster.local
  3. cluster.local
  4. localdomain

举例说明
假设有两个服务,ABA 现在要请求 B 的接口 GET /api/b/users
那么请求可以长这个样子 GET http://B/api/b/usres, B 服务的name 可以当成 域名来用
HTTP 报文如下

GET /api/b/users HTTP/1.1
Host: B
Accept: */*
Content-Type: application/json

实际解析域名的时候,按照顺序解析,解析到就返回 ip
顺序如下

  1. B.backend.svc.cluster.local
  2. B.svc.cluster.local
  3. B.cluster.local
  4. B.localdomain
  5. B

也就是说我们访问B的服务,域名的写法可以有很多种,都是支持的,如:

  • GET http://B/api/b/usres
  • GET http://B.backend/api/b/usres
  • GET http://B.backend.svc/api/b/usres

既然有这么多种写法,那么有没有最优解呢?

数量对比试验

ndots=5, 域名点号=4

# cat /etc/resolv.conf
nameserver 172.23.0.10
search backend.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5

# host -av r-wz9f2fc78874fa04.redis.rds.aliyuncs.com
Trying "r-wz9f2fc78874fa04.redis.rds.aliyuncs.com.backend.svc.cluster.local"
Trying "r-wz9f2fc78874fa04.redis.rds.aliyuncs.com.svc.cluster.local"
Trying "r-wz9f2fc78874fa04.redis.rds.aliyuncs.com.cluster.local"
Trying "r-wz9f2fc78874fa04.redis.rds.aliyuncs.com.localdomain"
Trying "r-wz9f2fc78874fa04.redis.rds.aliyuncs.com"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29554
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;r-wz9f2fc78874fa04.redis.rds.aliyuncs.com. IN ANY

;; ANSWER SECTION:
r-wz9f2fc78874fa04.redis.rds.aliyuncs.com. 19 IN A 172.16.4.243

Received 116 bytes from 172.23.0.10#53 in 0 ms

通过日志可以发现

  • 此时配置里的点号是5, ndots:5
  • 而我们的域名包含4个点 ., 4小于5,所以按照seacrh顺序添加后缀之后依次解析,都解析不到的情况下不加后缀去解析,日志Trying可以证明这一点

可以看出来,策略就是: 优先把域名当成内网的来解析,内网解析不到就当成外网去解析

ndots=4, 域名点号=4

 # cat /etc/resolv.conf
nameserver 172.23.0.10
search backend.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:4

 # host -av r-wz9f2fc78874fa04.redis.rds.aliyuncs.com
Trying "r-wz9f2fc78874fa04.redis.rds.aliyuncs.com"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37171
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;r-wz9f2fc78874fa04.redis.rds.aliyuncs.com. IN ANY

;; ANSWER SECTION:
r-wz9f2fc78874fa04.redis.rds.aliyuncs.com. 30 IN A 172.16.4.243

Received 116 bytes from 172.23.0.10#53 in 1 ms

通过日志可以发现

  • 此时配置里的点号是4, ndots:4
  • 而我们的域名包含4个点 ., 4小于4,所以按照seacrh顺序解析,直接拿来解析,日志Trying可以证明这一点

ndots=3, 域名点号=4

# cat /etc/resolv.conf
nameserver 172.23.0.10
search backend.svc.cluster.local svc.cluster.local cluster.local
options ndots:3

# host -av r-wz9f2fc78874fa04.redis.rds.aliyuncs.com
Trying "r-wz9f2fc78874fa04.redis.rds.aliyuncs.com"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 549
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;r-wz9f2fc78874fa04.redis.rds.aliyuncs.com. IN ANY

;; ANSWER SECTION:
r-wz9f2fc78874fa04.redis.rds.aliyuncs.com. 30 IN A 172.16.4.243

Received 116 bytes from 172.23.0.10#53 in 1 ms
  • 此时配置里的点号是3, ndots:3
  • 而我们的域名包含4个点 ., 4小于3,所以按照seacrh顺序解析,直接拿来解析,日志Trying可以证明这一点

上面都是外网域名,接下来试一下内网的

ndots=3, 内网域名点号=1

# cat /etc/resolv.conf
nameserver 172.23.0.10
search backend.svc.cluster.local svc.cluster.local cluster.local
options ndots:3

# host -av b.backend
Trying "b.backend.backend.svc.cluster.local"
Trying "b.backend.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41190
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;agent-app-service.backend.svc.cluster.local. IN    ANY

;; AUTHORITY SECTION:
cluster.local.      30  IN  SOA ns.dns.cluster.local. hostmaster.cluster.local. 1568253402 7200 1800 86400 30

Received 154 bytes from 172.23.0.10#53 in 1 ms
  • 1小于3,所以会尝试;
  • 在尝试第二次的时候就找到了

如何调整

终上所述,对于内网域名、外网域名,我们都希望尽可能少的进行 DNS 解析,以便提升性能
对于内网域名,这个好说,因为都是我们的代码可以控制的,可以改;外网域名改不了,着重研究一下

我们的服务对于外部调用比较频繁的大概有三类 redis mongodb es

  • redis
    r-xxx.redis.rds.aliyuncs.com 4个点号
  • mongodb
    dds-xxx.mongodb.rds.aliyuncs.com 4个点号
  • es
    es-xxx.elasticsearch.aliyuncs.com 3个点号

想要外网地址不走k8s解析的,可以取最小值3

所以,我们可以设置点号数量为 3

  1. 对于外部调用,3可以覆盖,直接解析
  2. 对于内部调用,直接要求大家写成全限定名 serviceName.namespace.svc.cluster.local. ,也是直接解析的

之所以不设置为1 (毕竟设置为1也是可以的), 就是想保留这个特性,在手动测试的时候,因为不追求性能,所以可以少写一点,如 get http://b/api/users 很方便

如何修改

ndots 默认的值是1, coredns 将其设置成5了
但是,想要修改 ndots ,不是去修改 coredns 的配置,走了一些弯路,这里贴出来

coredns
首先想的是去修改 CoreDNS 的配置项

coredns 的配置文件复制出来,可以看见
其配置文件并没有 ndots选项

nameserver 100.100.2.136
nameserver 100.100.2.138
options timeout:2 attempts:3 rotate single-request-reopen

手动修改

进入容器里面手动修改是没有用的,需要重启网络模块才会生效
一重启容器没了,改了等于白改

init containers

initContainers 也是一堆坑

k8s yaml

其实k8s 给我们提供了参数,叫做 dnsConfig, 如下所示

dnsConfig:
        options:
          - name: ndots
            value: '3'
dnsPolicy: ClusterFirst

所以最后,我们选择了使用 k8s yaml 的方式来修改,对于老的服务直接修改;对于新的服务,在上线模板里配置好这个值

参考文章

https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/

你可能感兴趣的:(k8s ndots 理解与配置优化)