開源項目 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 加密傳輸。