Golang Docker SDK 中 ContainerExecAttach 方法与 WebSocket 的结合应用: 实现可交互的 Docker 虚拟终端
以下是一个能与前端交互的 Docker 虚拟终端方法的示例代码:
package main
import (
"context"
"errors"
"io"
"net/http"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/gorilla/websocket"
)
func main() {
http.HandleFunc("/docker-terminal", dockerTerminalHandler)
http.ListenAndServe(":8080", nil)
}
func dockerTerminalHandler(w http.ResponseWriter, r *http.Request) {
// Upgrade HTTP connection to WebSocket
upgrader := websocket.Upgrader{}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Connect to Docker daemon
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Create container
resp, err := cli.ContainerCreate(context.Background(), &container.Config{
Image: "ubuntu",
Cmd: []string{"bash"},
Tty: true,
}, nil, nil, "")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Start container
if err := cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Attach to container
execResp, err := cli.ContainerExecCreate(context.Background(), resp.ID, types.ExecConfig{
Cmd: []string{"bash"},
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
Tty: true,
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
execID := execResp.ID
hijackedResp, err := cli.ContainerExecAttach(context.Background(), execID, types.ExecStartCheck{})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer hijackedResp.Close()
// Start reading from container
go func() {
for {
// Read data from container
buf := make([]byte, 1024)
n, err := hijackedResp.Reader.Read(buf)
if err != nil {
if !errors.Is(err, io.EOF) {
conn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
}
break
}
// Write data to WebSocket
if err := conn.WriteMessage(websocket.TextMessage, buf[:n]); err != nil {
break
}
}
}()
// Start writing to container
for {
// Read data from WebSocket
_, message, err := conn.ReadMessage()
if err != nil {
if !errors.Is(err, io.EOF) {
hijackedResp.Close()
}
break
}
// Write data to container
if _, err := hijackedResp.Conn.Write(message); err != nil {
break
}
}
}
这个方法会创建一个 Ubuntu 容器,并启动一个 bash 终端。然后,它会使用 websocket 包将 HTTP 连接升级为 WebSocket 连接,并将终端的输入和输出流连接到 WebSocket 连接。这样,用户就可以在前端页面上输入命令并查看终端的输出了。
原文地址: https://www.cveoy.top/t/topic/kWk0 著作权归作者所有。请勿转载和采集!