使用 noVNC 开发 Web 虚拟机控制台
2013年07月5日 | 标签: novnc, opennebula, vnc
OpenNebula 的控制面板 Sunstone 对 OpenNebula 私有云的管理员来说很方便实用,不用敲命令,但是对云计算、虚拟机不熟悉的用户来说有点复杂。所以,我们打算开发一个内部使用的 OpenNebula 控制面板,并和我们的其他内部服务集成起来。从不同 VPS 服务商那里用过 VPS 的用户都知道 VPS 控制面板的几个基本功能,创建、删除、重装、控制台访问。其中控制台访问功能的实现就是我们今天要讨论的主题。
我们知道不管是 VMware, Xen 还是 KVM,都可以配置 VNC 访问,然后通过 VNC 客户端访问这些虚拟机的控制台,这些 VNC 客户端往往需要下载安装,如果要开发虚拟机的 web 控制面板的话当然最好能配一个 web 的 VNC 客户端。
noVNC 正是我们需要的 HTML5 VNC 客户端,采用 HTML 5 WebSockets, Canvas 和 JavaScript 实现,noVNC 被普遍用在各大云计算、虚拟机控制面板中,比如 OpenStack Dashboard 和 OpenNebula Sunstone 都用的是 noVNC. 前面说了 noVNC 采用 WebSockets 实现,但是目前大多数 VNC 服务器都不支持 WebSockets,所以 noVNC 是不能直接连接 VNC 服务器的,怎么办呢?需要一个代理来做 WebSockets 和 TCP sockets 之间的转换,理解这一点很重要。这个代理也已经有了,在 noVNC 的目录里,叫做 websockify.
基本
下载 noVNC 代码后然后运行 noVNC/utils/websockify.py,把本机 VNC 服务(localhost)的端口(5900)和 noVNC 的代理端口(8000)连接起来,这样通过 noVNC/vnc.html 访问 8000 端口就自动转换到 5900 端口上(事实上 vnc.html 你可以放在任何机器上用浏览器直接打开用):
$ git clone https://github.com/kanaka/noVNC $ cd utils $ ./websockify.py 8000 localhost:5900 WARNING: no 'numpy' module, HyBi protocol is slower or disabled WebSocket server settings: - Listen on :8000 - Flash security policy server - No SSL/TLS support (no cert file) - proxying from :8000 to localhost:5900
流程大概是这样:
vnc.html -> 192.168.2.20:8000 -> websockify.py -> localhost:5900
当然代理和 VNC 服务可以不在同一机器上,比如代理在 192.168.2.20, VNC 服务在 192.168.2.21:
$ ./websockify.py 8000 192.168.2.21:5900
流程大概是这样:
vnc.html -> 192.168.2.20:8000 -> websockify.py -> 192.168.2.21:5900
理解了上面的过程,应该有想法如何集成 noVNC 到自己的程序了,很简单,先用 websockify 架一个代理,然后用 vnc.html 访问这个代理,vnc.html 和 vnc_auto.html 可以当作我们的范例程序参考。集成 noVNC 到自己的程序也没啥难度,按照官方文档修改相应参数就可以了,特别注意 INCLUDE_URI 这个变量。
如果想深入了解 OpenNebula 和 noVNC 请继续 ……
深入
如果给每个运行的 VNC 服务器开一个代理(和端口)是不是很繁琐?如果有成百上千个虚拟机呢?这么多虚拟机这么多端口怎么编程实现一一对应呢,是不是很麻烦?难道这么点东西还要个数据库来记录这些对应关系吗?我们来看一下 OpenNebula 是怎么实现 noVNC 集成的。
首先 OpenNebula 使用 websocketproxy.py 带 –target-config 参数的办法启动了代理,所有代理都在一个端口(29876)下,并会在指定的目录下(/var/lib/one/sunstone_vnc_tokens)生成一个对应的文件(one-96),打开这个文件就会看到前面的一串代码和后面的 VNC 服务(主机名:端口)对应起来。这样一个(启动了 VNC 服务的)虚拟机就对应在 sunstone_vnc_tokens 这个目录生成一个文件,文件内容能识别这个代理对应到哪个主机上的 VNC 服务。
# ps aux | grep websockify oneadmin 13661 0.0 0.2 197576 8388 ? S Jul04 0:07 python /usr/share/one/websockify/websocketproxy.py --target-config=/var/lib/one/sunstone_vnc_tokens 29876 # cat /var/lib/one/sunstone_vnc_tokens/one-96 cirjhccnthfinxpdlig: cloud32:5900
修改 noVNC/vnc_auto.html 文件的 host, port, path 部分,注意 path 是带 token 的,token 的参数要和上面的那串奇怪的代码一致:
... host = "192.168.2.20"; port = "29876"; ... path = "websockify/?token=cirjhccnthfinxpdlig"; ...
我们编程时只要改变上面的 token 参数就可以切换连接到不同的虚拟机 VNC,这样编程就方便多了。这个是我们利用 vnc_auto.html 修改过后的 VNC 连接界面(为了配合博客美观,截图有意缩小了):
如果对我们的控制面板感兴趣的话,可以看看截图,只完成了最最基本的几个功能,算作工作时间外的 side project,还在不紧张的开发中,开发工具是 Python/Flask/Bootstrap/MongoDB.