This code demonstrates how to build a virtual terminal using the Golang Docker SDK and WebSocket. It allows users to interact with a Docker container's shell through their browser.

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func main() {
	http.HandleFunc("/terminal", handleTerminal)
	http.ListenAndServe(":8080", nil)
}

func handleTerminal(w http.ResponseWriter, r *http.Request) {
	// Upgrade HTTP connection to WebSocket
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("Failed to upgrade connection:", err)
		return
	}

	// Connect to Docker API
	cli, err := client.NewEnvClient()
	if err != nil {
		fmt.Println("Failed to connect to Docker API:", err)
		return
	}

	// Create new container
	resp, err := cli.ContainerCreate(context.Background(), &types.ContainerConfig{
		Image: "ubuntu",
		Cmd:   []string{"/bin/bash"},
		Tty:   true,
	}, nil, nil, "")
	if err != nil {
		fmt.Println("Failed to create container:", err)
		return
	}

	// Start container
	if err := cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}); err != nil {
		fmt.Println("Failed to start container:", err)
		return
	}

	// Attach to container
	exec, err := cli.ContainerExecCreate(context.Background(), resp.ID, types.ExecConfig{
		Cmd:          []string{"bash"},
		AttachStdin:  true,
		AttachStdout: true,
		AttachStderr: true,
		Tty:          true,
	})
	if err != nil {
		fmt.Println("Failed to create exec command:", err)
		return
	}
	hijackedResp, err := cli.ContainerExecAttach(context.Background(), exec.ID, types.ExecStartCheck{Tty: true})
	if err != nil {
		fmt.Println("Failed to attach to exec command:", err)
		return
	}
	defer hijackedResp.Close()

	// Start reading from container and writing to WebSocket
	go func() {
		for {
			buf := make([]byte, 1024)
			n, err := hijackedResp.Reader.Read(buf)
			if err != nil {
				fmt.Println("Failed to read from container:", err)
				conn.Close()
				return
			}
			if err := conn.WriteMessage(websocket.TextMessage, buf[:n]); err != nil {
				fmt.Println("Failed to write to WebSocket:", err)
				return
			}
		}
	}()

	// Start reading from WebSocket and writing to container
	for {
		_, message, err := conn.ReadMessage()
			if err != nil {
				fmt.Println("Failed to read from WebSocket:", err)
				return
			}
			if _, err := hijackedResp.Conn.Write(message); err != nil {
				fmt.Println("Failed to write to container:", err)
				return
			}
	}
}

This code utilizes the ContainerExecAttach method from the Docker SDK to connect a new bash process to a running Ubuntu container. The gorilla/websocket library is used to bridge the standard input/output streams of the bash process with the WebSocket connection. When a user types commands in their browser, these commands are sent to the container's standard input stream. The bash process then executes the commands, writes the output to its standard output stream, and these outputs are then relayed back to the user's browser.

Golang Docker SDK ContainerExecAttach with WebSocket: Building a Virtual Terminal

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

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