webssh(1):ssh进k8s pod ; django后台websocket+前台xterm插件

技术点:

后端:django;websocket;多线程;前端:xterm;其他:k8s

库:

from dwebsocket.decorators import accept_websocket
from kubernetes.stream import stream

原理图:

webssh(1):ssh进k8s pod ; django后台websocket+前台xterm插件_第1张图片

后台处理:

ws.read()与ssh.send()绑定在同一线程;

ws.send()与ssh.read()绑定在同一线程

 

一.后台:

1.1 websocket请求处理:

@accept_websocket
def pod_exec(request):
    if request.is_websocket():
        namespace = 'dev-namespace'
        pod = "demo0908-857f66466f-l9566"
        container = "demo0908"
        api_instance = kube.corevaapi
        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']

        container_stream = stream(api_instance.connect_get_namespaced_pod_exec,
                                  name=pod,
                                  namespace=namespace,
                                  container=container,
                                  command=exec_command,
                                  stderr=True, stdin=True,
                                  stdout=True, tty=True,
                                  _preload_content=False
                                  )

        commands = [
            "echo This message goes to stdout",
            "echo \"This message goes to stderr\" >&2",
        ]
        kub_stream = K8SStreamThread(request.websocket, container_stream)
        kub_stream.start()

        while container_stream.is_open() and not request.websocket.is_closed():
            ws_reviced = request.websocket.read()
            if (ws_reviced != None):
                # container_stream.write_stdin('exit\r')
                re = container_stream.write_stdin(str(ws_reviced, encoding="utf-8"))
        else:
            if not request.websocket.is_closed():
                request.websocket.close()
            if container_stream.is_open():
                container_stream.close()
    else:
        return JsonResponse({"msg": "use websocket connect"})
 

1.2 多线程将websocket与k8s stream输入输出绑定

class K8SStreamThread(Thread):
    def __init__(self, websocket, container_stream):
        Thread.__init__(self)
        self.websocket = websocket
        self.stream = container_stream

    def run(self):
        while self.stream.is_open() and not self.websocket.is_closed():
            # self.stream.update()
            if self.stream.peek_stdout():
                stdout = self.stream.read_stdout()
                #stdout = self.stream.peek_stdout()
                if stdout:
                    self.websocket.send(stdout.encode(encoding='utf-8'))

            if self.stream.peek_stderr():
                stderr = self.stream.read_stderr()
                self.websocket.send(stderr)
        else:
            if not self.websocket.is_closed():
                self.websocket.close()
            if self.stream.is_open():
                self.stream.close()
 

二.前台:

依赖:term或xterm插件

var term;

//var wsUrl = "ws://127.0.0.1:8080/server";
var wsUrl = "ws://127.0.0.1:8000/api/kube/podexec/";
websocket = new WebSocket(wsUrl);//new 一个websocket实例
websocket.onopen = function (evt) {//打开连接websocket
    term = new Terminal({  //new 一个terminal实例,就是数据展示的屏幕和一些见简单设置,包括屏幕的宽度,高度,光标是否闪烁等等
        cols: 200,
        rows: 80,
        screenKeys: true,
        useStyle: true,
        cursorBlink: true,
    });

    /*term实时监控输入的数据,并且websocket把实时数据发送给后台*/
    term.on('data', function (data) {//term.on方法就是实时监控输入的字段,
        websocket.send(data);//websocket发送给后台
    });
    term.on('title', function (title) {
        document.title = 'test-jump';
    });
    term.open(document.getElementById('container-terminal'));//屏幕将要在哪里展示,就是屏幕展示的地方
    websocket.onmessage = function (evt) {//接受到数据
        term.write(evt.data);//把接收的数据写到这个插件的屏幕上
    }
    websocket.onclose = function (evt) {//websocket关闭
        term.write("Session terminated");
        term.destroy();//屏幕关闭
    }
    websocket.onerror = function (evt) {//失败额处理
        if (typeof console.log == "function") {
            console.log(evt)
        }
    }
}

var close = function () {//关闭websocket
    websocket.close();
};

三.效果图:

webssh(1):ssh进k8s pod ; django后台websocket+前台xterm插件_第2张图片

 

注意事项:

1.websocket与k8s.stream连接是否正常的判断与断开连接的条件,处理不好后台会残留线程

2.ssh返回中部分字符看似乱码,实则为ssh样式(颜色)显示,需配合term调试才能显示实际效果

3.k8s stream接口中peek_stdout()与read_stdout()区别

你可能感兴趣的:(django,Python,k8s,python,django,websocket)