

Kubernetes WebSSH终端窗口自适应Resize
source link: https://blog.ops-coffee.cn/s/4je9hivfg4gmbia4kkq7wg
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Kubernetes WebSSH终端窗口自适应Resize
追求完美不服输的我,一直在与各种问题斗争的路上痛并快乐着
上一篇文章Django实现WebSSH操作Kubernetes Pod最后留了个问题没有解决,那就是terminal内容窗口的大小没有办法调整,这会导致的一个问题就是浏览器上可显示内容的区域太小,当查看/编辑文件时非常不便,就像下边这样,红色可视区域并没有被用到
RESIZE_CHANNEL
前文说到kubectl exec
有两个参数COLUMNS
和LINES
可以调整tty内容窗口的大小,命令如下:
kubectl exec -i -t $1 env COLUMNS=$COLUMNS LINES=$LINES bash
这实际上就是将COLUMNS
和LINES
两个环境变量传递到了容器内,由于Kubernetes stream底层也是通过kubernetes exec
实现的,所以我们在启动容器时也将这两个变量传递进去就可以了,就像这样
exec_command = [
"/bin/sh",
"-c",
'export LINES=20; export COLUMNS=100; '
'TERM=xterm-256color; export TERM; [ -x /bin/bash ] '
'&& ([ -x /usr/bin/script ] '
'&& /usr/bin/script -q -c "/bin/bash" /dev/null || exec /bin/bash) '
'|| exec /bin/sh']
添加了export LINES=20; export COLUMNS=100;
,可以实现改变tty的输出大小,但这有个问题就是只能在建立链接时指定一次,不能动态的更新,也就是在一次websocket会话的过程中,如果页面大小改变了,后端输出的LINES和COLUMNS是无法随着改变的
在解决问题的过程中发现官方源码中有个RESIZE_CHANNEL
的配置,同样可以控制窗口的大小,使用方法如下:
cont_stream = stream(api_instance.connect_get_namespaced_pod_exec,
name=pod_name,
namespace=self.namespace,
container=container,
command=exec_command,
stderr=True, stdin=True,
stdout=True, tty=True,
_preload_content=False
)
cont_stream.write_channel(4, json.dumps({"Height": int(rows), "Width": int(cols)}))
这样我们就可以修改stream输出的窗口大小了
xterm.js fit
一顿操作后,打开页面,咦?怎么页面不行,原来窗口的调整不仅需要调整stream输出数据的窗口大小,前端页面也要跟着一并调整
这里用到了xterm.js的另一个组件fit,fit可以调整终端大小的cols
和rows
适配父级元素
首先调整terminal块的宽度和高度为整个页面可视区域的大小,要让整个可视区域为终端窗口
document.getElementById('terminal').style.height = window.innerHeight + 'px';
然后引入fit组件,在term初始化之后执行fit
操作
<script src="/static/plugins/xterm/xterm.js"></script>
<script src="/static/plugins/xterm/addons/fit/fit.js"></script>
<script>
// 修改terminal的高度为body的高度
document.getElementById('terminal').style.height = window.innerHeight + 'px';
var term = new Terminal({cursorBlink: true});
term.open(document.getElementById('terminal'));
// xterm fullscreen config
Terminal.applyAddon(fit);
term.fit();
console.log(term.cols, term.rows);
</script>
fit之后就可以通过term.cols
和term.rows
取到xterm.js根据字体大小自动计算过的cols
和rows
的值了,然后把这两个值传递给kubernetes,kubernetes再根据这两个值输出窗口大小,这样前后端匹配就完美了
xterm.js可以通过如下的方法动态的将cols
和rows
传递给后端
term.on('resize', size => {
socket.send('resize', [size.cols, size.rows]);
})
但当窗口由大变小时,之前输出的内容会有样式错乱,我为了方便直接在WebSocket连接建立时采用url传参的方式把cols
和rows
两个值传递给后端,kubernetes根据这两个值来设置输出内容的窗口大小,这样做的缺点是不会随着前端页面的变化动态的去调整后端stream输出窗口的大小,不过问题不大,如果页面调整大小,刷新下页面重新建立连接就可以啦,具体实现如下
首先需要修改的就是WebSocket的url地址
前端增加term.cols
和term.rows
两个参数的传递
var socket = new WebSocket(
'ws://' + window.location.host + '/pod/{{ name }}/'+term.cols+'/'+term.rows);
Routing增加两个参数的解析
re_path(r'^pod/(?P<name>\w+)/(?P<cols>\d+)/(?P<rows>\d+)$', SSHConsumer),
Consumer解析URL将对应参数传递给Kubernetes stream
class SSHConsumer(WebsocketConsumer):
def connect(self):
self.name = self.scope["url_route"]["kwargs"]["name"]
self.cols = self.scope["url_route"]["kwargs"]["cols"]
self.rows = self.scope["url_route"]["kwargs"]["rows"]
# kube exec
self.stream = KubeApi().pod_exec(self.name, cols=self.cols, rows=self.rows)
kub_stream = K8SStreamThread(self, self.stream)
kub_stream.start()
self.accept()
最后Kubernetes stream接收参数并修改窗口大小
def pod_exec(self, RAND, container="", rows=24, cols=80):
api_instance = client.CoreV1Api()
exec_command = [
"/bin/sh",
"-c",
'TERM=xterm-256color; export TERM; [ -x /bin/bash ] '
'&& ([ -x /usr/bin/script ] '
'&& /usr/bin/script -q -c "/bin/bash" /dev/null || exec /bin/bash) '
'|| exec /bin/sh']
cont_stream = stream(api_instance.connect_get_namespaced_pod_exec,
name=pod_name,
namespace=self.namespace,
container=container,
command=exec_command,
stderr=True, stdin=True,
stdout=True, tty=True,
_preload_content=False
)
cont_stream.write_channel(4, json.dumps({"Height": int(rows), "Width": int(cols)}))
return cont_stream
至此,每次WebSocket连接建立,前后端就会有一样的输出窗口大小,问题解决~
能看到这里一定是真爱,关注一下吧

Recommend
-
69
新建一个django程序,本文为chain。以下仅为简单例子,实际应用可根据自己平台情况进行修改。打开首页后,需要输入1,后台去登录主机,然后返回登录结果。正常项目可以post主机和登录账户,进行权限判断,然后去后台读取账户密码,进行登录。djang后台需要安装以下...
-
201
README.md WebSSH
-
14
echarts的自适应问题(窗口自适应,侧边栏自适应,el-tab中的自适应)发布于 今天 02:40 一、echart的图表提供了一个resize函数,当resize函数被触发时,图表会进行...
-
7
堡垒机的核心武器:WebSSH录像实现 WebSSH终端录像的实现终于来了 前边写了两篇文章『Asciinema:你的所有操作都将被录制』和
-
11
堡垒机WebSSH进阶之实时监控和强制下线 这个功能我可以不用,但你不能没有 前几篇文章实现了对物理机、虚拟机以及Kubernetes中Pod的WebSSH操作,可以...
-
10
WebSSH画龙点睛之lrzsz上传下载文件 本篇文章没有太多的源码,主要讲一下实现思路和技术原理 当使用Xshell或者SecureCRT终端工具时,我的所有文件传输工作都是通过lrzsz来完成的,主要是因为...
-
5
Django实现WebSSH操作物理机或虚拟机 我想用它替换掉xshell、crt之类的工具 WebSSH操作物理机或虚拟机 Django实现WebSSH操作Kub...
-
5
Django实现WebSSH操作Kubernetes Pod 优秀的系统都是根据反馈逐渐完善出来的 上篇文章介绍了我们为了应对安全和多分支频繁测试的问题而开发了一套Alodi系统,Alodi可以通过一个按钮快速构建一套测试环境,...
-
11
V2EX › 分享创造 开源 v1.1:简易探针+webssh(EasyNode)
-
5
用go+xtermjs实现的一个webssh的demo rushui · 大约10小时之前 · 178 次点...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK