以下是一个能与前端交互的 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 连接。这样,用户就可以在前端页面上输入命令并查看终端的输出了。

Golang Docker SDK 中 ContainerExecAttach 方法与 WebSocket 的结合应用: 实现可交互的 Docker 虚拟终端

原文地址: https://www.cveoy.top/t/topic/kWk0 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录