Docker 无法解析专用网络上的 DNS

Docker cannot resolve DNS on private network

我的机器在一个私有网络上,有私有 DNS 服务器,以及一个用于 DNS 解析的私有区域。我可以从我的主机解析此区域上的主机,但我无法从我主机上的容器 运行 解析它们。

主机:

root@host:~# cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.1.1

root@host:~# ping privatedomain.io
PING privatedomain.io (192.168.0.101) 56(84) bytes of data.

容器:

root@container:~# cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 8.8.8.8
nameserver 8.8.4.4

root@container:~# ping privatedomain.io
ping: unknown host privatedomain.io

很明显,Google 的 public DNS 服务器无法解析我的私有 DNS 请求。我知道我可以用 docker --dns 192.168.0.1 强制它,或者在 /etc/default/docker 中设置 DOCKER_OPTS="--dns 192.168.0.1",但我的笔记本电脑经常切换网络。似乎应该有一个系统的方法来解决这个问题。

Docker 通过复制主机的 /etc/resolv.conf 并过滤掉任何本地名称服务器(例如 127.0.1.1)来填充 /etc/resolv.conf。如果在那之后没有留下任何名称服务器,Docker 将添加 Google 的 public DNS 服务器(8.8.8.8 和 8.8.4.4)。

根据 Docker documentation:

Note: If you need access to a host’s localhost resolver, you must modify your DNS service on the host to listen on a non-localhost address that is reachable from within the container.

主机上的 DNS 服务是 dnsmasq,所以如果你让 dnsmasq 监听你的 docker IP 并将其添加到 resolv.conf,docker 将配置容器使用它作为名称服务器。

1 . Create/edit /etc/dnsmasq.conf 并添加以下行:

interface=lo
interface=docker0

2 . 找到您的 docker IP(在本例中,172.17.0.1):

root@host:~# ifconfig | grep -A2 docker0
docker0   Link encap:Ethernet  HWaddr 02:42:bb:b4:4a:50  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0

3 . Create/edit /etc/resolvconf/resolv.conf.d/tail 并添加此行:

nameserver 172.17.0.1

4 . 重启网络,更新 resolv.conf,重启 docker:

sudo service network-manager restart
sudo resolvconf -u
sudo service docker restart

您的容器现在可以从主机使用的任何 DNS 服务器解析 DNS。

† 路径可能是 /etc/dnsmasq.conf/etc/dnsmasq.conf.d/docker.conf/etc/NetworkManager/dnsmasq.conf/etc/NetworkManager/dnsmasq.d/docker.conf,具体取决于您的系统和个人喜好。

对于Ubuntu 18.04 和其他使用systemd-resolved 的系统,可能需要安装dnsmasq 和resolvconf。 systemd 解析为 hard-coded to listen on 127.0.0.53, and Docker filters out any loopback address when reading resolv.conf.

1 . 安装 dnsmasq 和 resolvconf.

sudo apt update
sudo apt install dnsmasq resolvconf

2 . 找到您的 docker IP(在本例中为 172.17.0.1):

root@host:~# ifconfig | grep -A2 docker0
docker0   Link encap:Ethernet  HWaddr 02:42:bb:b4:4a:50  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0

3 . 编辑 /etc/dnsmasq.conf 并添加以下行:

interface=docker0
bind-interfaces
listen-address=172.17.0.1

4 . Create/edit /etc/resolvconf/resolv.conf.d/tail 并添加此行:

nameserver 172.17.0.1

5 . 重启网络,更新 resolv.conf,重启 docker:

sudo service network-manager restart
sudo resolvconf -u
sudo service dnsmasq restart
sudo service docker restart

您的容器现在可以从主机使用的任何 DNS 服务器解析 DNS。

对于 Ubuntu 18.04 LTS 来说已经足够了:

sudo service network-manager restart
sudo resolvconf -u
sudo service dnsmasq restart
sudo service docker restart

如你所知,Docker复制host/etc/resolv.conf 文件到容器,但删除任何本地名称服务器。

我对这个问题的解决方案是继续使用 systemd-resolvdNetworkManager 但添加 dnsmasq 并将其用于 "forward" Docker 容器 DNS 查询 systemd-resolvd.

分步指南:

  • 制作/etc/resolv.conf一个"real"文件 sudo rm /etc/resolv.conf sudo touch /etc/resolv.conf
  • 创建文件 /etc/NetworkManager/conf.d/systemd-resolved-for-docker.conf 通知 NetworkManager 通知 systemd-resolvd 但不要触摸 /etc/resolv.conf [main] # NetworkManager will push the DNS configuration to systemd-resolved dns=systemd-resolved # NetworkManager won’t ever write anything to /etc/resolv.conf rc-manager=unmanaged
  • 安装dnsmasq sudo apt-get -y install dnsmasq
  • /etc/dnsmasq.conf中配置dnsmasq以监听DNS查询来自 Docker 并使用 systemd-resolvd 名称服务器 # Use interface docker0 interface=docker0 # Explicitly specify the address to listen on listen-address=172.17.0.1 # Looks like docker0 interface is not available when dnsmasq service starts so it fails. This option makes dynamically created interfaces work in the same way as the default. bind-dynamic # Set systemd-resolved DNS server server=127.0.0.53
  • 编辑 /etc/resolv.conf 以使用 systemd-resolvd 名称服务器 (127.0.0.53) 和主机 IP (172.17.0.1) 在Docker网络中 # systemd-resolvd name server nameserver 127.0.0.53 # docker host ip nameserver 172.17.0.1
  • 重启服务 sudo service network-manager restart sudo service dnsmasq restart sudo service docker restart

有关详细信息,请参阅我的 post(西班牙语)https://rubensa.wordpress.com/2020/02/07/docker-no-usa-los-mismos-dns-que-el-host/

我的 docker 容器中的 DNS 解析器有问题。我尝试了很多不同的东西,最后,我发现我的 Hostgator 中的 CentOS VPS 默认没有安装 NetworkManager-tui (nmtui), 我刚刚安装并重新启动它

sudo yum install NetworkManager-tui

并使用默认 DNS 重新配置我的 resolv.conf 8.8.8.8

nano /etc/resolv.conf

如果您使用的是 VPN,则 VPN 协议可能会附加到超出您专用网络上配置的 MTU 的出站数据包。

典型的 MTU 是 1500。

尝试将此内容添加到 /etc/docker/daemon。json

{
  "mtu": 1300,
  "dns": ["<whatever DNS server you need in your private network>"]
}

然后systemctl restart docker.

我的案例有许多来自 docker 集线器(nodered、syncthing 和其他)的图像:

  • 容器在非根用户
  • 下运行
  • /etc/resolv.conf 容器内的权限为 600 且归 root
  • 所有

所以我的解决方法很简单

root@container:~# chmod 644 /etc/resolv.conf

赚了! :))

我的 systemctl 状态 docker 中有相同的错误消息。 我 运行 一个 Nextcloud 和一个 nextcloud nginx 代理容器,并使用 docker compose 来安装它。它在没有 big hickups 的情况下工作了好几个月,但在星期五它无法访问。服务器已关闭。 我重新启动了它,我的 icecast2 实例工作正常,并在这个星期天用于我们教堂的服务。但是 docker 容器不见了。 docker ps -a 没有显示任何内容,我无法像往常一样通过 docker exec 访问 nextcloud。我收到错误消息:

No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: [nameserver 8.8.8.8 nameserver 8.8.4.4]"
Feb 06 19:04:58 ncxxxxxxxxx dockerd[21551]: time="2022-02-06T19:04:58.894366765Z" level=info msg="IPv6 enabled; Adding default IPv6 external servers: [nameserver 2001:4860:4860::8888 nameserver 2001:4860:4860::8844]

我的 resolv.conf 看起来像这样:

GNU nano 4.8
/etc/resolv.conf
nameserver 127.0.0.53 
options edns0 trust-ad
search fritz.box

基于@rubensa 的回答,但更简单、更完整的恕我直言:

  • 安装dnsmasq sudo apt-get -y install dnsmasq
  • /etc/dnsmasq.d/docker-dns-fix.conf配置dnsmasq监听DNS 来自 Docker 并使用 systemd-resolvd 名称服务器的查询 # Use interface docker0 interface=docker0 # Explicitly specify the address to listen on listen-address=172.17.0.1 # Looks like docker0 interface is not available when dnsmasq service starts so it fails. This option makes dynamically created interfaces work in the same way as the default. bind-dynamic # Set systemd-resolved DNS server server=127.0.0.53
  • 通过editing/crea告诉Docker使用dnsmasq { "dns": ["172.17.0.1"] }
  • 重启服务 sudo service dnsmasq restart sudo service docker restart