使用 client-go 实现 k8s webshell
原文地址:http://maoqide.live/post/cloud/kubernetes-webshell/
通过 client-go 提供的方法,实现通过网页进入 kubernetes pod 的终端操作。
- client-go remotecommand
- websocket
- xterm.js
remotecommand
k8s.io/client-go/tools/remotecommand
kubernetes client-go 提供的 remotecommand 包,提供了方法与集群中的容器建立长连接,并设置容器的 stdin,stdout 等。
remotecommand 包提供基于 SPDY 协议的 Executor interface,进行和 pod 终端的流的传输。初始化一个 Executor 很简单,只需要调用 remotecommand 的 NewSPDYExecutor 并传入对应参数。
Executor 的 Stream 方法,会建立一个流传输的连接,直到服务端和调用端一端关闭连接,才会停止传输。常用的做法是定义一个如下 PtyHandler
的 interface,然后使用你想用的客户端实现该 interface 对应的Read(p []byte) (int, error)
和Write(p []byte) (int, error)
方法即可,调用 Stream 方法时,只要将 StreamOptions 的 Stdin Stdout 都设置为 ptyHandler,Executor 就会通过你定义的 write 和 read 方法来传输数据。
// PtyHandler
type PtyHandler interface {
io.Reader
io.Writer
remotecommand.TerminalSizeQueue
}
// NewSPDYExecutor
req := kubeClient.CoreV1().RESTClient().Post().
Resource("pods").
Name(podName).
Namespace(namespace).
SubResource("exec")
req.VersionedParams(&corev1.PodExecOptions{
Container: containerName,
Command: cmd,
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true,
}, scheme.ParameterCodec)
executor, err := remotecommand.NewSPDYExecutor(cfg, "POST", req.URL())
if err != nil {
log.Printf("NewSPDYExecutor err: %v", err)
return err
}
// Stream
err = executor.Stream(remotecommand.StreamOptions{
Stdin: ptyHandler,
Stdout: ptyHandler,
Stderr: ptyHandler,
TerminalSizeQueue: ptyHandler,
Tty: true,
})
websocket
github.com/gorilla/websocket 是 go 的一个 websocket 实现,提供了全面的 websocket 相关的方法,这里使用它来实现上面所说的PtyHandler
接口。
首先定义一个 TerminalSession 类,该类包含一个 *websocket.Conn
,通过 websocket 连接实现PtyHandler
接口的读写方法,Next 方法在 remotecommand 执行过程中会被调用。
// TerminalSession
type TerminalSession struct {
wsConn *websocket.Conn
sizeChan chan remotecommand.TerminalSize
doneChan chan struct{}
}
// Next called in a loop from remotecommand as long as the process is running
func (t *TerminalSession) Next() *remotecommand.TerminalSize {
select {
case size := <-t.sizeChan:
return &size
case <-t.doneChan:
return nil
}
}
// Read called in a loop from remotecommand as long as the process is running
func (t *TerminalSession) Read(p []byte) (int, error) {
_, message, err := t.wsConn.ReadMessage()
if err != nil {
log.Printf("read message err: %v", err)
return copy(p, webshell.EndOfTransmission), err
}
var msg webshell.TerminalMessage
if err := json.Unmarshal([]byte(message), &msg); err != nil {
log.Printf("read parse message err: %v", err)
// return 0, nil
return copy(p, webshell.EndOfTransmission), err
}
switch msg.Operation {
case "stdin":
return copy(p, msg.Data), nil
case "resize":
t.sizeChan <- remotecommand.TerminalSize{Width: msg.Cols, Height: msg.Rows}
return 0, nil
default:
log.Printf("unknown message type '%s'", msg.Operation)
// return 0, nil
return copy(p, webshell.EndOfTransmission), fmt.Errorf("unknown message type '%s'", msg.Operation)
}
}
// Write called from remotecommand whenever there is any output
func (t *TerminalSession) Write(p []byte) (int, error) {
msg, err := json.Marshal(webshell.TerminalMessage{
Operation: "stdout",
Data: string(p),
})
if err != nil {
log.Printf("write parse message err: %v", err)
return 0, err
}
if err := t.wsConn.WriteMessage(websocket.TextMessage, msg); err != nil {
log.Printf("write message err: %v", err)
return 0, err
}
return len(p), nil
}
// Close close session
func (t *TerminalSession) Close() error {
return t.wsConn.Close()
}
xterm.js
前端页面使用xterm.js进行模拟terminal展示,只要 javascript 监听 Terminal 对象的对应事件及 websocket 连接的事件,进行对应的页面展示和消息推送就可以了。
具体实现参考 https://github.com/maoqide/kubeutil.
原文地址:https://www.cnblogs.com/maoqide/p/11375825.html
上一篇: HTML DOM 表单对象
下一篇: 传奇服务器外联网设置超级详细图文教程
推荐阅读
-
使用 client-go 实现 k8s webshell
-
小红书大产品部架构 小红书产品概览--经过性能、稳定性、成本等多个维度的详细评估,小红书最终决定选择基于腾讯云星海自研硬件的SA2云服务器作为主力机型使用。结合其秒级的快速扩缩、超强兼容和平滑迁移能力,小红书在抵御上亿次用户访问、保证系统稳定运行的同时,也实现了成本的大幅降低。 星海SA2云服务器是基于腾讯云星海的首款自研服务器。腾讯云星海作为自研硬件品牌,通过创新的高兼容性架构、简洁可靠的自主设计,结合腾讯自身业务以及百万客户上云需求的特点,致力于为云计算时代提供安全、稳定、性能领先的基础架构产品和服务。如今,星海SA2云服务器也正在为越来越多的企业提供低成本、高效率、更安全的弹性计算服务。 以下是与小红书SRE总监陈敖翔的对话实录。 问:请您介绍一下小红书及其主要商业模式? 小红书是一个面向年轻人的生活方式平台,在这里,他们发现了向上、多元的真实世界。小红书日活超过 3500 万,月活跃用户超过 1 亿,日均笔记曝光量达 80 亿。小红书由社交平台和在线购物两大部分组成。与其他线上平台相比,小红书的内容基于真实的口碑分享,播种不止于线上,还为线下实体店赋能。 问:围绕业务发展,小红书的系统架构经历了怎样的变革和演进? 系统架构变化不大,影响最深的是资源开销。过去三年,资源开销大幅增加,同比增长约 10 倍。在此背景下,我们努力进行优化,包括很早就开始使用 K8S 进行资源调度。到 18 年年中,绝大多数服务已经完全实现了容器化。 问:目前小红书系统架构中的计算基础设施建设和布局是怎样的? 我们目前的建设方式可以简单描述为星型结构。腾讯云在上海的一个区是我们的计算中心,承载着我们的核心数据和在线业务。在外围,我们还有两个数据中心进行计算分流,同时承担灾备和线上业务双活的角色。 与其他新兴电子商务互联网公司类似,小红书的大部分计算能力主要用于线下数据分析、模型训练和在线推荐等平台。随着业务的发展,对算力的需求也在加速增长。