企业网络下镜像构建时网络调用失败

94

我在公司网络上构建Docker镜像时遇到了问题。我刚开始使用Docker,因此我有一个用于hello-world类型应用的Dockerfile:

# DOCKER-VERSION 0.3.4
FROM    centos:6.4
# Enable EPEL for Node.js
RUN     rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
# Install Node.js and npm
RUN     yum install -y npm
# Bundle app source
ADD . /src
# Install app dependencies
RUN cd /src; npm install
EXPOSE  8080
CMD ["node", "/src/index.js"]

当我在家里的无线网络上构建时,这个工作很好。它会下载必要的依赖项并正确地构建镜像。

然而,在我上班时使用公司网络时,这个相同的docker构建失败了,当尝试从download.fedoraproject.org下载RPM时出现以下错误消息:

Step 2 : RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm ---> Running in e0c26afe9ed5 curl: (5) Couldn't resolve proxy 'some.proxy.address' error: skipping http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm - transfer failed

在我的公司网络上,我可以轻松访问该URL。但是一旦Docker尝试构建容器,它突然就无法解析了。对于各种外部资源(apt-get等),这种行为都是相同的:它们在公司网络上的笔记本电脑上都可以正常解析,但Docker无法解析。

我不知道网络知识,无法弄清楚这里发生了什么。有人知道为什么在构建Docker容器时会出现这种奇怪的行为吗?


请查看 http://stackoverflow.com/questions/19210563/using-docker-behind-a-proxy-on-an-ec2-instance ,它可能也可以解决您的问题。 - Thomasleveil
我遇到了相同的问题。我忘记运行 apt-get update - Matthias Beaupère
这些可能是“Docker无法从Cisco AnyConnect获取DNS信息”的症状。 - Jason
在家里使用ADSL连接时遇到了类似的问题。但是在我的办公室,它可以正常工作。 - bcag2
9个回答

96

我已经找出问题所在。在Ubuntu上,Docker将容器的DNS服务器设置为Google服务器的8.8.8.x。据我所知,这是Ubuntu的一种解决方法,因为Ubuntu将/etc/resolv.conf设置为127.0.0.1。

由于我们的防火墙无法访问这些Google服务器,因此我们无法解析任何网址。

解决方法是告诉Docker使用哪些DNS服务器。该解决方法取决于您如何安装Docker:

Ubuntu软件包

如果您安装了Ubuntu软件包,请编辑/etc/default/docker并添加以下行:

DOCKER_OPTS="--dns <your_dns_server_1> --dns <your_dns_server_2>"
您可以在此配置中添加任意数量的DNS服务器。编辑完文件后,您需要重启Docker服务:
sudo service docker restart

二进制文件

如果您是通过二进制文件方式安装 Docker(即没有使用软件包),则可以在启动 Docker 守护进程时设置 DNS 服务器:

sudo docker -d -D --dns <your_dns_server_1> --dns <your_dns_server_2> &

4
使用"Docker build"命令和Dockerfile呢?在这种情况下似乎不起作用: docker --dns=209.18.47.61 build . 2>&1 | tee ./output.txt - Quasaur
2
是的,这应该可以使用docker build。docker build本身没有--dns标志,但如果您像这样在守护程序上设置它,则在使用docker build时它将应用。 - dsw88
1
我已经完成了这个步骤,但又开始出现错误。重新启动服务再次解决了问题。 - Andrew Grothe
我在使用Docker 1.7时遇到了问题,尽管我已经尝试使用--dns选项运行它或将配置放在/etc/default/docker中。 - Patryk
在我的情况下,启动docker守护进程时需要设置--dns选项,但使用网络中的名称服务器无法正常工作。相反,强制使用谷歌的名称服务器即可解决问题,即8.8.8.8和8.8.4.4。这是在Centos7上运行的docker 1.8.2,尝试构建基于Centos6的容器。 - phansen
显示剩余3条评论

71

我建议更改Docker守护程序的DNS设置。您可以通过在/etc/docker/daemon.json中创建守护程序配置文件来设置docker守护程序的默认选项。根据您的主机机器设置DNS服务器,例如我的DNS服务器是10.0.0.2:

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

然后您只需要重新启动docker服务:

sudo service docker restart

这里提供了逐步解释:修复Docker的网络DNS配置


1
在家中解决了我与法国网络服务供应商(“free.fr”)的问题。 - bcag2

21
以下步骤适用于我(适用于docker build和docker run命令)。 我的Linux版本是Ubuntu 14.04。
- 使用以下命令标识DNS。
nm-tool | grep DNS
此结果在我的情况下为DNS:192.168.1.1
- 在/etc/default/docker.io中创建条目。 我当前的条目如下所示:
DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --dns 192.168.1.1"
- 重新启动docker服务。
sudo service docker.io restart

2
CentOS的等效文件是/etc/sysconfig/docker,我能够在其中添加DOCKER_OPTS="--dns 8.8.8.8"一行并解决我的问题。 - MarkHu
OpenSuSE也有/etc/sysconfig/docker文件。 - David Lakatos

11

对于任何使用SystemD的Linux发行版(如Ubuntu 16、RHEL 7等),您可以使用以下命令显示路径:

对于任何使用SystemD的Linux发行版(如Ubuntu 16、RHEL 7等),您可以使用以下命令显示路径:

$ systemctl status docker
 docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2016-06-29 08:10:33 PDT; 2min 34s ago
     Docs: https://docs.docker.com
 Main PID: 1169 (dockerd)
    Tasks: 19
   Memory: 85.0M
      CPU: 1.779s
   CGroup: /system.slice/docker.service
           ├─1169 /usr/bin/dockerd --dns 172.18.20.11 --dns 172.20.100.15 --dns 8.8.8.8 --dns 8.8.4.4 -H fd://
           └─1232 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --met

路径是/lib/systemd/system/docker.service。在启动守护进程的行中添加DOCKER_OPTS值,可以使用任何--dns选项。

cat /lib/systemd/system/docker.service | grep dns 
ExecStart=/usr/bin/dockerd --dns 172.18.20.11 --dns 172.20.100.15 --dns 8.8.8.8 --dns 8.8.4.4  -H fd://

1
谢谢!在编辑docker.service之后,我必须使用sudo service docker stop停止docker服务,然后运行systemctl daemon-reload,最后再使用sudo service docker start启动。 - Kaveh Ghahremani
1
最好在/etc/systemd/system/docker.service.d中添加一个单元文件,其中包含修改后的配置(systemd会很有帮助地合并/覆盖系统配置),而不是更改系统版本。后者将在升级时丢失。 - Raman

9

将您的DNS指定给Docker守护进程。

首先获取您的DNS地址

$ nmcli dev show | grep 'IP4.DNS'
IP4.DNS[1]:                             10.0.0.2

通过启动一个强制使用新DNS的docker容器来测试问题是否真的与DNS有关

$ docker run --dns 10.0.0.2 <image_name> <command_name>

如果这解决了问题,您可以按照以下方式为所有的Docker守护进程应用此修复方法:
编辑或创建文件/etc/docker/daemon.json
在该文件中添加以下行:
{
"dns": ["10.0.0.2", "8.8.8.8"]
}

重启docker
$ sudo service docker restart

这里有一份非常好的指南,可以帮助你完成所有这些过程。请前往以下链接查看:https://development.robinwinslow.uk/2016/06/23/fix-docker-networking-dns/

这是一个边缘仅链接回答。您应该扩展您的答案,包括尽可能多的信息,并仅将链接用于参考。 - Blue
如果您通过Snap安装了Docker,则daemon.json文件将位于/var/snap/docker/<id>/config/daemon.json - sjt003

9

Docker(至少>=1.13,可能更早版本)在Mac和Windows上允许您在“首选项 ->守护程序 ->高级”中配置DNS:

以下配置设置了两个公司DNS服务器(在此处使用您自己的值),并回退到Google公共DNS服务器。

Docker Daemon Adv Config


你救了我的一天 - 它在我的Windows Docker桌面实例上运行得很好。 - Leonid
谢谢Jason--如果这个方法不行的话,请看我的后续回答,了解在UI上设置DNS的新方法。 - Reg Edit

3

无需重新启动Docker服务的解决方案

可以在构建时覆盖resolv.conf,从而修改单个Docker镜像的DNS设置,而不影响其他docker build调用(并且无需重新启动Docker服务)。

FROM ubuntu:18.04

RUN echo "nameserver 123.123.123.123" > /etc/resolv.conf && apt update

将IP 123.123.123.123 替换为您公司网络中使用的IP(使用 nmcli dev show | grep 'IP4.DNS' 获取当前使用的DNS服务器)。

缺点:

  • 这不会影响 Dockerfile 中的任何其他行。因此,如果它依赖于DNS解析,则必须在每行前面加上修复。

1
无法使用,因为Docker已经将/etc/resolv.conf设为只读。 - Anatoly Sazanov
谢谢您的评论,您知道这个更改是在哪个版本中发生的吗? - Murmel

1
在我的Ubuntu 16.04机器上,有时候使用Google的DNS无法构建Docker镜像。
cat /etc/docker/daemon.json
{"dns": [""8.8.8.8"] }

我必须使用以下命令手动查找我的服务提供商DNS。

nmcli device show <interfacename> | grep IP4.DNS

125.22.47.102

将其翻译成中文如下:

并将其添加到我的daemon.json中,如下所示

cat /etc/docker/daemon.json 

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

 restart docker

sudo service docker restart

(PS nm-tool 在 Ubuntu 15.04 中已被弃用)


0

2021年9月更新信息

受Jason的回答启发,将DNS服务器设置在JSON中对我来说在当前版本中无效,但现在有另一个设置它的地方:

enter image description here

当您打开切换键时,8.8.8.8已经存在,所以我只是把它留下来,对于我在开发环境中来说足够好用。我没有研究过它,但如果需要,可能可以通过逗号/分号/空格等方式添加列表。


2
我的Windows上的Docker桌面版(v4.12.0)没有那个DNS选项,只有子网。 - AndrWeisR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接