关于通过web页面实现类似SSH客户端工具的技术方案

前言


      前端一段时间被"容器云"团队抓了"壮丁",去支援了一段时间,恰好有一个需求是通过web页面实现链接容器的命令行工具。这里分享一下相关的实现方案。有兴趣的可以了解一下。

可以参考的三种方案:
  1. noVNC+vncserver
  2. Xtermjs+SSH2+nodejs
  3. nodejs+tty.js

      前面提到容器,了解的朋友请忽略,不了解的朋友就把它当做一台虚拟服务器把,虽然他不是。下面的案例也是通过web页面实现和服务器的连接,并不是和容器的连接,但是原理是一样的。

优缺点分析:
  1. noVNC+vncserver方案相对来说后端服务实现较轻松,但前端界面国语简陋,需要弄清楚原来前端业务的逻辑和代码结构,重够前端。另一方面由于整个noVNC是开源的,安全以及后期维护问题需要进行相关评估和考量。
  2. Xtermjs+SSH2+nodejs方案无论前端还是后端都需要重新开发,工作量会比较大。后期的维护性和扩展较容易。虽然Xtermjs和SSH2都是第三方模块,但是他们都只是提供功能的简单封装,安全是可控的。
  3. nodejs+tty.js 没跑起来,安装tty.js报错,网上说nodejs新版本已经不支持该模块的部分方法了。所以…

具体方案

一.noVNC+vncserver


      先走一下程序百度科普一下什么是VNC技术,VNC(Virtual Network Computing)网络遥控技术是指由一部计算机(主控端)去控制另一部计算机(被控端),而且当主控端在控制端时,就如同用户亲自坐在被控端前操作一样,可以执行被控端的应用程序,及使用被控端的系统资源。

      这种方案相对简单,我们大部分工作是集成,因为作者已经将前端,后端服务都写好了,我们只需要部署上去就能正常的运行起来。当然,只是运行起来,他运行起来是长这样的:
关于通过web页面实现类似SSH客户端工具的技术方案_第1张图片
正常情况下这界面是不满足我们需要的,我们需要根据自己的交互稿去修改源文件的前端代码,当然后端也可能需要一定的定制,比如和数据库进行交互…。但是它不用服务端去解析命令输入和目标服务器的连接,这看起来前端的工作好像要大一点了。下面这张图是百度云的webSSH窗口 ,他就是基于noVNC实现的,在这个基础上做了一定的定制。
关于通过web页面实现类似SSH客户端工具的技术方案_第2张图片
看起来好像有点简陋,但是人家是一个有内涵的。外观简洁,功能强大,在SSH客户端上能实现的他基本上都能实现,所以有时候我们还是不能只看颜值,内在美也不能忽略。

整个业务流程:
关于通过web页面实现类似SSH客户端工具的技术方案_第3张图片

实现步骤:

  1. 安装vncserver
  2. 安装noVNC
  3. 实现远程服务器连接的任意切换
  4. 实现免密登录
vncserver安装

      vncserver是部署在远程服务器上的服务,通过接收和处理noVNC传输过来的命令,然后实现对目标服务器的操作,然后再将操作结果和过程通过双方建立的tcp通道返回给noVNC,noVNC服务再通过websocket推送给前端页面,前端页面服务显示信息和收集下发命令。下面是一张草图,供参考。
       首先需要操作的服务器上装上vncserver服务,他才是在宿主机上接受命令,然后向Linux操作系统下发命令的,而noVNC只是一个中间代理人的角色,这个后面安装noVNC再讲。

sudo apt-get install vnc4server

安装成功后执行vnc4server,启动服务

:~$ vncserver         //启动vncserver服务

You will require a password to access your desktops.

Password:
Verify:
xauth:  file /home/xy/.Xauthority does not exist

New 'tnode07:1 (nsr)' desktop is tnode07:1

Creating default startup script /home/xy/.vnc/xstartup
Starting applications specified in /home/xy/.vnc/xstartup

命令查看vncserver状态

ps axu|grep vnc4

      安装好vncServer后,再来安装noVNC,因为我这里只有一台服务器,所以我server和client的服务是部署再一台机器上的,通常情况下这两个是部署在不同服务上的,这里提一下。

noVNC安装

      noVNC提供浏览器访问的web服务,访问目标服务器vncserver提供的vnc服务
noVNC和vncserver建立TCP连接,浏览器端和noVNC服务之间通过websocket连接,前端通过Canvas录入和接收显示命令和信息。浏览器其实就相当于一个客户端,类似win下面的vncviewer。

 git clone https://github.com/kanaka/noVNC

这里我建议在线通过git 将远程仓库克隆下来,因为再克隆的过程中还会下载websocket相关的包,如果通过离线的方式,这些包还需要手动去安装。
下载成功后执行启动服务命令

 ./noVNC/utils/.launch.sh --vnc localhost:5900
 Warning: could not find self.pem  
Starting webserver and WebSockets proxy on port 6080  
WARNING: no 'numpy' module, HyBi protocol will be slower  
WebSocket server settings:  
  - Listen on :6080  
  - Flash security policy server  
  - Web server. Web root: /home/xiaofei/work/noVNC  
  - No SSL/TLS support (no cert file)  
  - proxying from :6080 to 192.168.110.179:5901  

因为我noVNC和vncServer是安装一台机器上的,所以就是是localhost,如果不是一台机器,就是vncServer所在服务器的地址。5900是vncServer开放的访问端口

这样就安装成功了,然后通过浏览器访问一下,看看是长什么样子。
关于通过web页面实现类似SSH客户端工具的技术方案_第4张图片
点击链接,然后输入远程服务器的登陆密码
关于通过web页面实现类似SSH客户端工具的技术方案_第5张图片
看起来确实有点抽象,比上面百度云那个看起来抽象多了,这里就是我们前端发挥作用的时候了,我们可以将noVNC的前端源码按照我们的UI输出进行修改,达到我们想要的效果。
到这一步,基本功能就实现了。

实现切换到任意一台远程服务器

在做管理平台时,需求是需要通过noVNC提供的服务来访问任意我们有权访问的远程服务器,但是我们可以发现,前面我们在启动noVNC的时候,我们是通过

 ./noVNC/utils/.launch.sh --vnc localhost:5900

的形式来启动的,这样是指定了远程服务的ip和端口,那么如何实现noVNC和远程服务器链接的任意切换呢?
答案就是通过配置文件来实现多台服务器的管理,然后通过在访问时带上为每台远程服务的唯一命名,来实现链接不同的远程服务。具体实现如下:

  1. 在noVNC目录下创建vnc_tokens文件
 vi ./noVNC/vnc_token

配置格式为hostName:ip:port,hostName,为远程服务器的名称,配置好后执行

root@instance-364se3r0:/soft/vnc/noVNC/utils/websockify# ./run --web /soft/vnc/noVNC --target-config /soft/vnc/noVNC/vnc_token 6080
/soft/vnc/noVNC/utils/websockify/websockify/websocket.py:30: UserWarning: no 'numpy' module, HyBi protocol will be slower
  warnings.warn("no 'numpy' module, HyBi protocol will be slower")
WebSocket server settings:
  - Listen on :6080
  - Web server. Web root: /soft/vnc/noVNC
  - No SSL/TLS support (no cert file)
  - proxying from :6080 to targets generated by TokenFile

然后我们访问vnc.html页面
关于通过web页面实现类似SSH客户端工具的技术方案_第6张图片
在上面红框处填写填写需要访问的远程服务器名称,noVNC服务端通过参数token来区分需要链接那台远程服务

免密登陆

正常情况下,我们的需求是,进入云服务管理平台后,打开对应的云服务器或容器服务列表,这时会有一个入口用来弹出命令行面板,用来操作远程服务器。但这里是不需要再次进行登陆的,我们再登陆管理平台后,相当于已经一键登陆了。显然上面的noVNC还不满足我们的要求,我们需要实现免密码登陆。如何实现呢?这里讲一下大致流程,应为这里不只涉及到前端,还需要后端服务做一些工作。

  1. 我们在申请云服务器的时候会要求输入密码,这里需要将服务的密码和我们的平台用户关联并保存在数据库。
  2. 利用vnc.html和平台同源,使用cookie实现一键登录,当进入vnc.html页面时,页面就发起websocket链接,服务端判断携带cookie是否有效,做相关登陆操作,然后在web端通过canvas创建命令行面板。

二. xtermjs+SSH2+nodejs


      这种方案,从大体方向来说和前面提到noVNC的方案神似,主要是在中转服务端和需要访问的目标服务端之间的传输协议不同,noVNC是使用的RFB协议传输,而xtermjs+SSH2+nodejs是依赖ssh安全传输协议。整体交互模式和noVNC是一样的。

实现步骤:

  1. 通过任意的前端方案,实现前端界面(vue+xtermjs+socket.io-client)
  2. 通过nodejs实现中转服务(nodejs+Eggjs+redis)

      这里并没有在目标服务器上安装类似vncserver一类的服务,是因为该方案是采用的SSH协议,只要我们目标服务上部署了SSH服务就OK了,正常情况下SSHserver是服务器必备的。所以该方案就不必在实现一个类似vncServer的服务了。
下面讲讲具体实现:

前端界面实现

实现功能:

  1. 命令窗口的创建,销毁,移动,最大化
  2. 命令输入和信息回显
中转服务实现

关于通过web页面实现类似SSH客户端工具的技术方案_第7张图片
具体实现:
其实网上关于xtermjs的使用教程有很多,但是大部分只是说了一下,怎么创建显示区域,和接受输入和现实信息。和后端交互的整个流程提到的比较少,我这里结合实际功能大致提一下整个流程:

  1. 首先调用xtermjs提供方的API创建命令行窗口
  2. 建立websocket连接,实现前端后端的全双工通信
  3. 输入回显,这里其实不是监听到输入就直接显示write到窗口中,窗口中只显示websocket传来的信息,在监听到输入后,直接将输入通过websocket链接发送给后端,后端处理后再将字符回传过来,这不是吃饱没事干,在正常使用xshell或者CRT等工具时,有事也会出现输入显示延时的现象,这是因为网络传输慢或服务器负载过高导致。我们通过上面这种先传再回显的方式也可以做到这种效果。
  4. 命令响应结果回显,这里需要注意换行符号,最好由后端来处理换行等字符,前端负责显示就完了。尽量避免前端设置过多的处理逻辑,前端更多负责实现交互,这也是前端开发的一个原则"重交互,轻逻辑"。

后端实现功能:

  1. 提供REST API接口,供前端查询相关目标服务的信息,包括,ip,port…
  2. 提供websocket服务,用来连接前后端,实现数据的双向传输
  3. 提供SSH连接功能,用来在中转服务器上建立和目标服务之间的连接,数显命令的下发,和响应数据的回传
  4. 启动一个redis服务,用来实现内存共享,保存SSH连接实例,因为这里可能会同时有多个SSH实例存在,每个浏览器端对应一个实例。缓存输入,为每个连接创建一个命令字符集合,当监听到我们输入回车键时就将之前收到的字符组成命令语句,然后执行,同样这也方便我们实现上下键快速输入历史命令的功能。

      总的来说这种方式,需要对SSH工具的功能了解的比较透彻,每个功能点都需要我们用代码来实现。所以开发周期回比较长。
由于代码实现的代码量比较大,这里我就不贴代码了,贴一下我自己的一个实现webSSH仓库地址,内容目前还在进一步完善中,但是基本的流程已经完成,有需要的可以看看,欢迎大家提出意见,可以在评论中@我。

3. nodejs+tty.js

      该方案,我自己没有搭建起来,在装tty.js的时候,老是报错,最后也没装上,论坛里面看了看,说是nodejs在5.X的时候就不在支持该模块内的相关方法了,现在nodejs的版本都1x.x了,而且还在不断的更新,不能向上兼容的东西,个人觉得也没有必要去弄了。

总结:

       noVNC和xtermjs+SSH2的方案都有各自的优缺点,这个需要各自团队自己根据实际情况进行评估,像百度就是用noVNC,我们公司是用的后者,虽然后者可以高度定制化开发,但是坑比较多,我们现在都还在坑此坑次的填坑,目前已经有换成noVNC的想法了。公司后端是用的java不是nodejs,我自己个人搭建的时候后端选择的nodejs,毕竟我还是一个前端。
      有时间就多折腾一下,了解一下总是好的。 如果你读到了这里,请别介意前面文中的"通假字",谢谢。

你可能感兴趣的:(vue,nodejs,javascript)