使用docker-py进行交互式Docker exec

1 投票
1 回答
41 浏览
提问于 2025-04-14 16:19

我正在尝试实现一个类似于下面的功能:

docker exec -it <some_container> /bin/bash

也就是说,在一个容器中运行一个命令,并将我程序的 stdin(标准输入)和 stdout(标准输出)连接到这个命令的 stdinstdout

根据我对文档的理解,下面的代码应该可以实现这个功能:

import docker
client = docker.from_env()
container, = client.containers.list()
container.exec_run(['/usr/local/bin/bash'], stdin=True, tty=True)

(这里有一个正在运行的容器,使用的是 bash:latest

但是似乎我的程序的 stdin 并没有连接到这个被 exec 执行的命令上。命令行只是静静地在那里,回显我的输入,但没有任何反应。

我还尝试直接与原始套接字进行交互(这是通过 exec_run 返回的,而不是 docker.sock):

_, s = container.exec_run(['/usr/local/bin/bash'], stdin=True, tty=True, socket=True)
s.write('echo hello world')

但我收到的错误是 UnsupportedOperation: File or stream is not writable.

问题:我需要做些什么才能让我的代码用户能够与在容器中执行的命令的标准输入输出进行交互,使用 docker-py?

1 个回答

0

exec_run的结果是一个socket.SocketIO对象。你可以使用它的socket来进行接收和发送数据,方法是recv()和sendall()。

比如:

import docker
import threading
import queue

client = docker.from_env()
container = client.containers.get('YOUR CONTAINER NAME')
_, sock = container.exec_run(cmd='bash', stdin=True, socket=True)
ch = queue.Queue()

def read():
    while res := sock._sock.recv(4096):
        print(res[8:].decode())

def write():
    while item := ch.get():
        item = item + '\n'
        item = bytes(item, 'utf-8')
        sock._sock.sendall(item)

writer = threading.Thread(target=write)
writer.start()

reader = threading.Thread(target=read)
reader.start()

while cmd := input():
    ch.put(cmd)
    if cmd == 'exit':
        break

sock._sock.close()
ch.put(None)

writer.join()
reader.join()

撰写回答