写点什么

docker 的 DNS 配置说明

作者:Geek_f24c45
  • 2022 年 2 月 23 日
  • 本文字数:1596 字

    阅读完需:约 5 分钟

在 daemon 没有主动配置 DNS 的情况下, 就是


  1. copy 宿主机 /etc/resolv.conf

  2. 过滤 本地地址 比如 127 xx


默认情况下,endpoint 加入 default bridge 网络中, 比如 docker run --rm -it xx


当使用自定义网络时, 比如 compose 中自定义了 bridge 网络, endpoint 加入了 新的 隔离 bridge 中,,


两者 访问外部网络都依靠 主机 forward , nat


自定义网络, 可以支持容器名字,服务名字解析, 是中间实现了一个 dns


docker run --rm --network=test_cluster_default --privileged  -it weibeld/ubuntu-networking /bin/bash
root@3e2e096e00c1:/# cat /etc/resolv.conf nameserver 127.0.0.11options timeout:1 attempts:2 ndots:0root@3e2e096e00c1:/# root@3e2e096e00c1:/# root@3e2e096e00c1:/#

所以使用 自定义网络时,看到的dns地址都是 127.0.0.11
内部使用 iptables 重定向了 dns 到内部的服务上
-A OUTPUT -d 127.0.0.11/32 -j DOCKER_OUTPUT-A POSTROUTING -d 127.0.0.11/32 -j DOCKER_POSTROUTING-A DOCKER_OUTPUT -d 127.0.0.11/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.11:45981-A DOCKER_OUTPUT -d 127.0.0.11/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:38095-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p tcp -m tcp --sport 45981 -j SNAT --to-source :53-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p udp -m udp --sport 38095 -j SNAT --to-source :53
内部dns 插入需要解析的内容,解析不到再 forward 到根据宿主机 /etc/resolv.conf 文件拿到的DNS地址
复制代码


这里有一个有趣的问题 "每一个容器都重定向了 DNS 的请求,实际请求都发到了 同一个 dockerd 服务, dockerd 服务在主机的 netns 下, 容器在自己的 netns 下, 数据怎么发过来的那?"


我们写一个 demo 程序,就能看明白了!


func main() {	// Lock the OS Thread so we don't accidentally switch namespaces	runtime.LockOSThread()	defer runtime.UnlockOSThread()
// Save the current network namespace origns, _ := netns.Get() defer origns.Close()
// Create a new network namespace newns, _ := netns.GetFromName("testns2") netns.Set(newns) defer newns.Close()
fmt.Println("enter ns testns2") // Do something with the network namespace ifaces, e := net.Interfaces()
if e != nil { fmt.Printf("get Interfaces error : %v\n", e) }
fmt.Printf("Interfaces: %v\n", ifaces) ln, err := net.Listen("tcp", ":9090") if err != nil { fmt.Printf("listen in ns error, %v", err) return }
// Switch back to the original namespace netns.Set(origns) fmt.Println("listen in original ns") for { conn, e := ln.Accept()
if e != nil { continue }
go handleConn(conn) }
}
复制代码


在主机上,运行该程序, 我们查看 testns2 下的监听情况, 如下, 能正常看到监听的 socket, 连接也是正常的, (其实主机 ns 下是看不到的)


ip netns exec testns2 netstat -anp  
Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp6 0 0 :::9090 :::* LISTEN 27417/main Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path


ip netns exec testns2 telnet 127.0.0.1 9090
Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.aabb^]
复制代码


hack 点就是 socket listen,accept 在不通的 ns 下处理 ,这样就绕过了服务网络上的问题, docker 当中也是这么处理的

用户头像

Geek_f24c45

关注

还未添加个人签名 2018.03.24 加入

还未添加个人简介

评论

发布
暂无评论
docker的DNS配置说明