• 通过noVNC和websockify连接到QEMU/KVM 转


    开源项目 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。它们之间的关系如图所示。

    图1

     

    由于 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” 解禁,如图所示。

    图2

    默认情况下 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 的名称,得到的结果如图所示。

    图3

    自动分配的 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 就启动起来了。

    图4

    oh,it’s work.

    现在你可以在浏览器输入:

    http://192.168.10.230:6080/vnc.html?host=192.168.10.230&port=6080

    就可以访问到客户机(虚拟机)Guest1 了。

    图5

    我们来梳理一下用户发出请求到得到响应的流程:

    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 代理器的端口号。

    图6

    现在可以打开 noVNC 的 vnc_lite.html,并在末尾加上 
    ?host=192.168.10.230&port=6080&path=websockify/?token=generic 就可以访问远程客户机(虚拟机)Guest1 了。

    图7

    如果要连接其他客户机(虚拟机)只需往 ./token/ 目录下添加对应的 token 文件,然后改变 url 的 token 就可以通过 noVNC 访问客户机(虚拟机)。

    图8

    容器化 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,如图所示。

    图9

    这个时候请查看启动 websockify 的控制台,如果是 handler exception: [Errno 111] Connection refused,通常是由于远端要连接的宿主机 ip 或映射 port 填写错误,或者你远端要连接的客户机(虚拟机)压根没开机。如果没有错误提示,但仍然无法连接,那么可能是远端要连接的客户机(虚拟机)在 virt-manager 或者其他工具中已经打开。

    未完待续,后续将讲解 noVNC 加密传输。

  • 相关阅读:
    git 删除所有提交下的某个文件
    Sublime Text 中文
    git 常用文件目录介绍
    设计模式之——单例模式
    Mysql系统知识梳理
    Spring系列之——使用了哪些设计模式
    JAVA基础之——三大特征、接口和抽象类区别、重载和重写区别、==和equals区别、JAVA自动装箱和拆箱
    集合系列问题
    做一个优秀的职场人才
    Spring系列之——Spring事务以及两大核心IOC和AOP
  • 原文地址:https://www.cnblogs.com/zqyanywn/p/11417028.html
Copyright © 2020-2023  润新知