如何让Docker容器通过代理连接所有内容

5
我知道可以像这个StackOverflow答案所示的那样,将http_proxy和https_proxy环境变量传递给容器。不过,这仅适用于像wget和curl这样的代理感知命令,因为它们仅仅读取并使用这些环境变量。
我需要通过代理连接所有东西,以便所有的Internet访问都通过代理路由。实际上,代理应该被转换成一种VPN类型。
我正在考虑类似于--net=container选项的东西,其中容器从另一个容器获取其网络。
如何配置容器使所有内容都通过代理运行?

也许您可以像这个问题的答案中所述更改默认路由:https://dev59.com/MFoU5IYBdhLWcg3w9aei - Hans Kilian
@HansKilian 我该如何更改默认路由以使用代理,例如http://username:password@proxy2.domain.com?任何想法都将不胜感激 :) - marlar
1
https://medium.datadriveninvestor.com/how-to-transparently-use-a-proxy-with-any-application-docker-using-iptables-and-redsocks-b8301ddc4e1e - Jan Garaj
如果我理解正确,您想将所有容器放在代理后面?如果是这样,我会将它们全部放在自己的虚拟网络中,并与一个暴露每个容器独立端点的nginx容器一起使用。 - Brandon Piña
@JanGaraj,你提供的链接实际上提供了有价值的信息。我认为我可以从那里开始。 - marlar
@BrandonPina 不,只有一个容器。我认为关键词是透明代理。 - marlar
2个回答

5

Jan Garaj的评论实际上指引了我正确的方向。

正如我的问题所述,不是所有程序和命令都使用代理环境变量,因此简单地将http_proxy和https_proxy env变量传递给docker并不是一个解决办法。我需要一个解决方案,在这个方案中整个docker容器都通过代理在某些端口上发送每个网络请求。无论哪个程序或命令发出的请求,都要通过代理。

Medium文章演示了如何构建和设置一个docker容器,通过redsocks的帮助,将所有ftp请求重定向到另一个作为代理运行的docker容器。容器之间的通信通过docker网络完成。

在我的情况下,我已经有一个正在运行的代理,因此我不需要docker网络和docker代理。此外,我需要代理http和https,而不是ftp。

通过更改配置文件,我让它工作了。在这个例子中,我只是调用wget ipecho.net/plain来检索我的外部IP。如果它起作用,这应该是代理的IP,而不是我的真实IP。

配置

Dockerfile:

FROM debian:latest
LABEL maintainer="marlar"
WORKDIR /app
ADD . /app
RUN apt-get update
RUN apt-get upgrade -qy
RUN apt-get install iptables redsocks curl wget lynx -qy
COPY redsocks.conf /etc/redsocks.conf
ENTRYPOINT /bin/bash run.sh

安装脚本(run.sh):

#!/bin/bash
echo "Configuration:"
echo "PROXY_SERVER=$PROXY_SERVER"
echo "PROXY_PORT=$PROXY_PORT"
echo "Setting config variables"
sed -i "s/vPROXY-SERVER/$PROXY_SERVER/g" /etc/redsocks.conf
sed -i "s/vPROXY-PORT/$PROXY_PORT/g" /etc/redsocks.conf
echo "Restarting redsocks and redirecting traffic via iptables"
/etc/init.d/redsocks restart
iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 12345
iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-port 12345
echo "Getting IP ..."
wget -q -O- https://ipecho.net/plain

redsocks.conf:

base {
 log_debug = off;
 log_info = on;
 log = "file:/var/log/redsocks.log";
 daemon = on;
 user = redsocks;
 group = redsocks;
 redirector = iptables;
}
redsocks {
 local_ip = 127.0.0.1;
 local_port = 12345;
 ip = vPROXY-SERVER;
 port = vPROXY-PORT;
 type = http-connect;

}

构建容器

build -t proxy-via-iptables .

运行容器

docker run -i -t  --privileged -e PROXY_SERVER=x.x.x.x -e PROXY_PORT=xxxx proxy-via-iptables

使用相应的数字替换代理服务器和端口。

如果容器工作并使用外部代理,则wget应该输出代理的IP地址,即使wget命令不使用-e use_proxy=yes选项。如果它没有工作,则会给出您自己的IP地址。或者根据故障情况可能不会显示任何IP地址。


1
我已经尝试按照这些步骤进行操作,但每次请求都会收到502响应错误...我的设置似乎与你的类似,我在本地机器上运行mitmproxy代理服务器,同时尝试捕获来自docker容器的网络流量。 - utpamas

-1

您可以使用代理环境变量:

docker container run \
  -e HTTP_PROXY=http://username:password@proxy2.domain.com \
  -e HTTPS_PROXY=http://username:password@proxy2.domain.com \
 yourimage

如果您希望在启动容器时自动使用代理服务器,可以在Docker CLI配置文件(~/.docker/config.json)中配置默认的代理服务器。您可以在用户指南的网络部分找到有关此操作的说明

例如:

{
  "proxies": {
    "default": {
      "httpProxy": "http://username:password@proxy2.domain.com",
      "httpsProxy": "http://username:password@proxy2.domain.com"
    }
  }
}

为了验证~/.docker/config.json配置是否生效,请启动一个容器并打印其环境变量:

docker container run --rm busybox env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=220e4df13604
HTTP_PROXY=http://username:password@proxy2.domain.com
http_proxy=http://username:password@proxy2.domain.com
HTTPS_PROXY=http://username:password@proxy2.domain.com
https_proxy=http://username:password@proxy2.domain.com
HOME=/root

1
很遗憾,使用代理环境变量并不像我在问题中所述那样有效。并非所有程序都使用这些变量。我需要整个容器将所有内容重定向到代理。 - marlar

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