本文发自 http://www.binss.me/blog/the-way-to-use-host-proxy-in-docker-containers-or-parallels-desktop-machines/,转载请注明出处。
问题
Docker容器内,apt-get无法更新,报错:
Err http://archive.ubuntu.com trusty Release.gpg
Cannot initiate the connection to 6152:80 (0.0.24.8). - connect (22: Invalid argument)
经过检查,原来是Docker在容器中也使用了我的系统全局代理设置,通过env可以发现设置了HTTP和HTTPS代理为127.0.0.1:6152。而显然容器localhost是没有开启代理服务的,导致出错。
最简单的解决方法是unset掉环境变量:
$ unset no_proxy http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
此时apt-get能够正常更新,然而速度缓慢,时不时抛个缓存错误。这是因为只是摘掉了错误的代理,相当于直连,受运营商劫持到Cache等影响导致,最好的解决方法当然是代理出去。经过一番折腾,发现Docker网络流量皆由com.docker.slirp这个进程发出,在宿主机上通过Proxifier将之劫持到代理端口即可。
然而又发现了一个问题,我发现代理软件上收到的请求的目标是IP而不是域名,而我的代理规则又主要是基于域名的,虽然可以把IP写死到规则里,再用个掩码划一个网段,但总是不嗨森。
这时候突然发现思路错了。解决问题的point不是如何在宿主机中使容器走代理,应该是如何在容器内连接宿主机的代理。
方案
宿主机上跑个Web Server,容器内尝试wget,能成功代表可以成功访问宿主机。
解决
先查看容器的接口信息:
root@88fbd6e341ec:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:14 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1156 (1.1 KB) TX bytes:578 (578.0 B)
于是猜想宿主机的IP为172.17.0.1,ping一下发现可以ping通,然而wget却失败了。这时想起在Mac上,Docker本身也是跑在一个虚拟机内的,172.17.0.1可能就是该虚拟机的IP。
由于我用的是Docker for MAC,使用的是Xhyve,而我对此没什么了解,只能上官方论坛一阵搜索,发现可通过Screen命令来访问虚拟机:
$ screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
输完命令后敲回车出现登录提示,输入root登入。
登入后查看接口信息:
Welcome to the Moby alpha, based on Alpine Linux.
moby:~# ifconfig
docker0 Link encap:Ethernet HWaddr 02:42:00:CF:6F:AD
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:ff:fecf:6fad%32719/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:77 errors:0 dropped:0 overruns:0 frame:0
TX packets:58 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:4151 (4.0 KiB) TX bytes:28040 (27.3 KiB)
eth0 Link encap:Ethernet HWaddr C0:FF:EE:C0:FF:EE
inet addr:192.168.65.2 Bcast:192.168.65.7 Mask:255.255.255.248
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:109 errors:0 dropped:0 overruns:0 frame:0
TX packets:112 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:45044 (43.9 KiB) TX bytes:8691 (8.4 KiB)
果然,这台虚拟机的IP为172.17.0.1,并通过此和容器共享网络。看这台虚拟机的网卡eth0,很明显是对外的了,本机IP为192.168.65.2,猜测宿主机IP为192.168.65.1。wget一下:
moby:~# wget 192.168.65.1:7777
Connecting to 192.168.65.1:7777 (192.168.65.1:7777)
index.html 100% |*******************************| 12068 0:00:00 ETA
成功。到容器中试试:
root@88fbd6e341ec:/# wget 192.168.65.1:7777
--2016-07-21 17:13:37-- http://192.168.65.1:7777/
Connecting to 192.168.65.1:7777... connected.
HTTP request sent, awaiting response... 200 OK
Length: 12068 (12K) [text/html]
Saving to: ‘index.html’
100%[====================================================================>] 12,068 --.-K/s in 0s
2016-07-21 17:13:37 (254 MB/s) - ‘index.html’ saved [12068/12068]
成功。因此到Docker的设置中设置成相应的IP即可:
注意容器的环境变量在创建时就被定下了,要改需要重新创建容器.....
搞定后发现apt-get终于走了宿主机的代理了:
P.S. 向screen发送命令的快捷键和我们习惯的不一样,比如quit的快捷键为 Ctrl+a Ctrl+\ ,然后按y。具体可以查阅man。
2018.01.11 更新
心血来潮将 Docker 更新到 17.12.0-ce-mac46 (21698) ,结果发现代理失效了。
重复以上方法发现宿主机 ip 变为 192.168.65.2 ,在 Docker 的设置中修改后发现不会被新建容器所继承,还会导致 pull image 时尝试走该代理而无法连接,因此在设置处设置为 Use System Proxy
就好。
然后记得在新建容器时指定环境变量:
-e HTTP_PROXY=http://192.168.65.2:6152/ -e http_proxy=http://192.168.65.2:6152/ -e HTTPS_PROXY=https://192.168.65.2:6152/ -e https_proxy=https://192.168.65.2:6152/
同时流量也不再是由 com.docker.slirp 发出而是 VPNkit,这和 Docker 的架构变化有关。
Parallels Desktop虚拟机代理方案
虽然我的虚拟机都是拿来玩游戏跑迅雷的,但偶尔也是需要访问宿主机的,比如说访问Docker容器映射到宿主机端口上的游戏服务端(有点绕)。
这里宿主机IP就比较容易看了,打开Parallels desktop的Preferences-Network,选择虚拟机正在使用的网络,勾选Show in System Preferences,然后就能够在MAC的Network中看到宿主机的IP:
拿到之后在IE里填上:
于是原本不能访问外网(Host-Only)的虚拟机通过访问宿主机的代理后能够上网了:
题外话:我对访问百度过程中访问的123.60.63.137很好奇,查了下,貌似是微软在HK的服务器?是用来验证的还是用来分析用户行为的?害怕.jpg。
总结
折腾了一晚上,累感不爱。以文记之,希望能帮到大家。
1F ZengLeiPro 7 years, 7 months ago 回复
谢谢,帮了大忙
2F zz 7 years, 1 month ago 回复
好奇 HTTP 代理软件是什么,居然还能看到代理源?
3F miltonleex 7 years, 1 month ago 回复
截图上的http抓包软件是啥?
4F springwarm 6 years, 9 months ago 回复
回复 [3F] miltonleex:Surge。同遇到博主这个问题,环境完全一样 (Docker for Mac + Surge),然而自己并没有什么思路,汗颜。感谢博主。
5F binss MOD 6 years, 9 months ago 回复
回复 [2F] zz:Surge for Mac。不好意思,之前评论通知模块出了点问题,现在才看见
6F twitter 6 years, 4 months ago 回复
我想问个小白问题,6152这个端口号我如何简单快速获得。谢谢了。
7F binss MOD 6 years, 4 months ago 回复
回复 [6F] twitter:这个是你本地 HTTP 代理的端口号,我用的是 Surge for Mac,端口是可以自己在配置文件里配置的,我配置的是 6152
8F 笑笑生 6 years, 3 months ago 回复
如何在docker 给不同的容器 设不同的代理ip?
9F binss MOD 6 years, 3 months ago 回复
回复 [8F] 笑笑生:由于我走的是宿主机的代理,所以填的是宿主机对应的 IP ,192.168.65.2 是 docker 在内部网桥中为宿主机分配的 IP。既然你需要走不同的代理 IP,那么可以认为你的代理是在外部。创建不同容器时各自进行指定即可:
-e HTTP_PROXY=http://(your_proxy_ip):(your_proxy_port)/ -e http_proxy=http://(your_proxy_ip):(your_proxy_port)/ -e HTTPS_PROXY=https://(your_proxy_ip):(your_proxy_port)/ -e https_proxy=https://(your_proxy_ip):(your_proxy_port)/
10F gchr 6 years, 1 month ago 回复
网上找到了这篇文章 https://juejin.im/post/5ae921bf6fb9a07aad17528c 同时看到了你的😊
11F 匿名 3 years, 11 months ago 回复
在Mac上docker宿主机的IP可以用docker.for.mac.host.internal作为地址直接访问,在网上找的,不用费劲去找ip了