有没有办法配置 Docker 的嵌入式 DNS 服务器的上游名称服务器的端口?

Is there a way to configure Docker's embedded DNS server's upstream nameserver's port?

一般背景

Docker 守护进程带有一个嵌入式 DNS 服务器。它解析本地 Docker 群和网络记录,并将对外部记录的查询转发到配置了 --dns 1.

的上游名称服务器

文档说您可以使用 --dns=[IP_ADDRESS...] 为这个上游域名服务器设置 IP 地址。使用的默认端口是 53。

我的问题

我也可以配置使用的端口吗?

我的主机 /etc/docker/daemon.json 显示 "dns": ["10.99.0.1"],。有没有办法让我指定类似 "dns": ["10.99.0.1:53"] 的内容,以便 dockerd 始终知道将 DNS 查询转发到端口 53?

我的用例

在我的例子中,10.99.0.1 是本地主机网桥接口的 IP。我 运行 此主机上的本地 DNS 缓存服务器。所以发送到 10.99.0.1:53 的 DNS 查询有效。但是 dockerd 将源自连接到用户定义的桥接网络(使用 docker network create 创建)的容器的查询转发到它选择的非标准端口。请参阅下面的终端输出。

详细的终端输出和调试信息

“toogle”是一个 Docker 容器,连接到我用 docker network create 创建的 Docker 网络。 127.0.0.11 是另一个环回地址。来自连接到用户定义的 Docker 网络的 Docker 个容器内的 DNS 查询被发往此 IP。

Docker 的嵌入式 DNS 服务器实际上是 运行ning 吗?

DNS 查询由 toogle 的防火墙规则以这种方式路由。

$ sudo nsenter -n -t $(docker inspect --format {{.State.Pid}} toogle) iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 1 packets, 60 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 1 packets, 60 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DOCKER_OUTPUT  all  --  *      *       0.0.0.0/0            127.0.0.11

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DOCKER_POSTROUTING  all  --  *      *       0.0.0.0/0            127.0.0.11

Chain DOCKER_OUTPUT (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            127.0.0.11           tcp dpt:53 to:127.0.0.11:37619   <-- look at this rule
    0     0 DNAT       udp  --  *      *       0.0.0.0/0            127.0.0.11           udp dpt:53 to:127.0.0.11:58552   <-- look at this rule

Chain DOCKER_POSTROUTING (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 SNAT       tcp  --  *      *       127.0.0.11           0.0.0.0/0            tcp spt:37619 to::53
    0     0 SNAT       udp  --  *      *       127.0.0.11           0.0.0.0/0            udp spt:58552 to::53

在这些端口上侦听的任何东西都在接受 TCP 和 UDP 连接

$ sudo nsenter -n -t $(docker inspect --format {{.State.Pid}} toogle) nc 127.0.0.11 37619 -vz

127.0.0.11: inverse host lookup failed: Host name lookup failure
(UNKNOWN) [127.0.0.11] 37619 (?) open

$ sudo nsenter -n -t $(docker inspect --format {{.State.Pid}} toogle) nc 127.0.0.11 58552 -vzu

127.0.0.11: inverse host lookup failed: Host name lookup failure
(UNKNOWN) [127.0.0.11] 58552 (?) open

但是两者都没有 DNS 回复

$ sudo nsenter -n -t $(docker inspect --format {{.State.Pid}} toogle) dig @127.0.0.11 -p 58552 accounts.google.com

; <<>> DiG 9.11.3-1ubuntu1.14-Ubuntu <<>> @127.0.0.11 -p 58552 accounts.google.com
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached


$ sudo nsenter -n -t $(docker inspect --format {{.State.Pid}} toogle) dig @127.0.0.11 -p 37619 accounts.google.com +tcp

; <<>> DiG 9.11.3-1ubuntu1.14-Ubuntu <<>> @127.0.0.11 -p 37619 accounts.google.com +tcp
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

dockerd 正在从 toogle 中侦听该 IP 和端口上的 DNS 查询。

$ sudo nsenter -n -p -t $(docker inspect --format {{.State.Pid}} toogle) ss -utnlp
Netid        State          Recv-Q         Send-Q                    Local Address:Port                    Peer Address:Port
udp          UNCONN         0              0                            127.0.0.11:58552                        0.0.0.0:*             users:(("dockerd",pid=10984,fd=38))
tcp          LISTEN         0              128                          127.0.0.11:37619                        0.0.0.0:*             users:(("dockerd",pid=10984,fd=40))
tcp          LISTEN         0              128                                   *:80                                 *:*             users:(("toogle",pid=12150,fd=3))

但是 dockerd 正在尝试将 DNS 查询转发到 10.99.0.1,这是我的 docker0 网桥网络接口。

$ sudo journalctl --follow -u docker
-- Logs begin at Tue 2019-11-05 18:17:27 UTC. --
Apr 22 15:43:12 my-host dockerd[10984]: time="2021-04-22T15:43:12.496979903Z" level=debug msg="[resolver] read from DNS server failed, read udp 172.20.0.127:37928->10.99.0.1:53: i/o timeout"
Apr 22 15:43:13 my-host dockerd[10984]: time="2021-04-22T15:43:13.496539033Z" level=debug msg="Name To resolve: accounts.google.com."
Apr 22 15:43:13 my-host dockerd[10984]: time="2021-04-22T15:43:13.496958664Z" level=debug msg="[resolver] query accounts.google.com. (A) from 172.20.0.127:51642, forwarding to udp:10.99.0.1"

dockerd 将请求名称服务器 127.0.0.11:58552 的 DNS 查询转发到 10.99.0.1,但仅更改 IP 而未更改端口。因此 DNS 查询被转发到 10.99.0.1:58552 并且该端口没有任何监听。

$ dig @10.99.0.1 -p 58552 accounts.google.com
[NO RESPONSE]

$ nc 10.99.0.1 58552  -vz
10.99.0.1: inverse host lookup failed: Unknown host
(UNKNOWN) [10.99.0.1] 58552 (?) : Connection refused

对 10.99.0.1:53 的 DNS 查询按预期工作。

dig @10.99.0.1 -p 53 accounts.google.com

; <<>> DiG 9.11.3-1ubuntu1.14-Ubuntu <<>> @10.99.0.1 -p 53 accounts.google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53674
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;accounts.google.com.       IN  A
;; ANSWER SECTION:
accounts.google.com.    235 IN  A   142.250.1.84
;; Query time: 0 msec
;; SERVER: 10.99.0.1#53(10.99.0.1)
;; WHEN: Thu Apr 22 17:20:09 UTC 2021
;; MSG SIZE  rcvd: 64

我认为没有办法做到这一点。我也误读了输出。 Docker 守护进程正在转发到端口 53。

read udp 172.20.0.127:37928->10.99.0.1:53: i/o timeout