gin框架使用websocket实现进入容器内部执行命令
@
1. 先决条件
docker开放远程API端口
2. gin框架实现
type GetCommandResultRequire struct { IpAddr string `json:"ip_addr"` //传入要控制容器的ip地址 ContainerUuid string `json:"container_uuid"` //容器id } func GetCommendResult(c *gin.Context) { var sendCommandRequire GetCommandResultRequire sendCommandRequire.IpAddr = c.Query("ip_addr") sendCommandRequire.ContainerUuid = c.Query("container_uuid") //升级接口 ws, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { fmt.Print("升级websocket连接错误:", err) return } defer ws.Close() execHr := new(types.HijackedResponse) dockerCli, err := ConnectDocker(sendCommandRequire.IpAddr) if err != nil { tools.SetErr(c, 500, err, err.Error())//此处是自己实现的gin返回 return } //启动携程,持续接收信息、传入命令、异常关闭docker链接 go func() { for { _, message, err := ws.ReadMessage() if err != nil { logger.Error("接口断开:", err) execHr.Close() ws.Close() return } logger.Info(string(message)) //发送命令 err = SendCommend(string(message), execHr) if err != nil { logger.Error("命令发送错误") } } }() err = ExecContainer(dockerCli, execHr, ws, sendCommandRequire.ContainerUuid) if err != nil { tools.SetErr(c, 500, err, err.Error()) return } logger.Info("链接关闭") } //定义一个函数,链接容器,并持续输出。 func ExecContainer(dockerCli *client.Client, execHr *types.HijackedResponse, conn *websocket.Conn, containerId string) error { ctx := context.Background() // 在指定容器中执行/bin/bash命令 ir, err := dockerCli.ContainerExecCreate(ctx, containerId, types.ExecConfig{ AttachStdin: true, AttachStdout: true, AttachStderr: true, Cmd: []string{"/bin/sh"}, Tty: true, }) if err != nil { return err } // 保持链接 *execHr, err = dockerCli.ContainerExecAttach(ctx, ir.ID, types.ExecStartCheck{Detach: false, Tty: true}) if err != nil { return err } //关闭I/O defer execHr.Close() // 输入一个测试命令(非必要) _, err = execHr.Conn.Write([]byte("ls\r")) if err != nil { return err } // 输出 scanner := bufio.NewScanner(execHr.Conn) for scanner.Scan() { fmt.Println(scanner.Text()) text := scanner.Text() b, _ := json.Marshal(text) err = conn.WriteMessage(websocket.TextMessage, b) if err != nil { log.Println("写入错误", err) //return err continue } } logger.Info("容器输出结束") return nil } //写一个函数,向容器中发送命令。 func SendCommend(cmdString string, execHr *types.HijackedResponse) (err error) { _, err = execHr.Conn.Write([]byte(cmdString + "\r")) if err != nil { return } return nil }
3. 测试用html文件
仅是一个测试文件,很丑,但是后端测试够了。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <title>TestWebsocket</title> <script type="text/javascript"> var Server_Com; function LinkServer() { // 声明连接 if ("WebSocket" in window) { Server_Com = new WebSocket("ws://127.0.0.1:18000/v1/m6e/docker/container/exec?ip_addr=10.10.239.32&container_uuid=48bcf6811212"); console.log("新建连接到->127.0.0.1:18000"); } // 建立连接后发送 Server_Com.onopen = function() { Server_Com.send("Hello Server!"); // Web Socket 已连接上,使用 send() 方法发送数据 console.log("已连接上服务器"); } // 接收服务器消息 Server_Com.onmessage = function(event) { var recv_msg = event.data; if (recv_msg == "Hello Client!") { console.log("接收到服务器的问候: " + recv_msg); // 用于提示收到信息 } else { document.getElementById("Time").textContent = document.getElementById("Time").textContent + "\r\n" + recv_msg; // 实时更新显示服务器发回的时间 console.log("接收到服务器数据: " + recv_msg); } } } function SendMessage(){ var inputMessage = document.getElementById("sendcmd").value; Server_Com.send(inputMessage); } </script> </head> <body> <p>接收到的信息:</p> <p id="Time">crow-exec测试</p> <button onclick="SendMessage()">发送消息</button> <input id="sendcmd" name="sendcmd"></input> <button onclick="LinkServer()">连接</button> </body> </html>
4. 需要完善
vi 编辑器无法实现,需要进一步完善。
分类:
go语言开发 / gin框架实战
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2022-03-23 docker命令总结
2022-03-23 HTML基础-09-布局(使用<div>实现,使用<table>实现)