在 Docker 容器中使用主机 DNS 解析

在 Docker 容器中使用主机 DNS 解析

我认为这是 SO Network 中广泛讨论的问题之一。大多数解决方案都是过时的或陈旧的建议,并带有最新的 Ubuntu (21.04)/Systemd 更改。

问题:Docker 容器不支持主机网络的 VPN 更改。

尝试过的解决方案:

  1. Docker 守护进程支持自定义dns解析。
    {
        "dns": ["172.17.0.1", "8.8.8.8", "8.8.4.4"]
    }

此解决方案不适用于 Systemd DNS Resolution。

resolvectl status

Link 7 (docker0)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 92 (tun0)
    Current Scopes: DNS
         Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 1.1.1.1
       DNS Servers: 1.1.1.1
        DNS Domain: consul vpn.net
  1. 安装 dnsmasq 并将其绑定docker0 interface/etc/dnsmasq.conf
interface=docker0
listen-address=172.17.0.1

如果我使用bind-dynamic,它会失败,并且bind-dynamic and bind-interfaces无法一起使用。我不得不从bind-interfaces设置的位置开始挖掘

最终在这里找到:

cat /etc/dnsmasq.d/libvirt-daemon
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: /etc/dnsmasq.d/libvirt-daemon
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ bind-dynamic
   2   │ except-interface=virbr0

将第 1 行更改bind-interfacesbind-dynamic,并且没有明确添加dnsmasq.conf

重启服务后,这似乎有效docker and dnsmasq。但是重启系统后,这又不起作用了。只有当我按以下顺序启动服务docker first (so that 172.17.0.1 comes available) and dnsmasq following that 或必须明确重启 dnsmasq 服务才能正确绑定到 172.17.0.1 时,它才有效。

我没有禁用 Systemd DNS 解析器,以避免网络管理器和任何其他组件将来出现升级/集成问题。

请提出解决方案

  1. 避免每次重启后重新启动 dnsmasq 服务
  2. 有没有优雅的解决方案,而不是乱七八糟地使用 SystemD/dnsmasq/docker。只需在所有服务/接口上进行一次 DNS 解析?

答案1

如果我理解正确的话,您可以为每个运行的容器提供主机 DNS 信息。我不明白为什么这不适用于解决或者域名系统DNS 解析(尽管我使用的是 Unbound)。

您应该将以下内容添加到您运行的每个容器中,以提供必要的 DNS 信息。我假设您的 DNS 解析器在地址 172.17.0.1 上运行(如果我错了,请纠正我)。

使用 Docker CLI:(只是一个随机示例配置)

docker run -d \
  --name <container-name> \
  --dns 172.17.0.1 \
  --dns 172.17.0.2 \ # your secondary DNS server if you have one
  --dns 8.8.8.8 \
  --dns 8.8.4.4 \
  -p <port>:<port> \
  -v /path/to/data/<container>:/path/to/data \
  --restart always \
  <repo>/<container>:<branch>

使用 Docker Compose:(相同的随机配置)

version: '3'

  services:

    <service-name>:
      image: <repo>/<container>:<branch>
      container_name: <container-name>
      dns:
        - 172.17.0.1
        - 172.17.0.2 # your secondary DNS server if you have one
        - 8.8.8.8
        - 8.8.4.4
      ports:
        - <port>:<port>
      volumes:
        - /path/to/data/<container>:/path/to/data
      restart: always

我已经对几个容器完成了这个操作,它们使用我的内部 DNS 解析 DNS(我的地址是 10.10.2.2 和 10.10.2.4 并且使用 Unbound,但我不明白为什么它应该有所不同)。

在我看来,这种方法至少有两个优点:

  • 您不需要自定义或配置您的 DNS 解析器,除了您通常会做的事情 - 它“只”需要在主机上监听(可以是本地机器或任何其他 DNS 主机 - 在本例中为 172.17.0.1,如果有辅助主机,则为 172.17.0.2)。
  • 您也不需要使用自己的 DNS 解决方案定制您的容器,因为 DNS 信息是在容器初始化时作为参数提供的(如果需要,您甚至可以使用不同的 DNS 解决方案来管理不同的容器)。

我能想到的第一个“缺点”是:

  • 您需要为启动的每个容器提供 DNS 信息 - 但如果您保存容器配置,则每个容器只需执行一次,并且大多数情况下 DNS 配置应该相似。

我相信这个答案符合你的标准:

  • 避免每次重启后重新启动 dnsmasq 服务
  • 有没有优雅的解决方案,而不是乱七八糟地使用 SystemD/dnsmasq/docker。只需在所有服务/接口上进行一次 DNS 解析?

答案2

我将尝试在 docker 中运行 dnsmasq 的解决方案,如下所示:

https://blog.csainty.com/2016/09/running-dnsmasq-in-docker.html

其中 dnsmasq 将读取添加到 /etc/dnsmasq 的所有 .conf 文件(需要重新启动容器才能加载更改)。

答案3

您似乎已经差不多搞定了。您的整体解决方案需要两样东西:

  1. 指向主机的每个容器的 DNS
  2. 在您的主机上运行的 DNS 递归解析器

您已经设置了两者,但我怀疑您的解析器设置不正确。docker 守护进程配置隐式地执行了--dns 172.17.0.1 --dns 8.8.8.8 --dns 8.8.4.4与使用默认 docker 网络传递给每个容器相同的操作,因此每个容器都应该首先查询递归解析器。您还在主机系统上运行了 dnsmasq 来提供递归解析器。

您的问题似乎在于 dnsmasq 的运行方式;它似乎不接受来自 docker 网络的 DNS 请求。我怀疑这与显式docker接口绑定与 libvirt-daemon 的动态绑定相冲突有关。我猜您可能只需删除特定于 docker 的配置并保留 libvirt-daemon 配置,它就会在 dnsmasq 重新启动后开始工作。应该bind-dynamic绑定到除明确排除的网络接口之外的所有网络接口:(except-interface=virbr0),理论上将包括docker0桥接网络。

回答您的具体标准:

  1. 应通过取消对 systemd 服务的屏蔽,使 dnsmasq 服务在启动时自动启动,这将解决您的重启问题。使用bind-dynamic,它应在运行时自动处理网络环境的变化,而无需手动重启。

  2. 不幸的是,实际上没有解决方案可以让 docker 的默认 DNS 解析器按应有的方式运行。默认情况下,Docker 将 DNS 配置从主机复制到容器,然后通过主机路由实际网络。因此,DNS 查找独立于主机运行,但 IP 路径使用主机运行。这肯定会在使用拆分/隧道网络的大多数用例(企业环境、VPN 等)中导致问题,但确实允许在其他用例中进行 DNS 分离隔离。如果您想解决这个问题,您几乎必须在至少在 docker 桥接网络上公开的主机上运行一些递归解析器,而大多数 Ubuntu 系统默认情况下都没有运行/提供此功能。

相关内容