开源项目 QEMU、KVM、libvirt 实现了建立虚拟机,启动虚拟机,监控虚拟机。咱们解决了从无到有的问题,这时就该考虑从有到优了。尽管咱们能使用 SSH 的方式来登陆使用虚拟机,但这种方式从感受欠缺点什么,用户每每会更喜欢绚丽多彩的东西。html
事实上 VNC 的客户端不少,诸如 VNC Viewer,TightVNC,RealVNC 等。然而咱们须要的是 web 版的 VNC,天然而然我选择了 noVNC。前端
noVNC 是一个能够运行在众多浏览器的 HTML5 VNC 客户端,包括手机浏览器(iOS 和 Android)。java
诸如 Ganeti Web Manager,OpenStack,OpenNebula,LibVNCServer 和 ThinLinc 等众多厂商、项目和产品整合了 noVNC。python
除非你使用的 VNC Server 支持 WebSockets 链接(好比 x11vnc/libvncserver、QEMU 或者 MobileVNC),不然你须要使用一个 WebSockets 和 TCP socket 之间相互转换的代理。git
幸运的是 noVNC 提供了一个代理器 websockify。github
尽管官方说 QEMU 支持 WebSockets 链接,但我仍然不知道如何在不使用 websockify 的状况下链接到 QEMU,若是有知道的朋友,分享出来吧。web
物理机系统版本:Windows7 64 位docker
宿主机:VMware 12.1.0
宿主机系统版本:Ubuntu 16.04 64 位编程
客户机(虚拟机):QEMU 2.5.0 libvirt 1.3.1
客户机(虚拟机)系统版本:Deepin 15.4 64 位api
一眼看去,可能关系很复杂,其实很简单,由于笔者比较穷,只有一台物理台式机,宿主机是在该物理机上经过 VMware 虚拟出来,而客户机(虚拟机)是在宿主机上经过 QEMU、KVM 虚拟出来的。
宿主机有两台,分别命名为 Node1 和 Node2,这两台宿主机的系统环境彻底一致。Node1 的 IP 为:192.168.10.231,Node2 的 IP 为:192.168.10.230。客户机(虚拟机)有一台,名为 Guest1,位于宿主机 Node1,也就是 VNC Server 位于 Node1。要用 noVNC 链接的远程机器就是客户机(虚拟机)Guest1,noVNC 和 websockify 位于宿主机 Node2。它们之间的关系如图所示。
因为 QEMU、KVM 自己对 VNC Server 支持很友好,所以不须要额外在宿主机 Node1 安装 tightvnc 或 x11vnc 。若是你要链接的机器没有 VNC Server,可直接安装 tightvnc 和 x11vnc 的任意一个。
sudo gedit /etc/libvirt/qemu.conf
打开后有以下文件内容(仅截取部分)展现。
# Master configuration file for the QEMU driver. # All settings described here are optional - if omitted, sensible # defaults are used. # VNC is configured to listen on 127.0.0.1 by default. # To make it listen on all public interfaces, uncomment # this next option. # # NB, strong recommendation to enable TLS + x509 certificate # verification when allowing public access # # vnc_listen = "0.0.0.0" # Enable this option to have VNC served over an automatically created # unix socket. This prevents unprivileged access from users on the # host machine, though most VNC clients do not support it. # # This will only be enabled for VNC configurations that do not have # a hardcoded 'listen' or 'socket' value. This setting takes preference # over vnc_listen. # #vnc_auto_unix_socket = 1 # Enable use of TLS encryption on the VNC server. This requires # a VNC client which supports the VeNCrypt protocol extension. # Examples include vinagre, virt-viewer, virt-manager and vencrypt # itself. UltraVNC, RealVNC, TightVNC do not support this # # It is necessary to setup CA and issue a server certificate # before enabling this. # #vnc_tls = 1 ......
将 vnc_listen = “0.0.0.0” 解禁,如图所示。
默认状况下 VNC 监听 127.0.0.1,修改成 0.0.0.0 后适应性更高,若是你使用 libvirt 建立虚拟机,那么虚拟机 xml 配置文件能够向下面这样添加一个 graphics。
<graphics type='vnc' autoport='yes' keymap='en-us' listen='0.0.0.0'/> <!--VNC配置,autoport="yes"表示自动分配VNC端口,推荐使用,listen="0.0.0.0"表示监听全部IP-->
得到客户机(虚拟机)Guest1 的 port(端口号),有两种方式得到,可经过调用 libvirt Java api 得到客户机(虚拟机)Guest1 的 xml 配置描述文件,而后从中取出 port,还可经过 virsh 控制台命令得到端口号,命令以下。
sudo virsh vncdisplay kvmdemo
kvmdemo 是客户机(虚拟机)Guest1 的名称,获得的结果如图所示。
自动分配的 VNC 端口(自增)默认从 5900 开始,所以 kvmdemo 的 port 是 5900。
首先下载 noVNC,可经过 git 下载,也可到官网下载压缩包。
按照前面的拓扑关系,咱们将 noVNC 下载到宿主机 Node2。
sudo git clone https://github.com/novnc/noVNC.git
下载完毕后,进入 noVNC 文件夹,执行以下命令。
sudo ./utils/launch.sh --vnc 192.168.10.231:5900
注意: 这里填写的是宿主机 Node1 的 ip,而不是客户机(虚拟机)Guest1 的 ip,VNC Server 经过端口映射的方式找到位于宿主机上的客户机(虚拟机)。
若是不指定端口,noVNC 默认的访问端口是 6080。执行过程当中,noVNC 会去 GitHub 下载 websockify,若是以为下载太慢,可先将 websockify 下载下来后,解压到 utils 文件夹下。
如此,一个 noVNC 就启动起来了。
oh,it’s work.
如今你能够在浏览器输入:
http://192.168.10.230:6080/vnc.html?host=192.168.10.230&port=6080
就能够访问到客户机(虚拟机)Guest1 了。
咱们来梳理一下用户发出请求到获得响应的流程:
PC Chrome(192.168.10.100) => Node1(192.168.10.230:6080) => websockify => Node2(192.168.10.231:5900) => websockify => Node1 => Chorme
PC Chrome 请求 Node1,websockify 将请求转发到指定的 Node2(192.168.10.231:5900),Node2收到请求返回 TCP socket 响应,在 Node1 websockify 代理器这里被转成 Web socket 的响应。
整个过程 websockify 代理器是关键,noVNC 能够被放在浏览器端。从流程来看 websockify 能够被部署在任何地方,下一节就将实现 websockify 与 noVNC 分离。
上一节,咱们已经经过 noVNC 连上了 KVM,然而这种链接方式并不实用。在实际应用中,不可能为每台虚拟机都架一个代理,这种方式对端口号的消耗也是巨大的,同时 noVNC 一般是集成在前端页面。那有没有可能仅开一个端口,而实现代理多台虚拟机呢,答案天然是能够。
在 websockify 项目的 Wiki 主页介绍了实现一个端口,多个代理的方法。
实现的原理就是 websocketproxy.py 这个代理从一个指定的 token 目录读取 token 文件,一个 token 文件一般对应一台客户机(虚拟机)。token文件内容形如 token1:host1:port1 ,这里的 token1 是全局惟一的一个字符串标识,host1 是客户机(虚拟机)所在的宿主机的 ip 地址,本例中就是 Node1 的 ip,而 port1 是客户机(虚拟机) VNC Server 的端口号,本例中就是 Guest1 的 VNC Server 的端口号。所以,本例中名为 generic 的客户机(虚拟机)Guest1 的 token 文件内容为:generic:192.168.10.231:5901。
注意: 一个 token 文件能够对应一台客户机(虚拟机),一个 token 文件也能够对应多台客户机(虚拟机)。为了方便编程,一般是一对一的关系。
在 Github 上 noVNC 和 websockify 原本就是独立的两个项目。
首先下载 websockify,可经过 git 下载。
按照前面的拓扑关系,咱们将 websockify 下载到宿主机 Node2。
sudo git clone https://github.com/novnc/websockify.git
下载完毕后,进入 websockify 文件夹,将上面的 generic 的 token 文件移动到 ./token/目录下,而后执行以下命令。
sudo python2.7 ./run --token-plugin TokenFile --token-source ./token/ 6080
这里的 6080 就是 websockify 代理器的端口号。
如今能够打开 noVNC 的 vnc_lite.html,并在末尾加上
?host=192.168.10.230&port=6080&path=websockify/?token=generic 就能够访问远程客户机(虚拟机)Guest1 了。
若是要链接其余客户机(虚拟机)只需往 ./token/ 目录下添加对应的 token 文件,而后改变 url 的 token 就能够经过 noVNC 访问客户机(虚拟机)。
微服务如今是一个很火的概念,提到微服务,天然少不了 docker。下面就提供一种将 websockify 去状态并容器化运行的方案。
1.编写 Dockerfile 文件
FROM python MAINTAINER kyyee "kyyee.com" RUN apt-get update -y RUN apt-get upgrade -y # Installing the fundamental package for scientific computing with Python: numpy RUN apt-get install -y python-numpy # clean the backup RUN apt-get clean # Copy the files into the container ADD ./websockify/ /websockify/ # start the java application CMD ["python2.7", "/websockify/run", "--token-plugin", "TokenFile", "--token-source", "/websockify/token/", "6080"] # usage volume # VOLUME ["/websockify/token/"]
2.生成 docker 镜像
sudo docker build -t websockify .
3.运行 docker 镜像
sudo docker run -p 6080:6080 --name websockify -it websockify -v /home/kyyee/websockify/token/:/websockify/token/
-v 为 docker 挂载命令,: 前是宿主机上的目录,: 后是 docker 容器中的目录。这里将 /websockify/token/ 目录挂载到宿主机上的 /home/kyyee/websockify/token/ 目录,在 /home/kyyee/websockify/token/ 目录操做与在 /websockify/token/ 目录操做没有区别。
某些状况下,你可能连不上 VNC Server,如图所示。
这个时候请查看启动 websockify 的控制台,若是是 handler exception: [Errno 111] Connection refused,一般是因为远端要链接的宿主机 ip 或映射 port 填写错误,或者你远端要链接的客户机(虚拟机)压根没开机。若是没有错误提示,但仍然没法链接,那么多是远端要链接的客户机(虚拟机)在 virt-manager 或者其余工具中已经打开。
未完待续,后续将讲解 noVNC 加密传输。