内容简介:在微服务大行其道的今天,容器恰巧又是微服务的主要载体,所以我们操作的对象也由最开始的「物理机」到「虚拟机」再到今天的「容器」。由于这些载体的变更,我们的使用方式也需要随之发生一些改变。比如一个最常用的登入操作,「虚拟机」下我们可能通过 ssh 的方式 ,但如果是容器呢?ssh 的方式就需要在每个容器中都运行一个 sshd 进程,这种做法可行但略显繁琐,也不太符合一个容器只运行一个进程的思想。那么有没有一个即方便快捷又安全的登入方式呢?有,通过 Web Terminal 的方式,通过 Web 的方式即可以避免
一、前言
在微服务大行其道的今天,容器恰巧又是微服务的主要载体,所以我们操作的对象也由最开始的「物理机」到「虚拟机」再到今天的「容器」。由于这些载体的变更,我们的使用方式也需要随之发生一些改变。比如一个最常用的登入操作,「虚拟机」下我们可能通过 ssh 的方式 ,但如果是容器呢?ssh 的方式就需要在每个容器中都运行一个 sshd 进程,这种做法可行但略显繁琐,也不太符合一个容器只运行一个进程的思想。
那么有没有一个即方便快捷又安全的登入方式呢?
有,通过 Web Terminal 的方式,通过 Web 的方式即可以避免对客户端的依赖又能够实现用户权限控制。目前,有很多开源的 Web Terminal 的项目,基本上都是通过 ssh 代理的方式调用并返回一个 shell 的虚拟终端(pty)。
二、实现容器的 Web Terminal
2.1 架构图
2.2 前端 Web Termianl 页面
Linux 终端返回的内容会带很多特殊的字符,比如我输入一个 ls 指令,终端返回的结果如下:
\'l\' \'s\' \'\r\n\' \'\x1b[0;0mRUNNING_PID\x1b[0m \x1b[1;34mbin\x1b[
这样我们就需要自己做穷举处理了,这里推荐使用一款的模拟 Terminal 的 JavaScript 库 xterm.js。这个库已经帮我们做了这些复杂操作。
<script> var term = new Terminal(); term.open(document.getElementById(\'terminal\')); term.write(\'Hello from \x1B[1;3;31mxterm.js\x1B[0m $ \') </script>
可以看到它已经将 \x1B[1;3;31mxterm.js\x1B[0m 这些特殊字符变成了红色:
2.3 调用 Docker Daemon API 返回 Shell 虚拟终端
在平常的命令行操作下,我们经常会使用 docker exec -i -t /bin/sh 来模拟一个 Shell 的伪终端。在 Web Terminal 实现里,我们需要通过 API 调用的方式来实现同样的操作。当然,我们首先要确保 Docker Daemon 的远程调用是开启的。
先调用 execCreate 来创建一个 Exec。在调用时,需要指定Tty,AttachStdin、AttachStdout和 AttachStderr 参数均为 true,Cmd 参数为 bash,这样才能获得 bash 进程的标准输入输出和错误;
request:
POST /v1.24/containers/e90e34656806/exec HTTP/1.1 Content-Type: application/json { "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Cmd": ["sh"], "DetachKeys": "ctrl-p,ctrl-q", "Tty": true, ... }
如果调用 execCreate 成功,调用请求会返回该 Exec 的 ID,根据这个 ID 继续调用execStart 接口。在调用时,需要指定 Detach 为 False,Tty 为 True,这样才会返回一个 HTTP 的 stream:
request:
POST /v1.24/exec/e90e34656806/start HTTP/1.1 Content-Type: application/json { "Detach": false, "Tty": true }
2.4 d-terminal
d-terminal 是这个系统的核心,它分成两个部分:
一部分用于处理用户端的输入和输出,以及存储和展示后端 Docker Dameon 主机的 IP 和 container_id。因为像 top 这样的监控命令需要服务端定时推送数据给客户端,所以使用了 WebSocket 协议以支持服务端推送。
另一部分用于调用 Docker Daemon 返回虚拟终端。对于终端来说,通常是你输入一个字符就会立马返回,直到你输入一个 "归位键" 终端才会把你输入的字符拼接成一个字符串并发送给 shell 解释器,并将 shell 解释器的结果返回。为了提升使用流畅性,新启用了一个线程去调用 Docker Daemon API,当然也可以使用像 epoll 这样的多路复用技术来实现。
d-terminal 是使用 Python 实现的 Web 应用,核心代码如下:
@sockets.route(\'/echo\') def echo_socket(ws): ... # 调用 Docker API 返回一个虚拟终端 docker_daemon_sock = get_tty()._sock # 启动一个与 Docker Daemon 通讯的子线 docker_daemon_sock_thd = DockerDaemonSock(ws, docker_daemon_sock) docker_daemon_sock_thd.start() while not ws.closed: message = ws.receive() # 接收 terminal 的输入 # 将用户的输入发送那个 docker daemon docker_daemon_sock.send(bytes(message, encoding=\'utf-8\')) # 子线程 DockerDaemonSock 类 class DockerDaemonSock(threading.Thread): def __init__(self, ws, docker_daemon_sock): super(DockerDaemonSock, self).__init__() self.ws = ws self.docker_daemon_sock = docker_daemon_sock def run(self): while not self.ws.closed: try: # 接收 docker daemon 的返回 resp = self.docker_daemon_sock.recv(2048) if resp: # 将 docker daemon 的返回发送给前端 terminal self.ws.send(str(resp, encoding=\'utf-8\')) else: print("docker socket closed.") self.ws.close() except Exception as e: print("docker termial socket error: {}".format(e)) self.ws.close()
三、总结
上述仅仅是描述了一个最基本的实现,完全是为了抛砖引玉,后续可以通过在中间层添加一些扩展,比如,用户权限的分配,与自己环境中的容器编排引擎集成等,最终作为 Pass 平台的一个基础的组成部分。
最后,上述的 demo 可去 github 具体查看。效果如下:
四、参考
https://blog.csdn.net/y4x5m0nivsrjay3x92c/article/details/80617135
以上所述就是小编给大家介绍的《容器管理利器:Web Terminal 简介》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 容器监控利器 - prometheus在生产落地过程中的思考
- DevOps和微服务助攻,新一代容器PaaS平台成数字化转型利器
- JMockit:单元测试利器
- 利器+
- Go 调试利器:delve
- go调试利器-delve
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。