我认为这是 SO Network 中广泛讨论的问题之一。大多数解决方案都是过时的或陈旧的建议,并带有最新的 Ubuntu (21.04)/Systemd 更改。
问题:Docker 容器不支持主机网络的 VPN 更改。
尝试过的解决方案:
- 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
- 安装 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-interfaces
为bind-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 解析器,以避免网络管理器和任何其他组件将来出现升级/集成问题。
请提出解决方案
- 避免每次重启后重新启动 dnsmasq 服务
- 有没有优雅的解决方案,而不是乱七八糟地使用 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
您似乎已经差不多搞定了。您的整体解决方案需要两样东西:
- 指向主机的每个容器的 DNS
- 在您的主机上运行的 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
桥接网络。
回答您的具体标准:
应通过取消对 systemd 服务的屏蔽,使 dnsmasq 服务在启动时自动启动,这将解决您的重启问题。使用
bind-dynamic
,它应在运行时自动处理网络环境的变化,而无需手动重启。不幸的是,实际上没有解决方案可以让 docker 的默认 DNS 解析器按应有的方式运行。默认情况下,Docker 将 DNS 配置从主机复制到容器,然后通过主机路由实际网络。因此,DNS 查找独立于主机运行,但 IP 路径使用主机运行。这肯定会在使用拆分/隧道网络的大多数用例(企业环境、VPN 等)中导致问题,但确实允许在其他用例中进行 DNS 分离隔离。如果您想解决这个问题,您几乎必须在至少在 docker 桥接网络上公开的主机上运行一些递归解析器,而大多数 Ubuntu 系统默认情况下都没有运行/提供此功能。