use-xterm-js-attach-to-docker-container
使用 xterm.js
“attach” 到 docker 的容器。
xterm.js
xterm.js
是一个前端组件,可以在中浏览器提供功能齐全的“终端”。只要,使用相关插件和提供相关功能的后端模块,就可以使用 xterm.js
在 web 中接入到 linux,除此,还能够接入到 docker 的容器。
xterm.js 已经“自带”了相关的后端和插件,如 Terminado
,如果需要也可以自己开发一个。
xterm.js 插件
- attach:用于 attach 到 docker 容器
- fit:自适应,指终端的窗口自适应,内容自动调整
- fullscreen:全屏
- terminado:用于和 xterm.js 的后端 Terminado 一起使用
使用 xterm.js 接入 linux
xterm.js 官网给了两个使用 Terminado 的例子,主要的区别是关于 xterm.js 的引用方式,这部分可以使用传统的方式直接引用 xterm.js 的 js 文件,也可以使用 ES6 的语法,引用相关模块,再“编译”。实际上 xterm.js 首推的是使用 ES6 的语法,不过这个例子我是直接引用预先“编译”好的 js 文件。
步骤
首先新建一个项目,下载、安装 xterm.js 和 Terminado。
1 | npm install --save xterm |
然后将 xterm.js 预先“编译”好的目标文件 ./node_modules/xterm/dist/
复制到项目 root 目录。
接着在项目 root 目录下添加一个后端文件 app.py
和一个前端文件 index.html
。
app.py
1 | #!/bin/usr/python3 |
index.html
1 |
|
测试
最后运行 app.py
。
▲ xterm.js 接入 linux 效果
项目的关键文件为 app.py
、index.html
及已经预先“编译”好的 xterm.js 目标 js 文件 dist/
使用 xterm.js attach 到 docker 容器
这部分使用 ES6 的方式引用 xterm.js,实际尝试过直接引用预先“编译”好的 js 文件,不过并没能成功,而官网也没“传统”引用方法的示例(这部分),所以还是直接选择“避坑”吧…
步骤
同样的新建一个项目,因为浏览器目前对 ES6 并不能 100% 支持,所以需要下载 webpack
、webpack-cli
、webpack-dev-server
,用于打包(编译)、调试 js。
1 | npm install --save-dev webpack webpack-cli webpack-dev-server |
接着下载 xterm.js。
1 | npm install --save xterm |
▲ 项目包含的包(package.json)
配置 package.json 和 webpack
package.json
配置 npm 脚本,修改根目录下的 package.json
,在 scripts
添加如下内容。
1 | { |
webpack.config.js
配置 webpack,在项目根目录下修改 webpack.config.js 文件。
1 | path = require('path'); |
注意:
output
里的path
为打包后的目标文件的路径,devServer
里的contentBase
为 webpack-dev-Server 指定的 web root 目录,这两个需要一样,不然“热更新”可能无效。
开发环境配置好后,就可以进入主题了。
根据前面 webpack.config.js
的配置,在项目根目录下新建入口文件 ./src/index.js
。
./src/index.js
1 | import {Terminal} from 'xterm'; |
ws 的 URL,实际是 docker engine 的 API,需要注意的是,需要将 stream
设置为 true
,不然即使连接上,也是无法传递数据的。
▲ docker websocket API
接着在项目 root 目录下新建 index.html。
index.html
1 |
|
到这里,所有的关键代码已经准备好了。
▲ 项目目录结构
测试
首先运行一个容器。
1 | docker run --name test -itd ubuntu:latest bash |
在项目 root 目录执行 npm run dev
,进行调试。
1 | npm run dev |
▲ xterm.js 接入 docker 容器效果
关于 xterm.js attach 到容器
docker engine 的 API 里面提供了两个 attach 到容器的方法。一个是和其他 API 一样使用 HTTP 协议的 attach,另一个为使用 websocket 协议的 attach。
在上面的说明(docker api的截图)中可以看到,docker engine 的 API 里面并没有对 websocket 有过多的解释。实际上,websocket 协议的 attach 和 HTTP 协议的 attche在“原理”上是一样的,只是他们的数据的传输方式不一样。
docker attach
▲ docker attach 的解释
实际是 docker attach 是 “attach” 到容器创建时的 ENTRYPOINT/CMD
命令的进程(默认指PID 1进程)。如果在容器创建时通过 -i
让容器保持打开 stdin
,“attach” 到容器后将可以与容器进行“交互”(如果条件合适)。
关于 -i
Keep STDIN open even if not attached.
-i
有两个作用;一、是会让容器保持stdin开放,二是、同时也会 attach 到容器的 stdin(即使通过 -a
指定 attach 到 stdxx)。
注:
-t
是给容器分配一个虚拟终端,也是关键。
docker create 或 exec 指定的 commond 会通过 stdin (这里应该是 API -> docker engine -> container,不过我简略了)在容器内执行,执行这“一次”结束后容器,将会关闭“此次”的 stdin;如果是使用 -i
,将会保持stdin打开;要是commond进程可以交互,用户则可以输入命令,命令将继续通过开放stdin在容器内执行。
如上所述,attach 最终能不能交互还得看ENTRYPOINT/CMD
命令的进程自身有没有“交互”的功能,比如可以交互的有 bash
、top
,不能交互的有 ls
等。
xterm.js attach 的局限
到这里可以得出结论,xterm.js attach 到容器,最终能不能进行交互,和容器的 ENTRYPOINT/CMD
的命令有很大的关系。如果在创建容器时没指定 -it
或者 ENTRYPOINT/CMD
不是 bash
之类的可交互进程,xterm.js 虽然可以连接到容器,但都不可以与容器进行交互的。
而实际情况是,绝大多数的容器事务,这两个条件都没有。
xterm.js 连接到容器的解决方案
使用 exec
。
参考
- Blog Link: https://unihon.github.io/2019-05/use-xterm-js-attach-to-docker-container/
- Copyright Declaration: The author owns the copyright. Please indicate the source reproduced!