[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
就是 coredns
的 service
(也就是 kube-dns
) 的 ip (虚拟ip,也叫 vip
)
search
是搜索顺序, backend
是pod所在命名空间
options
是一些选项
ndots 含义
ndots
意思就是 点号.
(dot) 的个数
ndots: 5
就是 5个点号
5个点号
的意思就是说
对于一个 域名, 如果不是完全限定名(即某个域名不是以.
结尾, a.com
不是, a.com.
是)
且点号数量少于5个
, 那么就按照 search
的顺序,依次解析
如果点号大于或者等于5, 直接解析
如上面的 search 配置项表达的解析顺序就是
- backend.svc.cluster.local
- svc.cluster.local
- cluster.local
- localdomain
举例说明
假设有两个服务,A
和B
, A
现在要请求 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
顺序如下
- B.backend.svc.cluster.local
- B.svc.cluster.local
- B.cluster.local
- B.localdomain
- 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
- 对于外部调用,
3
可以覆盖,直接解析 - 对于内部调用,直接要求大家写成全限定名
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/