一. 前言

在微服务大行其道的今天,容器恰巧又是微服务的主要载体,所以我们操作的对象也由最开始的「物理机」到「虚拟机」再到今天的「容器」。由于这些载体的变更,我们的使用方式也需要随之发生一些改变。比如一个最常用的登入操作,「虚拟机」下我们可能通过 ssh 的方式 ,但如果是容器呢?ssh 的方式就需要在每个容器中都运行一个 sshd 进程,这种做法可行但略显繁琐,也不太符合一个容器只运行一个进程的思想。
那么有没有一个即方便快捷又安全的登入方式呢?
有,通过 Web Terminal 的方式,通过 Web 的方式即可以避免对客户端的依赖又能够实现用户权限控制。目前,有很多开源的 Web Terminal 的项目,基本上都是通过 ssh 代理的方式调用并返回一个 shell 的虚拟终端(pty)。
index1.png

二. 实现容器的 Web Terminal

2.1 架构图

index2.png
JS虽然可以利用方法来调用命令行等工具,但本身并没有操纵操作系统的能力。这时,Web Terminal在JS中能够实现的只有虚拟终端的部分。JS通过WebSocket与d-terminal相互通信,将d-terminal与数据库交互、与服务器交互的内容经过处理后,展示在界面中。

2.2 前端 Web Termianl 页面

Linux 终端返回的内容会带很多特殊的字符,比如我输入一个 ls 指令,终端返回的结果如下:

  1. 'l'
  2. 's'
  3. '\r\n'
  4. '\x1b[0;0mRUNNING_PID\x1b[0m \x1b[1;34mbin\x1b[0m
  5. \x1b[1;34mconf\x1b[0m \x1b[1;34mlib\x1b[0m\r\nbash-4.3# '

将这些结果渲染在页面显然是不可以的,这时候就必须要借助一些工具,例如模拟 Terminal 的 JavaScript库 xterm.js、jquery.terminal、ioterm、terminal.js等等。虽然看起来种类很多,但是他们的本质趋于相同,
利用canvas或者各种标签来模拟终端的样式。通过WebSocket与后端通信,把得到的信息展示在界面中。

2.3 d-terminal

d-terminal 是这个系统的核心,它分成两个部分:

一部分用于处理用户端的输入和输出,以及存储和展示后端 Docker Dameon 主机的 IP 和 container_id。因为像 top 这样的监控命令需要服务端定时推送数据给客户端,所以使用了 WebSocket 协议以支持服务端推送。

另一部分用于调用 Docker Daemon 返回虚拟终端。对于终端来说,通常是你输入一个字符就会立马返回,直到你输入一个 “归位键” 终端才会把你输入的字符拼接成一个字符串并发送给 shell 解释器,并将 shell 解释器的结果返回。为了提升使用流畅性,新启用了一个线程去调用 Docker Daemon API,当然也可以使用像 epoll 这样的多路复用技术来实现。
index3.png

三. 总结

上述仅仅是描述了一个最基本的实现逻辑,具体实现还需要自行编写。