我知道 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)如何暴露主机命名空间中的一些端口和其他命名空间(容器)中的一些端口?我读了一些代码,但仍然无法弄清楚,有人可以帮忙解答吗?
谢谢。
也许您已经发现 Docker(又名 Moby)内部使用
libnetwork
来配置和启用嵌入式 DNS 解析器。 Libnetwork 将解析器绑定到容器的环回接口,以便可以将 127.0.0.11
处的 DNS 查询路由(通过 iptables)到 Docker 引擎中的“后端 DNS 解析器”。请参阅 libnetwork 类型 和实际的 ResolveName() 代码。每个容器的沙箱允许通过网络命名空间路由 DNS 查询。
关于一个进程如何公开主机上和容器内部的端口的问题:在这种情况下,将处理程序线程绑定到接口将是一个更合适的表达。 Docker引擎创建一个容器并配置其网络命名空间,因此它还可以通过iptables配置容器的网络接口和数据包路由。将解析器绑定到容器的内部接口是您在主机上找不到任何监听端口 53 的进程的原因。
Docker 是做什么的:
setns
系统调用)
/etc/resolv.conf
至
nameserver 127.0.0.11
查看 dockerd 监听 127.0.0.11:
docker ps
docker inspect --format "{{.State.Pid}}" 89c249fc51f6
nsenter -n -t 3794 ss -lnutp
(或者:
nsenter -n -t 3794 netstat -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))
nsenter -n -t 3794 iptables -nvL -t nat
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
在
// 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));
defInvokeFunc
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)
...
前往https://github.com/vishvananda/netns