开源项目 QEMU、KVM、libvirt 实现了创建虚拟机,启动虚拟机,监控虚拟机。我们解决了从无到有的问题,这时就该考虑从有到优了。尽管我们能使用 SSH 的方式来登录使用虚拟机,但这种方式从感觉欠缺点什么,用户往往会更喜欢绚丽多彩的东西。

事实上 VNC 的客户端很多,诸如 VNC Viewer,TightVNC,RealVNC 等。然而我们需要的是 web 版的 VNC,自然而然我选择了 noVNC。

noVNC:HTML5 技术的 VNC 客户端

noVNC 是一个可以运行在众多浏览器的 HTML5 VNC 客户端,包括手机浏览器(iOS 和 Android)。

诸如 Ganeti Web ManagerOpenStackOpenNebulaLibVNCServer 和 ThinLinc 等众多厂商、项目和产品整合了 noVNC。

VNC Server

除非你使用的 VNC Server 支持 WebSockets 连接(比如 x11vnc/libvncserverQEMU 或者 MobileVNC),否则你需要使用一个 WebSockets 和 TCP socket 之间相互转换的代理。

幸运的是 noVNC 提供了一个代理器 websockify

尽管官方说 QEMU 支持 WebSockets 连接,但我仍然不知道如何在不使用 websockify 的情况下连接到 QEMU,如果有知道的朋友,分享出来吧。

Linux 系统环境

物理机系统版本:Windows7 64 位

宿主机:VMware 12.1.0  
宿主机系统版本:Ubuntu 16.04 64 位

客户机(虚拟机):QEMU 2.5.0 libvirt 1.3.1 
客户机(虚拟机)系统版本:Deepin 15.4 64 位

一眼看去,可能关系很复杂,其实很简单,因为笔者比较穷,只有一台物理台式机,宿主机是在该物理机上通过 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 的任意一个。

准备工作

修改 /etc/libvirt/qemu.conf 配置文件。

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 的端口号

获得客户机(虚拟机)Guest1 的 port(端口号),有两种方式获得,可通过调用 libvirt Java api 获得客户机(虚拟机)Guest1 的 xml 配置描述文件,然后从中取出 port,还可通过 virsh 控制台命令获得端口号,命令如下。

sudo virsh vncdisplay kvmdemo

kvmdemo 是客户机(虚拟机)Guest1 的名称,得到的结果如图所示。

自动分配的 VNC 端口(自增)默认从 5900 开始,因此 kvmdemo 的 port 是 5900。

noVNC 快速开始

首先下载 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 进阶,独立 websockify 实现一个端口,多个代理

上一节,我们已经通过 noVNC 连上了 KVM,然而这种连接方式并不实用。在实际应用中,不可能为每台虚拟机都架一个代理,这种方式对端口号的消耗也是巨大的,同时 noVNC 通常是集成在前端页面。那有没有可能仅开一个端口,而实现代理多台虚拟机呢,答案自然是可以。

一个端口,多个代理原理,引入 token 文件

在 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 文件也可以对应多台客户机(虚拟机)。为了方便编程,通常是一对一的关系。

分离 noVNC 与 websockify

在 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 访问客户机(虚拟机)。

容器化 websockify

微服务现在是一个很火的概念,提到微服务,自然少不了 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 加密传输。

通过noVNC和websockify连接到QEMU/KVM 转的更多相关文章

  1. 理解 QEMU/KVM 和 Ceph(2):QEMU 的 RBD 块驱动(block driver)

    本系列文章会总结 QEMU/KVM 和 Ceph 之间的整合: (1)QEMU-KVM 和 Ceph RBD 的 缓存机制总结 (2)QEMU 的 RBD 块驱动(block driver) (3)存 ...

  2. KVM 介绍(8):使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机 [Nova Libvirt QEMU/KVM Live Migration]

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  3. KVM 介绍(6):Nova 通过 libvirt 管理 QEMU/KVM 虚机 [Nova Libvirt QEMU/KVM Domain]

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  4. 干货分享: 长达250页的Libvirt Qemu KVM的ppt,不实验无真相

    下载地址:Libvirt Qemu KVM 教程大全 http://files.cnblogs.com/popsuper1982/LibvirtQemuKVM.pptx 1. 概论 1.1 虚拟化的基 ...

  5. KVM(八)使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机

    1. QEMU/KVM 迁移的概念 迁移(migration)包括系统整体的迁移和某个工作负载的迁移.系统整理迁移,是将系统上所有软件包括操作系统完全复制到另一个物理机硬件机器上.虚拟化环境中的迁移, ...

  6. KVM(六)Nova 通过 libvirt 管理 QEMU/KVM 虚机

    1. Libvirt 在 OpenStack 架构中的位置 在 Nova Compute 节点上运行的 nova-compute 服务调用 Hypervisor API 去管理运行在该 Hypervi ...

  7. 理解 QEMU/KVM 和 Ceph(3):存储卷挂接和设备名称

    本系列文章会总结 QEMU/KVM 和 Ceph 之间的整合: (1)QEMU-KVM 和 Ceph RBD 的 缓存机制总结 (2)QEMU 的 RBD 块驱动(block driver) (3)存 ...

  8. 理解 Linux 网络栈(3):QEMU/KVM + VxLAN 环境下的 Segmentation Offloading 技术(发送端)

    本系列文章总结 Linux 网络栈,包括: (1)Linux 网络协议栈总结 (2)非虚拟化Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO (3)QEMU/KVM + Vx ...

  9. 理解 QEMU/KVM 和 Ceph(1):QEMU-KVM 和 Ceph RBD 的 缓存机制总结

    本系列文章会总结 QEMU/KVM 和 Ceph 之间的整合: (1)QEMU-KVM 和 Ceph RBD 的 缓存机制总结 (2)QEMU 的 RBD 块驱动(block driver) (3)存 ...

随机推荐

  1. 本地spark报:java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.createFileWithMode0(Ljava/lang/String;JJJI)Ljava/io/FileDescriptor;

    我是在运行rdd.saveAsTextFile(fileName)的时候报的错,找了很多说法……最终是跑到hadoop/bin文件夹下删除了hadoop.dll后成功.之前某些说法甚至和这个解决方法自 ...

  2. 扩展ACL

  3. SignalR简单实用_转自:https://www.cnblogs.com/humble/p/3851205.html

    一.指定通信方式 建立一个通讯方式需要一定的时间和客户机/服务器资源.如果客户机的功能是已知的,那么通信方式在客户端连接开始的时候就可以指定.下面的代码片段演示了使用AJAX长轮询方式来启动一个连接, ...

  4. java 面试题目(java高级架构)

    题目信息 java基础: 1. Java 基础 JDK 和 JRE 有什么区别?   Java中JDK和JRE的区别是什么?它们的作用分别是什么? == 和 equals 的区别是什么? 两个对象的 ...

  5. 分布式缓存Redis集群搭建

    redis安装 1.下载tar包至/opt/redis 2.解压tar包 tar -xvf redis-4.0.14.tar.gz 3. cd redis-4.0.14 make一下. 单节点的red ...

  6. Assignment3:白盒测试以及测试框架简介

    一. 白盒测试简介       白盒测试又称结构测试.透明盒测试.逻辑驱动测试或基于代码的测试.白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,你清楚盒子内部的东西以及 ...

  7. 关于 array of const

    之前应该参考一下: 关于开放数组参数 //这是在 System 单元定义的一组标识数据类型的常量: vtInteger    = ; vtBoolean    = ; vtChar      = ; ...

  8. 如何选题?| 什么样的科学问题 | 研究项目才是有意义的?| scientific method

    搞科研,尤其是生命科学,经常会觉得自己做的东西是坨屎,没有任何意义. 在硕博的时候这种感觉会非常强烈,一个是自己思考能力不足:二是你的项目不是你设计的,不懂个中缘由,只执行的话就会很无聊,找不到意义感 ...

  9. HttpWebRequest使用时发生阻塞的解决办法

    HttpWebRequest使用如下: 第一种:使用Using 释放资源 /// <summary> /// Http Get请求返回数据 /// </summary> /// ...

  10. 2019年ArcGIS规划专业专项培训(四天)

    2019年ArcGIS规划专业专项培训(四天) 商务合作,科技咨询,版权转让:向日葵,135-4855__4328,xiexiaokui#qq.com   第一天:GIS入门 第一章 GIS概述及其应 ...