Docker嵌入式DNS解析器如何工作?

9q78igpj  于 2022-11-22  发布在  Docker
关注(0)|答案(2)|浏览(204)

我知道Docker有一个嵌入式DNS解析器。
当我在自己的桥中运行一个容器时:

$ docker run -it --rm --privileged --network=mybridge xxx bash

root@18243bfe6b50:/# cat /etc/resolv.conf  
nameserver 127.0.0.11  
options ndots:0  

root@18243bfe6b50:/# netstat -anop  
Active Internet connections (servers and established)  
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer  
tcp        0      0 127.0.0.11:45997        0.0.0.0:*               LISTEN      -                off (0.00/0/0)  
udp        0      0 127.0.0.11:49614        0.0.0.0:*        

it shows there is a dns resolver, and iptables help do a port transfer.  

root@18243bfe6b50:/# iptables -nvL -t nat  
.....  
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:45997  
    0     0 DNAT       udp  --  *      *       0.0.0.0/0            127.0.0.11           udp dpt:53 to:127.0.0.11:49614  

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:45997 to::53  
    0     0 SNAT       udp  --  *      *       127.0.0.11           0.0.0.0/0            udp spt:49614 to::53  

but, which process is the dns resolver? I guess it is dockerd?  but dockerd is running in host network namespace, obviously it is different with the container network namespace, also, I can not find dockerd has dns port listening in host:  

root@test:~# netstat -tnop |grep dockerd  
tcp        0      0 10.5.79.50:59540        10.5.79.50:2377         ESTABLISHED 3332/dockerd     off (0.00/0/0)  
tcp        0      0 127.0.0.1:35792         127.0.0.1:2377          ESTABLISHED 3332/dockerd     off (0.00/0/0)  
tcp6       0      0 10.5.79.50:2377         10.5.79.70:45934        ESTABLISHED 3332/dockerd     off (0.00/0/0)  
tcp6       0      0 127.0.0.1:2377          127.0.0.1:35792         ESTABLISHED 3332/dockerd     off (0.00/0/0)  
tcp6       0      0 10.5.79.50:2377         10.5.79.50:59540        ESTABLISHED 3332/dockerd     off (0.00/0/0)

一个进程(dockerd)如何在主机名称空间和其他名称空间(容器)中公开一些端口?2我读了一些代码,但仍然不能弄清楚,有人能帮忙回答吗?
谢谢你的好意。

dz6r00yl

dz6r00yl1#

也许你已经找到了那个Docker Libnetwork将解析器绑定到容器的环回接口,以便路由127.0.0.11上的DNS查询(通过iptables)到Docker引擎中的“后端DNS解析器”。请参阅libnetwork类型和实际的ResolveName每个容器的沙盒允许通过网络命名空间路由DNS查询。
关于您提出的一个进程如何公开主机上和容器内的端口的问题:在这种情况下,将处理线程绑定到接口是一个更合适的表达。Docker引擎创建一个容器并配置其网络名称空间,因此它也可以配置容器的网络接口和通过iptables的数据包路由。将解析器绑定到容器的内部接口是您在侦听端口53的主机上没有找到任何进程的原因。

w6lpcovy

w6lpcovy2#

谢谢@gesellix
Docker的作用:
1.嵌入式DNS解析器(dockerd)将net NS切换到Container(使用setns系统调用)
1.在127.0.0.11:xxxx收听,并返回到其源网络NS。
1.使用iptables DNAT和SNAT规则,将端口53转发到xxxxx。
1.使用/etc/resolv.conf来命名服务器127.0.0.11
我猜是因为dockerd不在容器的pid_namespace中,所以你看不到容器中的PID/程序名。
在www.example.com上查看dockerd监听127.0.0.11:
1.获取容器ID: Docker
1.获取容器PID:码头检查--格式“{{.状态.Pid}}”89 c249 fc 51 f6
1.在容器网络NS中运行命令:nsenter -n -t 3794 ss -lnutp(备选:网络统计-anop)
您将看到类似以下内容:

Netid State   Recv-Q  Send-Q    Local Address:Port    Peer Address:Port                                                                                       
    udp   UNCONN  3072    0            127.0.0.11:43418        0.0.0.0:*      users:(("dockerd",pid=1348,fd=63))
    tcp   LISTEN  0       128          127.0.0.11:34643        0.0.0.0:*      users:(("dockerd",pid=1348,fd=65))

1.要查看iptables规则:插入器-n -t 3794 iptables -nvL -t nat
(In某些Linux发行版使用“iptables-legacy”替换“iptables”)

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:34643
    4   242 DNAT       udp  --  *      *       0.0.0.0/0            127.0.0.11           udp dpt:53 to:127.0.0.11:43418

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:34643 to::53
    0     0 SNAT       udp  --  *      *       127.0.0.11           0.0.0.0/0            udp spt:43418 to::53

关于libnetwork代码:
在解析器中

// SetupFunc() provides the setup function that should be run
    // in the container's network namespace.

在此处调用InvokeFunc

if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0));

定义调用函数

func (n *networkNamespace) InvokeFunc(f func()) error {
    return nsInvoke(n.nsPath(), func(nsFD int) error { return nil }, func(callerFD int) error {
        f()
        return nil
    })
}

在nsInvoke中,您将看到netns.Set

...
netns.GetFromPath(path)
...
netns.Set(newNs)
...

访问github.com/vishvananda/netns查看函数的详细信息

相关问题