docker: EC2 实例中堆栈中的容器不继承 dns 名称服务器

docker: containers in stacks within EC2 instance do not inherit dns nameserver

我已经在 AWS 上设置了一个 EC2 实例。

已正确设置我的安全组,以便实例能够访问 Internet,例如

ubuntu@ip-10-17-0-78:/data$ ping www.google.com
PING www.google.com (216.58.211.164) 56(84) bytes of data.
64 bytes from dub08s01-in-f4.1e100.net (216.58.211.164): icmp_seq=1 ttl=46 time=1.02 ms
64 bytes from dub08s01-in-f4.1e100.net (216.58.211.164): icmp_seq=2 ttl=46 time=1.00 ms

但是,当我执行到容器中时,这是不可能的:

root@d1ca5ce50d3b:/app# ping www.google.com
ping: www.google.com: Temporary failure in name resolution

update_1:连接问题与在特定堆栈中使用 docker stack deploy 启动的容器有关;

当我刚启动一个独立容器时,可以连接到 Internet:

ubuntu@ip-10-17-0-78:/data$ docker run -it alpine:latest /bin/ash
/ # ping www.google.gr
PING www.google.gr (209.85.203.94): 56 data bytes
64 bytes from 209.85.203.94: seq=0 ttl=38 time=1.148 ms
64 bytes from 209.85.203.94: seq=1 ttl=38 time=1.071 ms

update_2:经过一番调查,发现:

即这是来自 docker swarm - 启动的容器:

ubuntu@ip-10-17-0-78:~$ docker exec -it d1ca5ce50d3b bash
root@d1ca5ce50d3b:/app# cat /etc/resolv.conf 
search eu-west-1.compute.internal
nameserver 127.0.0.11
options ndots:0

update_3:当我用 docker-compose 而不是 docker stack deploy 启动堆栈时,同样的问题;似乎不是 swarm - 特定问题;

update_4: 我已经明确添加了 gfile /etc/docker/daemon.json 具有以下内容:

{
    "dns": ["10.0.0.2", "8.8.8.8"]
}

ubuntu@ip-10-17-0-78:/data$ docker 运行 busybox nslookup google.com 服务器:8.8.8.8 地址:8.8.8.8:53

非权威回答: 姓名:google.com 地址:216.58.211.174

*** 找不到google.com:没有答案

但查找仍然失败:

对于为什么会发生这种情况有什么建议吗?

我刚刚 运行 遇到了类似的问题。我意识到这已经 11 个月大了,但是很难找到关于这个主题的信息,所以我会在这里 post 信息。

我的问题原来是 docker swarm overlay 网络的默认子网与我的 vpcs 子网重叠,所以我的默认 amazon ec2 dns 服务器 (10.0.0.2) 混淆了docker 守护进程的 ip 地址路由认为它是一个 swarm overlay 本地服务(我认为)。无论如何,我通过堆栈文件网络更改默认覆盖子网解决了我的问题:部分和我的 docker 守护进程再次开始解析 10.0.0.2 vpc dns 服务器。

如果将节点 docker 守护程序放在调试模块中(在 linux /etc/docker/daemon.json 上,将 "debug": true 添加到 json),您可以监控通过跟踪特定系统上守护程序的日志来调试输出。如果守护进程是 运行 通过 systemd,journalctl -u docker 会给你日志。 -f 将关注日志。

在那里我找到了有关连接问题的信息(docker 守护程序无法与 10.0.0.2:54 上的 dns 服务器取得联系——udp dns 端口)。但是,nslookup 在主机 OS 上运行良好,/etc/resolve.conf 看起来很合适。如果您使用 docker exec 在 运行 服务之一中获得交互式 /bin/sh,则问题很明显。 nslookup 对任何外部域都失败,docker 守护程序调试日志吐出更多关于 10.0.0.2 的 "connection refused" 类型消息。在查看 docker DNS 解析支持问题一两个小时后,我发现一条评论指出 docker 集群虚拟网络是根据一些默认值分配地址的,有时这些默认值与如何重叠您已经设置了本地子网。我推断如果它们与我的 vpc 上的 dns 服务器重叠,它可能会尝试路由 dns 数据包 intra-swarm,而不是解析到 vpc 子网路由。

[edit@2020-02-10] 虽然我认为下面的内容可能仍然很有趣,但我不再认为它是解决问题的最佳方案。这并不意味着它不起作用,但它需要 使 docker-compose.yml 适应将要发布的环境,而人们更愿意正确地 代替。


免责声明:这个"answer"与其说是一个授权的解决方案,还不如说是对使它出现[=87=的事情的记录] 为我工作,以及它们是如何产生的。

鉴于:

  • AWS EC2 docker 主机实例的私有 IP 地址在 10.0.0.0/16 范围内;
  • docker swarm init 化;
  • 有一个应用程序 - 比如说 myapp - 部署为 docker stack deploy -c docker-compose.yml myapp;

可以发现:

  • Docker 将 - 对于 myapp_default 网络 - 为每个容器分配一个超出 10.0.x.0/24 私有范围的 IP 地址;
    这可以从 docker network inspect myapp_default | less -p '10\.0(\.[0-9]+){2}';
  • 的输出中推断出来
  • EC2 实例本身可以访问 10.0.0.2(AWS 提供的)以获取其 DNS;
  • 然而,
  • 从 docker 容器中进行 DNS 查找失败 - 除非 dockerd 守护程序已额外配置为连接到 public DNS 服务器(如 dockerd --dns 8.8.8.8 ...)- 实例的安全组允许这种流量;
    OP 也已经发现了这一点。
  • 明确地做 dockerd -dns 10.0.0.2 ... 似乎没有一点帮助;

确实有人想知道为什么 dockerd 无法在其 myapp_default 网络的私有 10.0.x.0/24 范围与其 EC2 主机实例所在的范围之间调解 DNS 查找;毕竟,它们仍然是两个完全断开连接的网络,只是恰好选择了重叠的 ip 范围,但显然 - 正如@Josh 已经指出的那样 - 就是这种情况;

此外,考虑到造成这种情况的根本原因是什么限制,人们不禁想知道为什么 "docker" 没有自动检测到这种情况,然后简单地为 [= 选择一个非重叠范​​围17=] 网络代替;

看来我们只需要自己明确地解决这个问题;那么我们该怎么做呢?我们怎样才能让 "docker" 为其 myapp_default 网络选择不同的范围?

@Josh 暗示了一个答案以及从中收集的点点滴滴的信息:

...我编造了这个顶级部分以添加到 docker-compose.yml:

networks:
    default:
        ipam:
            config:
                -
                    subnet: '192.168.0.0/24'
            driver: 'default'

重新部署 myapp 后,docker network inspect myapp_default 的输出提供证据表明容器不再分发 10.0.x.0/24 范围之外的 IP 地址,而是来自 192.168.0.0/24 而不是 - 我们发现他们的 DNS 查找现在可以工作了!

我所做的(还)知道上述是否是解决问题的必要且充分的方法,而不是打开其他一些蠕虫病毒......

更强大的解决方案的线索 - 不需要任何 - 可以在...

的输出中找到
docker info
Server:
    …
    Swarm: active
        …
        Default Address Pool: 10.0.0.0/8  
        SubnetSize: 24
        …

然后,此文档位于 https://docs.docker.com/engine/swarm/swarm-mode/#configuring-default-address-pools:

By default Docker Swarm uses a default address pool 10.0.0.0/8 for global scope (overlay) networks. Every network that does not have a subnet specified will have a subnet sequentially allocated from this pool. In some circumstances it may be desirable to use a different default IP address pool for networks.

For example, if the default 10.0.0.0/8 range conflicts with already allocated address space in your network, then it is desirable to ensure that networks use a different range without requiring Swarm users to specify each subnet with the --subnet command.

... 确信这也是 避免此类冲突的地方。

我们发现默认地址池可以(只能)定义在docker swarm init时间:

$ docker swarm init --default-addr-pool <IP range in CIDR> ...

(可以重复 --default-addr-pool 以使用更多范围扩展池)。

确实,例如

docker swarm init --default-addr-pool 192.168.0.0/16

...这次 - 没有 - 结果是 docker 现在从这个默认地址池中挑选子网,不再重叠对于网络中的任何地址,docker 主机实例本身都在。

docker info
Server:
    Swarm: active
        …
        Default Address Pool: 192.168.0.0/16
        SubnetSize: 24
    …
docker network inspect myapp_default
[
    {
        "Name": "myapp_default",
        …
        "Containers": {
            "…": {
                …
                "IPv4Address": "192.168.1.12/24",
            },
            …
        },
…