python - Python docker 模块:如何在 python 中为 docker 容器创建终端 shell?
问题描述
我想创建一个 discord/IRC 机器人,让随机的人访问我的服务器上的 bash 控制台。为了让这不那么疯狂,我决定使用一个 docker 容器,所以希望我的服务器不会得到 rm -rf ed。然而,不幸的是,我一直坚持将 IO 传输到 docker 容器上的 /bin/bash 。
import docker
import time
import asyncio
client = docker.from_env()
c = client.containers.run(
image='disbox:main',
command = "neofetch",
cpu_count = 1,
mem_limit = "1g",
hostname="disbox",
user = "discord",
entrypoint="/bin/bash",
ports = {'80': 8080},
detach = True
)
# wait for container to start
time.sleep(5)
container = client.containers.get(c.id)
while True:
cmd = input("\n:")
res = container.exec_run(cmd, stream=True)
for line in res:
print(line.output)
这给出了 url 错误的冲突,我不确定这意味着什么。我已经验证它尚未在其他地方运行。我正在使用 root 运行 python(否则它会给我一个 perms 错误)。
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 261, in _raise_for_status
response.raise_for_status()
File "/usr/lib/python3/dist-packages/requests/models.py", line 940, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 409 Client Error: Conflict for url: http+docker://localhost/v1.35/containers/f54feee310d0890b751d9544b020279e1ab35e470b98773f4b160b4c0a470d11/exec
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
File "/usr/lib/python3/dist-packages/docker/models/containers.py", line 193, in exec_run
resp = self.client.api.exec_create(
File "/usr/lib/python3/dist-packages/docker/utils/decorators.py", line 19, in wrapped
return f(self, resource_id, *args, **kwargs)
File "/usr/lib/python3/dist-packages/docker/api/exec_api.py", line 80, in exec_create
return self._result(res, True)
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 267, in _result
self._raise_for_status(response)
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 263, in _raise_for_status
raise create_api_error_from_http_exception(e)
File "/usr/lib/python3/dist-packages/docker/errors.py", line 31, in create_api_error_from_http_exception
raise cls(e, response=response, explanation=explanation)
docker.errors.APIError: 409 Client Error: Conflict ("Container f54feee310d0890b751d9544b020279e1ab35e470b98773f4b160b4c0a470d11 is not running")
此代码片段的目的是在 python 控制台中复制一个 bash 控制台。我哪里做错了?
编辑:图像名称是 100% 正确的,它是一个自定义的 ubuntu SE 图像,带有 neofetch 和一些其他预加载的东西。
解决方案
如果您以交互式 shell 作为其主进程运行容器,但未指定容器的标准输入应保持打开状态,则 shell 将立即退出。(这与docker run --entrypoint /bin/bash disbox:main
没有-it
选项相同。)创建容器时,您需要包含相关选项:
c = client.containers.run(
...,
stdin_open=True,
tty=True
)
然后容器对象有一个attach_socket
方法。这将返回一个类似套接字的对象,您可以send
往返recv
;直接连接到容器的标准输入和标准输出。在您的上下文中,您可能可以使用这些直接在客户端进程和容器之间来回中继数据,知道它是面向行的,但不知道它是一个外壳。
您在这里不需要“exec”类型的操作;您直接与容器进程的标准输入和标准输出进行交互。
(还请记住,在容器中使用 shell 可以解决很多问题:对主机本身发起 DoS 攻击、针对主机内核的本地权限提升攻击、加密货币矿工等。 您可以在此处获得一些保护,以免被在一个容器中,但如果您有任何理由不信任您的最终用户,它就不是“安全的”。)
推荐阅读
- javascript - Ionic - JavaScript:访问函数内的属性
- java - eclipse中的java错误“该项目未构建由于..”
- php - Laravel 模型只获得一个相关模型
- database - 无需编码即可创建数据库
- ruby-on-rails - rails/rspec 将 render_template 方法读取为 assert_template 'NoMethodError Exception'
- sql-server - 按移位的 DATETIME 字段和按 ID 的 PIVOT 分组
- c# - HTTPS 调用异常“由于意外的数据包格式,握手失败。”
- c - 使用 libcurl 通过 ac 程序从 owlbot 获取含义
- javascript - 我无法终止 JS 中的函数
- elasticsearch - 查询字符串查询中范围字段的 Elasticsearch 范围查询