Docker apt-get更新失败

55

有人可以帮我在我的docker容器中让apt-get工作吗?每当我尝试在我的docker容器中运行任何apt-get命令时,该命令都会失败。我正在运行Docker版本1.1.1,构建bd609d2,ubuntu 12.04。

当我执行

$ sudo docker run -i -t ubuntu:14.04 /bin/bash
# apt-get update

我收到错误信息,提示无法解析'archive.ubuntu.com'。我尝试在/etc/default/docker中取消以下行的注释:
DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4"
但我仍然无法ping通google.com,出现“ping: unknown host”错误。我确认容器正在使用dns服务器8.8.8.8和8.8.4.4,并且我能够ping通这两个服务器,所以我很确定防火墙没有丢弃我的数据包。
如果您能提供任何帮助,将不胜感激!
谢谢!

如果防火墙禁止使用外部递归名称服务器,则使用可用于您的局域网上的递归名称服务器或缓存转发器。我想,如果您可以重新配置防火墙,那么您现在已经这样做了,这意味着您无法更改它。通过dig @8.8.8.8 google.com确认是否为防火墙,看看是否解析。如果是,则不是防火墙。 - Deleted User
通过切换离开Google的DNS服务器到Cloudflare的@1.1.1.1 & 1.1.4.4,解决了问题。 - NerdOfCode
2
这个回答解决了你的问题吗?企业网络中镜像构建期间网络调用失败 - Ian Kemp
10个回答

42
感谢您的所有帮助!我发现这是一个DNS问题,因为防火墙的原因。在进一步搜索后,我找到了这个问题,而我之前在搜索“docker apt-get fail”时没有找到它。 Docker - 在公司网络中构建镜像期间网络调用失败 他的问题与我的类似,解决方案帮助我解决了问题。 我将他的解决方案复制过来,以供将来查看此问题的任何人使用。
这些 Google 服务器无法从我们的防火墙后面访问,这就是为什么我们无法解析任何 URL 的原因。
解决方法是告诉 Docker 使用哪些 DNS 服务器。具体取决于您如何安装 Docker: Ubuntu 包
如果您已经安装了 Ubuntu 包,请编辑 /etc/default/docker 并添加以下行:
DOCKER_OPTS="--dns --dns "
您可以在此配置中添加任意数量的 DNS 服务器。编辑完文件后,您需要重新启动 Docker 服务:
sudo service docker restart
二进制文件
如果您通过二进制文件方式安装了 Docker(即没有使用包),则可以在启动 Docker 守护程序时设置 DNS 服务器:
sudo docker -d -D --dns --dns &

3
不知道自己的 DNS 是什么的人可以参考这篇文章:https://robinwinslow.uk/2016/06/23/fix-docker-networking-dns/,它可以帮助您解决 Docker 网络 DNS 的问题。 - Avinash Raj
2
请注意,此答案(etc/default/docker)适用于使用Upstart的旧版本Ubuntu。自Ubuntu 16.04以来,它使用systemd,因此您需要按照https://dev59.com/6WAf5IYBdhLWcg3wSQ4z#51089399进行操作。 - wisbucky

29
如果您看到类似于Could not resolve ...的错误,很可能是DNS配置出了问题。
首先要检查的是在docker容器中运行cat /etc/resolv.conf命令。如果它有一个无效的DNS服务器,比如nameserver 127.0.x.x,那么容器将无法将域名解析为IP地址,因此ping google.com将失败。
第二个要检查的是在主机上运行cat /etc/resolv.conf命令。Docker基本上会将主机的/etc/resolv.conf每次启动容器时复制到容器中。因此,如果主机的/etc/resolv.conf不正确,那么Docker容器也会出现问题。
如果您发现主机的/etc/resolv.conf不正确,则有两个选择:
1. 在daemon.json中硬编码DNS服务器。这很容易,但如果您希望DNS服务器更改,则不理想。 2. 修复主机的/etc/resolv.conf。这有点棘手,但它是动态生成的,而且您没有硬编码DNS服务器。
1. 在docker daemon.json中硬编码DNS服务器
- 编辑/etc/docker/daemon.json
{
    "dns": ["10.1.2.3", "8.8.8.8"]
}
  • 重新启动docker守护程序以使更改生效:
    sudo systemctl restart docker

  • 现在当您运行/启动容器时,docker将使用来自daemon.json的值填充/etc/resolv.conf


  • 2. 修复主机的/etc/resolv.conf

    A. Ubuntu 16.04及早期版本

    • 对于Ubuntu 16.04及早期版本,/etc/resolv.conf是由NetworkManager动态生成的。

    • /etc/NetworkManager/NetworkManager.conf中注释掉dns=dnsmasq行(使用#)

    • 重启NetworkManager以重新生成/etc/resolv.conf
      sudo systemctl restart network-manager

    • 在主机上验证:cat /etc/resolv.conf

    B. Ubuntu 18.04及更高版本

    • Ubuntu 18.04 改为使用systemd-resolved生成/etc/resolv.conf。现在默认使用本地DNS缓存127.0.0.53。这在容器内部不起作用,因此Docker将默认使用Google的8.8.8.8 DNS服务器,这可能会影响防火墙后面的人。

    • /etc/resolv.conf实际上是一个符号链接(ls -l /etc/resolv.conf),默认情况下指向/run/systemd/resolve/stub-resolv.conf(127.0.0.53)在Ubuntu 18.04中。

    • 只需更改符号链接以指向真正的DNS服务器列表/run/systemd/resolve/resolv.conf
      sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

    • 在主机上验证:cat /etc/resolv.conf

    现在您应该有一个有效的/etc/resolv.conf,供docker复制到容器中。


    为我工作。 :) - Him Hah
    在Ubuntu 18.04上,/etc/resolv.conf使用127.0.0.53,但在我的情况下它不是一个符号链接。 - gtato
    @wisbucky,请解释一下你是如何获取DNS数组的第一个值的。它是随机的还是我们可以通过什么方式获取到这个值("10.1.2.3")。 - dinu0101
    @dinu0101 你需要知道主机正在使用的DNS服务器(这是一个单独的问题)。你可以尝试运行 nslookup google.com,第一行 Server: 就是它。 - wisbucky
    我在公司的工作站上使用vmware ubuntu18.04,第二个-B选项对我有效。谢谢! - Tran Triet
    添加 { "dns": ["8.8.8.8", "8.8.4.4"] } 对我来说有效。 - undefined

    11
    $ sudo docker run -i -t --net=host ubuntu /bin/bash
    # apt-get update
    

    没有错误!- 注意添加了 --net=host


    以下是如何重现错误。
    我在一个只安装了 Ubuntu 18.04 的干净机器上执行以下操作:

    首先安装 docker。逐行复制并在每行后按Enter

    sudo apt update                         # took 11 seconds for me
    sudo apt install -y apt-transport-https ca-certificates \
    curl software-properties-common
    

    上述两个命令中的第二个命令(一个命令分成两行)可选,我执行需要大约20秒。
    echo "cacert=/etc/ssl/certs/ca-certificates.crt" >> ~/.curlrc
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
    | sudo apt-key add -
    

    sudo add-apt-repository "deb [arch=amd64] https://\
    download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
    

    上述命令在我的电脑上花费了约7秒钟。

    sudo apt update                         # ~3 seconds this time
    sudo apt install -y docker-ce           # ~1 minute for me
    

    可选操作 -- 如果你不想每次在 docker 前加上 sudo:

    sudo usermod -aG docker ${USER}
    

    注销并重新登录。
    确认docker现已添加到您的组中:
    id -nG
    

    现在进入感兴趣的核心部分:

    $ sudo docker run -it ubuntu /bin/bash  # ~10 seconds for me
    # apt update                            # first Err after ~1 minute
    Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
      Connection failed [IP: 91.189.88.152 80]
    Err:2 http://security.ubuntu.com/ubuntu focal-security InRelease
      Connection failed [IP: 91.189.88.152 80]
    Err:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease
      Connection failed [IP: 91.189.88.152 80]
    Err:4 http://archive.ubuntu.com/ubuntu focal-backports InRelease
      Connection failed [IP: 91.189.88.152 80]
    ...
    W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/focal/InRelease [...]
    ...
    W: Some index files failed to download. They have been ignored, [...]
    

    请看,我刚刚重新创建了OP描述的错误!
    OP得到了“无法解析'archive.ubuntu.com'”,
    而我得到了“无法获取http://archive.ubuntu.com”。
    但根本原因是相同的:Docker容器没有访问互联网的权限。
    我不想继续使用这个有问题的Docker容器,所以我按下了 Ctrl + D
    我也不想保留它,所以我执行了以下命令:
    sudo docker container ps -a
    

    这告诉我,在我的案例中,CONTAINER IDc05ec98236f0

    我删除了这个容器:

    sudo docker container rm c05ec98236f0
    

    注意一下,有些事情不会给我报错。

    $ sudo docker run -it --net=host ubuntu bash
    # apt update                            # ~7 seconds
    Get:1 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]
    ...
    Fetched 16.4 MB in 4s (4332 kB/s)
    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    3 packages can be upgraded. Run 'apt list --upgradable' to see them.
    

    看这里!没有错误!

    参考文献:
    https://askubuntu.com/questions/1162163#1162198
    https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04
    https://dev59.com/SnA75IYBdhLWcg3wrrNS
    https://dev59.com/7VgQ5IYBdhLWcg3wGgBY


    只是添加 --net=host 对我很有用。谢谢。 - jdk

    4

    首先检查您是否有连接,直接ping IP地址91.189.92.201,该IP地址指向archive.ubuntu.com:

    ping 91.189.92.201

    如果您仍然无法到达主机,则不是DNS问题。

    另外,如果您有互联网连接,可以进行一次hack。只需将一行插入/etc/hosts文件即可解决问题:

    91.189.92.201 archive.ubuntu.com


    1
    我可以ping通archive.ubuntu.com,但仍然显示错误W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/trusty/InRelease - Tinkaal Gogoi

    3
    我正在使用Mint的版本,并在安装Docker后尝试创建Ubuntu镜像,但是执行apt-get update命令时无法识别。为解决这个问题,我按照以下步骤进行操作:
    docker run -it -p 8080:80  ubuntu /bin/bash
    echo "91.189.92.201 archive.ubuntu.com" >> /etc/hosts
    cat /etc/hosts
    apt-get update
    

    嗨Kor,你的代码可能是正确的,但如果加上一些上下文,它会成为更好的答案;例如,你可以解释一下这个提议的改变如何以及为什么会解决提问者的问题,或许包括一个相关文档的链接。这将使它对他们更有用,也将对其他寻找类似问题解决方案的网站读者更有用。 - Vince Bowdren
    看看现在有没有改进! - cristofersousa
    1
    回答很有趣,但自从写这篇文章以来IP地址已经更改,因此在执行此操作之前,可能需要进行DNS查找以检索archive.ubuntu.com的最新IP地址。 - Emmanuel

    2

    我在两种情况下遇到了问题,解决方案不同...

    第一种情况是Win7 + virtualbox(Xubuntu 16.04) 这条评论解决了问题:https://dev59.com/yl0b5IYBdhLWcg3wEdsx#29659783

    我修改了文件/etc/default/docker:

    DOCKER-OPTS="--ip-masq=true --dns my_ip_dns_win --dns 8.8.8.8 --dns 8.8.4.4" 然后运行 sudo service docker restart

    第二种情况是Xubuntu操作系统(ubuntu 16.04) 之前的解决方案不够。 这个评论解决了问题:https://github.com/docker/docker/issues/1809 我必须注释掉文件/etc/NetworkManager/NetworkManager.conf中的一行:

    dns=dnsmasq

    然后运行

    sudo restart network-manager


    1
    对于 --ip-masq=true,给予加1。如果您在另一个防火墙后面,并且只允许Docker主机与外部通信,则非常有用。 - mofoe

    2

    如果您正在运行docker build,则无法指定--net=host。这种情况会发生。

    在这种情况下,请执行以下操作:

    1. 如果不存在,则创建vim /etc/docker/daemon.json。通常不会存在。
    2. 将以下内容添加到文件中
    {
        "dns": ["10.1.2.3", "8.8.8.8"]
    }
    
    1. 如果您不想使用systemctl,请重新启动Dockersudo service docker restart

    我正在使用WSL2 Ubuntu。这个方法可行。


    1

    docker-compose出错 我遇到了与docker-compose相同的问题。我通过将ENV http_proxy 'proxy.com'添加到Dockerfile中来解决这个问题。


    对我有用,谢谢。但请注意,您应该将“ENV http_proxy 'proxy.com'”和“apt-get update”放在同一行中,以便两者在同一个容器中运行。 - vahidzolf

    1
    我使用的是Jenkins基础镜像,无论我做什么,apt-get update都会失败。 最终,这个方法有帮助,删除/var/lib/apt/lists/ /etc/apt/sources.list.d/* *解决了问题。
    USER root
    RUN rm -rf /var/lib/apt/lists/*
    RUN rm -rf /etc/apt/sources.list.d/*
    RUN apt-get update
    ....Continue using apt-get for installing your stuff..
    RUN apt-get install -y maven
    

    0

    只需使用“ubuntu:20.04”镜像(之前的LTS版本)而不是“ubuntu”。这对我有效。


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