首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >基于gin+sockjs实现k8s pod web terminal

基于gin+sockjs实现k8s pod web terminal

作者头像
有点技术
发布2020-07-14 14:55:40
发布2020-07-14 14:55:40
1.8K00
代码可运行
举报
文章被收录于专栏:有点技术有点技术
运行总次数:0
代码可运行

基于gin+sockjs实现k8s pod web terminal

路由定义

由于sockjs会动态生成路由参数用来记录回话id,所以这里需要使用参数路由,beego的也是一样,很早之前写过一个beego的,在github上可以找到

代码语言:javascript
代码运行次数:0
运行
复制
r.Any("/pod/exec/*path", cluster.ContainerTerminal)

定义一个sockjsterminal对象

代码语言:javascript
代码运行次数:0
运行
复制
# 这里写的比较粗糙,实际上可以定义通信消息对象,规范化字段func (self TerminalSockjs) Read(p []byte) (int, error) {    var reply string    var msg map[string]uint16    reply, err := self.Conn.Recv()    if err != nil {        return 0, err    }    if err := json.Unmarshal([]byte(reply), &msg); err != nil {        return copy(p, reply), nil    } else {        self.SizeChan <- &remotecommand.TerminalSize{            Width:  msg["cols"],            Height: msg["rows"],        }        return 0, nil    }}func (self TerminalSockjs) Write(p []byte) (int, error) {    err := self.Conn.Send(string(p))    return len(p), err}# resizefunc (self *TerminalSockjs) Next() *remotecommand.TerminalSize {    size := <-self.SizeChan    log.Printf("terminal size to width: %d height: %d", size.Width, size.Height)    return size}type TerminalSockjs struct {    Conn      sockjs.Session    SizeChan  chan *remotecommand.TerminalSize    Cluster   uint    Namespace string    Pod       string    Container string}

实现了读写方法,用来处理k8s exec接口的读写

sockjs handler定义

代码语言:javascript
代码运行次数:0
运行
复制
func Handler(t *TerminalSockjs, cmd []string) error {    client, err := kubeconn.GetClientset(t.Cluster)    if err != nil {        log.Println(err)        return err    }    clientConfig, err := kubeconn.GetClientconfig(t.Cluster)    if err != nil {        log.Println(err)        return err    }    restclient := client.CoreV1().RESTClient()    fn := func() error {        req := restclient.Post().            Resource("pods").            Name(t.Pod).            Namespace(t.Namespace).            SubResource("exec")        req.VersionedParams(            &v1.PodExecOptions{                Container: t.Container,                Command:   cmd,                Stdin:     true,                Stdout:    true,                Stderr:    true,                TTY:       true,            },            scheme.ParameterCodec,        )        executor, err := remotecommand.NewSPDYExecutor(            clientConfig, http.MethodPost, req.URL(),        )        if err != nil {            return err        }        return executor.Stream(remotecommand.StreamOptions{            Stdin:             t,            Stdout:            t,            Stderr:            t,            Tty:               true,            TerminalSizeQueue: t,        })    }    return fn()}

具体的handler

代码语言:javascript
代码运行次数:0
运行
复制
    Sockjshandler := func(session sockjs.Session) {        log.Println("ContainerTerminal2")        t := &term.TerminalSockjs{            Conn:      session,            SizeChan:  make(chan *remotecommand.TerminalSize),            Cluster:   uint(self.MustGet("cid").(int64)),            Namespace: namespace,            Pod:       pod,            Container: container,        }        if casbin.Enforcer.HasRoleForUser(self.MustGet("user").(db.User).Email, "admin") == true {            if err := term.Handler(t, []string{"/bin/bash"}); err != nil {                err := term.Handler(t, []string{"/bin/sh"})                log.Println(t.Conn.Close(200, "client close"), err)            }        } else {            if err := term.Handler(t, []string{"/bin/bash", "-c", "echo 'dev ALL=(root) NOPASSWD:/usr/local/bin/jstack,/usr/local/bin/jmap,/usr/local/bin/jstat'> /etc/sudoers;useradd dev;su dev"}); err != nil {                log.Println(err)                err := term.Handler(t, []string{"/bin/sh", "-c", "echo 'dev ALL=(root) NOPASSWD:/usr/local/bin/jstack,/usr/local/bin/jmap,/usr/local/bin/jstat'> /etc/sudoers;useradd dev;su dev"})                log.Println(t.Conn.Close(200, "client close"), err)            }        }    }

这里为了探测使用的shell所以定义了一个重试,另外为了结合平台实现不同用户进入容器的用户,以及可以执行sudo的命令,可以通过生成sudo配置来实现,示例为dev用户可执行sudo命令的命令列表,实际使用可以存入数据库动态生成sudo文件,实现细粒度的控制。

sockjs handler

代码语言:javascript
代码运行次数:0
运行
复制
sockjs.NewHandler("/api/cluster/pod/exec", sockjs.Options{        Websocket:       true,        JSessionID:      nil,        SockJSURL:       "https://cdn.bootcss.com/sockjs-client/1.3.0/sockjs.min.js",        HeartbeatDelay:  25 * time.Second,        DisconnectDelay: 5 * time.Second,        ResponseLimit:   128 * 1024,    }, Sockjshandler).ServeHTTP(self.Writer, self.Request)

前端结合xterm.js就可以实现webterminal,具体前端比较简单,可以看xterm.js的官方文档

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 有点技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 路由定义
  • 定义一个sockjsterminal对象
  • sockjs handler定义
  • sockjs handler
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档