У меня запущено приложение Django и Docker Setup.
Я пытаюсь добиться, чтобы пользователь приложения Django мог удаленно подключать
к контейнеру через веб-сокет и получать оболочка внутри своего браузера, поэтому ему не нужна дополнительная настройка et c ..
Моя первоначальная мысль примерно такая:
- Пользователь отправляет запрос контейнера X на Django.
- Django проверяет, аутентифицирован ли пользователь et c.
- Django звонки docker
- Docker открывает сокет
- Django возвращает сокет Frontend (User)
Чтобы проверить этот процесс, я попробовал что-то вроде:
import docker
client = docker.from_env()
container = client.containers.get("Id of conainer X")
result = container.exec_run(cmd="/bin/bash", stdout=True, stdin=True, stderr=True, tty=True, socket=True)
Здесь начинается моя борьба. Отладчики PyCharm сообщают мне
, что result[1]
(я предполагаю, это сокет для stdin?) Имеет тип: socket.SocketIO
Как я могу открыть оболочку в моем Frontend с помощью этого сокета?
I Мы рассмотрели Portainer и инструмент под названием docker -box ,
, но они оба используют странный метод Golang для перехвата соединения?
Вот код инструмента docker -box:
func ExecContainer(ws *websocket.Conn) {
container := ws.Request().URL.Path[len("/exec/"):]
if container == "" {
ws.Write([]byte("Container does not exist"))
return
}
type stuff struct {
Id string
}
var s stuff
params := bytes.NewBufferString("{\"AttachStdin\":true,\"AttachStdout\":true,\"AttachStderr\":true,\"Tty\":true,\"Cmd\":[\"/bin/bash\"]}")
resp, err := http.Post("http://"+*host+"/containers/"+container+"/exec", "application/json", params)
if err != nil {
panic(err)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
json.Unmarshal([]byte(data), &s)
if err := hijack(*host, "POST", "/exec/"+s.Id+"/start", true, ws, ws, ws, nil, nil); err != nil {
panic(err)
}
fmt.Println(ws)
spew.Dump(ws)
}
func hijack(addr, method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer, data interface{}) error {
params := bytes.NewBufferString("{\"Detach\": false, \"Tty\": true}")
req, err := http.NewRequest(method, path, params)
if err != nil {
return err
}
req.Header.Set("User-Agent", "Docker-Client")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Connection", "Upgrade")
req.Header.Set("Upgrade", "tcp")
req.Host = addr
dial, err := net.Dial("tcp", addr)
if tcpConn, ok := dial.(*net.TCPConn); ok {
tcpConn.SetKeepAlive(true)
tcpConn.SetKeepAlivePeriod(30 * time.Second)
}
if err != nil {
return err
}
clientconn := httputil.NewClientConn(dial, nil)
defer os.Exit(0)
defer clientconn.Close()
clientconn.Do(req)
rwc, br := clientconn.Hijack()
defer rwc.Close()
if started != nil {
started <- rwc
}
var receiveStdout chan error
if stdout != nil || stderr != nil {
go func() (err error) {
if setRawTerminal && stdout != nil {
_, err = io.Copy(stdout, br)
}
return err
}()
}
go func() error {
if in != nil {
io.Copy(rwc, in)
}
if conn, ok := rwc.(interface {
CloseWrite() error
}); ok {
if err := conn.CloseWrite(); err != nil {
os.Exit(0)
}
}
return nil
}()
if stdout != nil || stderr != nil {
if err := <-receiveStdout; err != nil {
return err
}
}
spew.Dump(br)
go func() {
for {
fmt.Println(br)
spew.Dump(br)
}
}()
return nil
}
Является ли Go единственным способом добиться этого, или я могу сделать то же самое и в Python?
Это мой первый проект с Django кстати ..
Спасибо за помощь.