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

时间:2018-07-18 14:24:53

标签: docker docker-networking

我已经在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

更新_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 :经过一番调查,结果发现:

  • 独立容器继承EC2实例的dns-nameserver;
  • 通过docker stack deploy开始的容器

即这是从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 run busybox nslookup google.com 服务器:8.8.8.8 地址:8.8.8.8:53

非权威性答案: 名称:google.com 地址:216.58.211.174

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

但查找仍然失败:

有人建议为什么这会令人沮丧吗?

3 个答案:

答案 0 :(得分:1)

我刚遇到类似的问题。我意识到这已经11个月了,但是在这个主题上查找信息有些困难,因此我将在此处发布信息。

我的问题原来是docker swarm覆盖网络的默认子网与我的vpcs子网重叠,因此在我的情况下,默认的Amazon ec2 dns服务器(10.0.0.2)混淆了docker守护程序的IP地址路由到认为这是一大堆本地服务(我认为)。无论如何,我通过通过堆栈文件network:部分更改默认的覆盖子网解决了我的问题,而我的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的udp dns端口上的dns服务器联系)。但是,nslookup在主机操作系统上运行良好,/etc/resolve.conf看起来很合适。如果您使用docker exec在其中一个正在运行的服务中获取交互式/bin/sh,则问题很明显。 nslookup对于任何外部域均失败,并且docker daemon调试日志吐出了更多有关10.0.0.2的“连接被拒绝”类型的消息。在研究了dns解析的docker支持问题一两个小时之后,我发现一条评论,指出docker swarm虚拟网络是根据一些默认值分配地址的,有时这些默认值与您设置本地子网的方式重叠。我认为,如果它们与我的vpc上的dns服务器重叠,则可能是在群内路由dns数据包,而不是解析到vpc子网路由。

答案 1 :(得分:1)

在...的输出中可以找到不需任何docker-compose.yml customisation的更强大解决方案的线索。

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

默认情况下,Docker Swarm将默认地址池10.0.0.0/8用于全局范围(覆盖)网络。每个未指定子网的网络都将从该池中依次分配一个子网。在某些情况下,可能希望对网络使用其他默认IP地址池。

例如, 如果默认的10.0.0.0/8范围与网络中已分配的地址空间冲突,则最好确保网络使用其他范围 ,而无需Swarm用户使用--subnet命令指定每个子网。

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

我们发现可以(仅)在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
这次

...- altering the docker-compose.yml to configure a specific, different subnet for just the default network-事实证明,现在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",
            },
            …
        },
…

答案 2 :(得分:0)

[edit @ 2020-02-10]虽然我认为以下内容可能仍然很有趣,但我不再将其视为解决问题的最佳方法。这并不意味着它不起作用,而是需要使docker-compose.yml 适应将要启动的环境,而人们更愿意正确地prepare the environment a docker-compose.yml is to be launched in代替。


免责声明:此“答案”远不是经过授权的解决方案,而是记录了出现为我工作的各种情况以及它们的来历关于。

给出:

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

可以发现:

  • 对于myapp_default网络,Docker将为每个容器分配一个10.0.x.0/24私有范围之外的IP地址;
    可以从docker network inspect myapp_default | less -p '10\.0(\.[0-9]+){2}';
  • 的输出中得出
  • EC2实例本身可以联系其DNS的10.0.0.2(由AWS提供);
  • 但是,从docker容器中进行
  • DNS查找失败-除非 dockerd守护进程已被配置为可以连接到公共DNS服务器(例如dockerd --dns 8.8.8.8 ...)-< em>和实例的安全组允许这种流量;
    OP也已经发现了这一点。
  • 明确地dockerd -dns 10.0.0.2 ...似乎无济于事;

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

此外,鉴于根本原因是什么,人们不禁要问为什么“ docker”无法自动检测到这种情况,然后为myapp_default网络选择一个不重叠的范围代替;

看来我们只需要自己明确补救即可;那我们该怎么办呢?我们如何才能使“码头工人”为其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范围之外的IP地址。相反-我们发现他们的DNS查找现在可以工作了!

我做的不是(到目前为止)还知道,以上内容对于解决该问题既是必要的又是充分的解决方案,并且没有打开其他蠕虫病毒的罐头……