【问题标题】:How do you run `apt-get` in a dockerfile behind a proxy?如何在代理后面的 dockerfile 中运行 apt-get?
【发布时间】:2014-04-06 10:07:23
【问题描述】:

我正在使用 docker(版本 0.8.1,构建 a1598d1)运行虚拟机(Ubuntu 13.10)。我正在尝试使用 dockerfile 构建图像。首先,我想更新软件包(使用下面的代码 - 代理被混淆)但 apt-get 超时并出现错误:Could not resolve 'archive.ubuntu.com'

FROM ubuntu:13.10
ENV HTTP_PROXY <HTTP_PROXY>
ENV HTTPS_PROXY <HTTPS_PROXY>
RUN export http_proxy=$HTTP_PROXY
RUN export https_proxy=$HTTPS_PROXY
RUN apt-get update && apt-get upgrade

我还在主机系统中运行了以下内容:

sudo HTTP_PROXY=http://<PROXY_DETAILS>/ docker -d &

主机能够毫无问题地运行apt-get

如何更改 dockerfile 以允许它从容器内访问 ubuntu 服务器?

更新

我在 CentOS 中运行了代码(将 FROM ubuntu:13.10 更改为 FROM centos),它运行良好。这似乎是 Ubuntu 的问题。

【问题讨论】:

  • 我刚刚在 centos (yum update) 和 ubuntu:13.10 (apt-get update) 中测试了 http 代理。这两个图像都对我有用,我什至尝试从容器中删除 dns 设置来测试代理(它应该可以在没有 dns 的情况下正常工作)。我只使用 http_proxy(没有 https)。
  • 您的 Dockerfile 中是否真的有“”或者这是一个占位符?
  • 我在文件中有实际的代理。我只是无法分享地址。
  • 看看这篇文章:Using Docker Behind a Proxy

标签: docker apt http-proxy


【解决方案1】:

更新

ENV 中的环境变量大小写错误。正确的是http_proxy。你的例子应该是:

FROM ubuntu:13.10
ENV http_proxy <HTTP_PROXY>
ENV https_proxy <HTTPS_PROXY>
RUN apt-get update && apt-get upgrade

FROM centos
ENV http_proxy <HTTP_PROXY>
ENV https_proxy <HTTPS_PROXY>
RUN yum update 

在 ENV 中指定的所有变量都添加到每个 RUN 命令之前。每个 RUN 命令都是在自己的容器/环境中执行的,因此它不会从以前的 RUN 命令继承变量!

注意:无需使用代理调用 docker daemon 即可工作,但如果您想提取图像等,您也需要为 docker deamon 设置代理。您可以在 Ubuntu 中为 /etc/default/docker 设置守护进程代理(不影响容器设置)。


此外,如果您在主机上运行代理(即 localhost,127.0.0.1),也会发生这种情况。主机上的 localhost 与容器中的 localhost 不同。在这种情况下,您需要使用另一个 IP(如 172.17.42.1)将您的代理绑定到,或者如果您绑定到 0.0.0.0,您可以在 docker build 期间使用 172.17.42.1 而不是 127.0.0.1 从容器连接。

您也可以在此处查找示例:How to rebuild dockerfile quick by using cache?

【讨论】:

  • 我在主机上没有代理。这是我落后的公司代理。相同的代码适用于具有相同代理设置的 CentOS(仅更改 FROM)。
  • 在 Docker 的当前状态下,您的 Dockerfile 中似乎必须有 ENV http_proxy corporate-proxy.com。这很恶心,因为这意味着您不能与公司以外的任何人共享您的 Dockerfile。我刚刚通过在容器中运行 polipo 验证了这一点,同时尝试缓存 apt-get install 用于开发 Dockerfile 的命令。也许未来版本的 Docker 将拥有一些神奇的 iptables 配置,允许对 HTTP 请求进行透明代理?
  • @TimPotter 我认为这还不错(不需要高级魔法)。您需要使用父代理 (polipo parentProxy=corporate-proxy.com) 在主机上设置 polipo,而不是使用 iptables 设置透明代理:iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner &lt;polipo-user&gt; --dport 80 -j REDIRECT --to-port 8123
  • 我刚刚整理了一个项目,该项目提供在容器中运行的 squid,并带有适当的 iptables / ip 规则命令,以通过 squid 容器重定向所有其他容器流量以进行透明代理。这可能对您所描述的有用吗? silarsis.blogspot.com.au/2014/03/proxy-all-containers.html
  • 你有办法从 docker 容器中获取 docker daemon (/etc/defailt/docker) 中的 http_proxy 设置吗?所以我可以添加脚本以注入 Dockerfile
【解决方案2】:

我遇到了同样的问题,并找到了另一个小解决方法: 我有一个从 docker 构建环境中添加的配置器脚本。 在脚本中,我根据 ping 检查设置环境变量:

Dockerfile:

ADD script.sh /tmp/script.sh
RUN /tmp/script.sh

script.sh:

if ping -c 1 ix.de ; then
    echo "direct internet doing nothing"
else
    echo "proxy environment detected setting proxy"
    export http_proxy=<proxy address>
fi

这仍然有点粗糙,但对我有用

【讨论】:

  • 这对你有用吗?我可以让脚本运行得很好,但是环境变量只对脚本可用。 apt-get、cURL 和 wget 之类的东西最终不会看到环境变量。
【解决方案3】:

于 2018 年 2 月 10 日更新

有了 docker 选项--config 中的新功能,您不再需要在 Dockerfile 中设置 Proxy。您可以在有或没有代理设置的情况下在公司环境内外使用相同的 Dockerfile

命令docker run 选项:

--config string      Location of client config files (default "~/.docker")

或环境变量DOCKER_CONFIG

`DOCKER_CONFIG` The location of your client configuration files.

$ export DOCKER_CONFIG=~/.docker

https://docs.docker.com/engine/reference/commandline/cli/

https://docs.docker.com/network/proxy/

我建议用httpProxy, httpsProxy, ftpProxynoProxy设置代理(官方文档漏掉了变量ftpProxy,这个变量有时很有用)

{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://192.168.1.12:3128",
     "httpsProxy": "http://192.168.1.12:3128",
     "ftpProxy": "http://192.168.1.12:3128",
     "noProxy": "*.test.example.com,.example2.com,127.0.0.0/8"
   }
 }
}

为您的代理环境调整代理IP和端口并保存到~/.docker/config.json

设置好之后,就可以正常运行docker build和docker run了。

$ cat Dockerfile

FROM alpine

$ docker build -t demo . 
    
$ docker run -ti --rm demo env|grep -ri proxy
(standard input):HTTP_PROXY=http://192.168.1.12:3128
(standard input):http_proxy=http://192.168.1.12:3128
(standard input):HTTPS_PROXY=http://192.168.1.12:3128
(standard input):https_proxy=http://192.168.1.12:3128
(standard input):NO_PROXY=*.test.example.com,.example2.com,127.0.0.0/8
(standard input):no_proxy=*.test.example.com,.example2.com,127.0.0.0/8
(standard input):FTP_PROXY=http://192.168.1.12:3128
(standard input):ftp_proxy=http://192.168.1.12:3128

旧答案(已停用)

Dockerfile 中的以下设置对我有用。我在CoreOSVagrantboot2docker 中进行了测试。假设代理端口为3128

###在 Centos 中:

ENV http_proxy=ip:3128 
ENV https_proxy=ip:3128

###在 Ubuntu 中: ENV http_proxy 'http://ip:3128' ENV https_proxy 'http://ip:3128'

注意格式,有的有http,有的没有,有的只有单一配额。如果 IP 地址为 192.168.0.193,则设置为:

###在 Centos 中:

ENV http_proxy=192.168.0.193:3128 
ENV https_proxy=192.168.0.193:3128

###在 Ubuntu 中: ENV http_proxy 'http://192.168.0.193:3128' ENV https_proxy 'http://192.168.0.193:3128'

###如果需要在coreos中设置代理,例如拉取镜像

cat /etc/systemd/system/docker.service.d/http-proxy.conf

[Service]
Environment="HTTP_PROXY=http://192.168.0.193:3128"

【讨论】:

  • 您可能还需要添加 https 代理设置,因为 apt-get 将使用安全连接。 [服务] Environment="HTTP_PROXY=your-proxy-server:port" HTTPS_PROXY=your-proxy-server:port:3128" "NO_PROXY=localhost,127.0.0.0/8"
  • 请注意,对于 Centos,您必须明确添加端口号,即使它是默认端口 80: stackoverflow.com/a/46949277/1654763
  • 这行得通。谢谢你的例子。 Docker 文档对此并不清楚。
  • $DOCKER_CONFIG 应该指向一个目录而不是直接指向config.json 文件
【解决方案4】:

我们正在做...

ENV http_proxy http://9.9.9.9:9999
ENV https_proxy http://9.9.9.9:9999

在 dockerfile 的末尾 ...

ENV http_proxy ""
ENV https_proxy ""

目前(直到 docker 引入构建环境变量),允许代理环境变量仅用于构建而不暴露它们

解决方案的替代方案不是在代理后面本地构建图像,而是让 docker 使用 docker“自动构建”为您构建图像。由于 docker 没有在您的代理后面构建图像,因此问题已解决。自动构建的示例可在 ...

https://github.com/danday74/docker-nginx-lua(GITHUB 仓库)

https://registry.hub.docker.com/u/danday74/nginx-lua(DOCKER repo 正在使用自动构建监视 github repo,并在推送到 github master 分支时执行 docker build)

【讨论】:

  • 只是想提一下,由于这些 ENV 变量暴露在每个中间容器中,最后取消设置它们不会隐藏它们,并且仍然可以很容易地访问它们。据我所知,处理敏感数据的安全选项已在此github issue 中介绍
【解决方案5】:

在你的 Dockerfile 中的任何 apt-get 命令之前,你应该把这一行放在

COPY apt.conf /etc/apt/apt.conf

不要忘记在您拥有 Dockerfile 的同一文件夹中创建 apt.confapt.conf 的内容文件应该是这样的:

Acquire::socks::proxy "socks://YOUR-PROXY-IP:PORT/";
Acquire::http::proxy "http://YOUR-PROXY-IP:PORT/";
Acquire::https::proxy "http://YOUR-PROXY-IP:PORT/";

如果您使用用户名和密码连接到您的代理,那么 apt.conf 应该如下所示:

Acquire::socks::proxy "socks://USERNAME:PASSWORD@YOUR-PROXY-IP:PORT/";
Acquire::http::proxy "http://USERNAME:PASSWORD@YOUR-PROXY-IP:PORT/";
Acquire::https::proxy "http://USERNAME:PASSWORD@YOUR-PROXY-IP:PORT/";

例如:

Acquire::https::proxy "http://foo:bar@127.0.0.1:8080/";

其中 foo 是用户名,bar 是密码。

【讨论】:

  • apt 根本不支持 SOCKS 代理。 Acquire::socks::proxy 表示为所有以 socks 方案开头的 URL 设置代理。由于您的 sources.list 没有任何 socks:// URL,因此该行将被完全忽略。我将提交修改以更正此问题。
  • 你在jessie 上有/etc/apt/apt.conf.d/&lt;config&gt;,所以Dockerfile COPY 指令需要在这里更新。
  • 这是唯一对我有用的答案(在公司代理后面运行 Docker for Windows)。
【解决方案6】:

如果你想为 wget 设置代理,你应该把这些行放在你的 Dockerfile

ENV http_proxy YOUR-PROXY-IP:PORT/
ENV https_proxy YOUR-PROXY-IP:PORT/
ENV all_proxy YOUR-PROXY-IP:PORT/

【讨论】:

    【解决方案7】:

    正如 Tim Potter 所指出的,在 dockerfile 中设置代理是可怕的。构建映像时,您为公司网络添加代理,但您可能部署在不需要代理或代理服务器不同的云或 DMZ 中。

    此外,您不能与公司 n/w 以外的其他人分享您的图像。

    【讨论】:

      【解决方案8】:

      当您想使用 Dockerfile 进行构建时,可以使用 --build-arg 选项。

      通过https://github.com/docker/docker/issues/14634 上的链接,请参阅“使用--build-arg 和多个HTTP_PROXY 构建”部分:

      [root@pppdc9prda2y java]# docker build 
        --build-arg https_proxy=$HTTP_PROXY --build-arg http_proxy=$HTTP_PROXY 
        --build-arg HTTP_PROXY=$HTTP_PROXY --build-arg HTTPS_PROXY=$HTTP_PROXY 
        --build-arg NO_PROXY=$NO_PROXY  --build-arg no_proxy=$NO_PROXY -t java .
      

      注意: 在您自己的系统上,确保您已设置 HTTP_PROXY 和 NO_PROXY 环境变量。

      【讨论】:

      • 这是一个讨厌的解决方法,对于持久设置,你应该使用 Dockerfile,就像@Reza Farshi 给出的例子
      • 讨厌的解决方法?在某些(大多数)情况下,最好不要将您自己的代理嵌入到图像中,如果您的图像(例如)供公司其他部门的人使用,他们可能使用不同的代理。
      【解决方案9】:

      在小写环境变量中使用--build-arg:

      docker build --build-arg http_proxy=http://proxy:port/ --build-arg https_proxy=http://proxy:port/ --build-arg ftp_proxy=http://proxy:port --build-arg no_proxy=localhost,127.0.0.1,company.com -q=false .
      

      【讨论】:

        【解决方案10】:

        正如其他答案所建议的那样,--build-arg 可能是解决方案。 就我而言,除了--build-arg 选项之外,我还必须添加--network=host

        docker build -t <TARGET> --build-arg http_proxy=http://<IP:PORT> --build-arg https_proxy=http://<IP:PORT> --network=host .
        

        【讨论】:

        • 如果它只在使用 --network=host 时有效,如果可能是 dnsmasq 的问题。请参阅下面的 wisbucky 的回答。在主机上的 /etc/resolv,conf 中获得正确的 dns 后,您不需要 --network=host
        【解决方案11】:

        如果您的代理设置正确,但仍无法访问互联网,则可能是 DNS 解析。检查主机 Ubuntu VM 上的 /etc/resolve.conf。如果它包含nameserver 127.0.1.1,那就错了。

        在主机 Ubuntu VM 上运行这些命令来修复它:

        sudo vi /etc/NetworkManager/NetworkManager.conf
        # Comment out the line `dns=dnsmasq` with a `#`
        
        # restart the network manager service
        sudo systemctl restart network-manager
        
        cat /etc/resolv.conf
        

        现在/etc/resolv.conf 应该有一个有效的名称服务器值,它将被 docker 容器复制。

        【讨论】:

        • 谢谢!这个答案非常有帮助,最终帮助我让pip install 在代理后面与 docker 一起工作。这不是 OP 真正想要的,但对我帮助很大! :)
        • 这里也一样,谢谢!以下是有关此问题的更多信息:superuser.com/questions/681993/…
        【解决方案12】:

        @Reza Farshi 提供的答案的一个小替代方案(在我的情况下效果更好)是通过 Dockerfile 使用echo 将代理设置写入/etc/apt/apt.conf,例如:

        FROM ubuntu:16.04
        
        RUN echo "Acquire::http::proxy \"$HTTP_PROXY\";\nAcquire::https::proxy \"$HTTPS_PROXY\";" > /etc/apt/apt.conf
        
        # Test that we can now retrieve packages via 'apt-get'
        RUN apt-get update
        

        这种方法的优点是可以在映像构建时动态传递代理地址,而不必从主机复制设置文件。

        例如

        docker build --build-arg HTTP_PROXY=http://&lt;host&gt;:&lt;port&gt; --build-arg HTTPS_PROXY=http://&lt;host&gt;:&lt;port&gt; .

        根据docker build docs。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-06-20
          • 2013-07-10
          • 1970-01-01
          • 2022-07-12
          • 1970-01-01
          • 1970-01-01
          • 2015-08-31
          • 1970-01-01
          相关资源
          最近更新 更多