好吧,今天的文章只和程序有关,和人生无关。连续喝了几天大馇子粥,该上点清香逸人的咖啡了。
如果你不知道啥是虚拟机(vagrant是一款虚拟机管理软件),看到这里可以休息休息眼睛,明天的连载传记『途客们的旅行梦』再见。
TL;DR
最近vagrant 1.5升级力度空前,增加了很多新功能,其中最令人瞩目的当属 vagrant share
。啥子意思呢?就是把你的虚拟机share给地球另一端的人。这功能很高大上啊,简直是居家旅行,远程办公的必备武器。你正在做的web app出bug了,需要帮忙?没问题,亲,把虚拟机share一下。
➜ dockerbox vagrant share
==> default: Detecting network information for machine...
...
==> default: URL: http://cheerful-beaver-2087.vagrantshare.com
...
我的虚机里开放了3000端口,是个web app。share好以后,别人就可以使用这个链接:http://cheerful-beaver-2087.vagrantshare.com
,访问程序君正在调试开发的app了。(别试了,当您看到本文时,程序君已经把共享关闭喽)。
很神奇吧?(更有意思的vagrant connect有待你自己去发掘)
估计你有和程序君一样的问题。程序君开始捣鼓。
首先tcp dump抓包。
➜ appshare git:(master) ✗ tcpdump -i en0
内容很多,就不在这里呈现了。没有太多实质的内容,主要是下面几个步骤:
(1) DNS请求 vagrantcloud.com 获得两个IP: 107.23.21.165, 54.85.101.30
(2) 分别进行https握手(详细内容见知乎)
(3) 传输数据 blablabla(这不废话么)
郁闷的是vagrant考虑到数据安全性,全部采用https,所以无法窥探里面的究竟。
为什么不用Fiddler来偷窥?好吧,fillder基于.net,程序君不想在mac上装mono...
所以程序君只能靠脑子生猜这个功能是怎么实现的了。
可能的实现手段:
(1) 使用ssl V**。具体做法:
local http server --- sslV** client ===== SA --- cloud http server
当ssl V** tunnel建立成功后,localp http server和cloud http server间就跟局域网一样可以直接访问。从浏览器访问过来的数据,可以被proxy到local http server,而不用担心网络连接。
不过,vagrant share不是这么实现的。因为建立ssl V**后ifconfig
会看到新的tunnel interface。而vagrant share之后,没有新的interface。
(2) 使用tcp proxy。具体做法:
local http server --- local proxy --- cloud proxy ---- cloud http server
用户从url访问过来的http请求,被cloud http server负载到cloud proxy,然后cloud proxy再将其relay给local proxy,local proxy再relay给local http server;http响应反之。
这个想法比较靠谱。
试着用go简单实现了一下,主要是为了验证想法。结果证实了这个方案可行(我搭了个本机的环境):
local http server (8000) --- local proxy --- (8211) cloud proxy (8211) ---- cloud http server
由于我在测试,所以不需要放一个nginx在cloud http server侧,直接访问:http://192.241.1xx.xx:8211
(我的一台ditalocean服务器)即可。经过两层proxy,local http server的内容被转到浏览器上。当然,目前的代码有问题,local proxy和cloud proxy间只有一个tcp connection,遇到keep-alive的http connection就阻塞住了...然后,然后后续的connection的数据就过不去了(堵车),所以你看到的页面是这样(local http server跑的是我的博客):
哈,给你一个到处都能访问的url,你就可以访问我本机的某个web app了。
方案没有大问题,需要注意的是下面几点:
(1) cloud proxy监听一个端口(如8211),等待http server或者browser过来的http request。
(2) cloud proxy监听另一个端口(如8210),等待local proxy的连接。注意因为local proxy(跑在用户的机器上)没有确定的公网地址,所以cloud proxy只能被动等待连接。
(3) local proxy启动后就要和cloud proxy建立持续的tcp connection。当cloud proxy有数据到达时(http request),cloud proxy才建立和local http server的tcp连接,将http request转至local http server。
(4) 基于以上前提,cloud proxy要先运行起来,然后是local proxy。
另外,如果真要把这个东西做成像vagrant share一样(先不考虑https),则需要:
(1) 自动生成唯一且难以猜测的名字。如 easy-sheep-9048.share.tchen.me
。并且client proxy和cloud proxy能根据它找到二者之间的连接。
(2) 域名提供商能够支持泛域名解析(最好三级域名也支持),dnspod免费版支持二级。
(3) nginx server配置将泛域名作为http request的一个参数传递给cloud proxy,然后cloud proxy可以区分对应的是哪个share。
有空程序君再把它捣鼓好吧。