我正在创建一个应用程序,允许用户上传视频文件,然后对视频文件进行一些处理。
我有两个容器。
Nginx
为网站提供服务的容器,用户可以在其中上传视频文件。 FFmpeg
和其他一些处理工具的视频处理容器。我想要实现的目标。我需要容器 1 才能在容器 2 上运行 bash 脚本。
据我所知,一种可能性是让它们通过 API 通过 HTTP 进行通信。但随后我需要在容器 2 中安装一个 Web 服务器并编写一个 API,这似乎有点大材小用。 我只想执行 bash 脚本。
有什么建议吗?
您有几个选择,但首先想到的两个是:
/var/run/docker.sock
(您需要从
启动容器时的主机)。然后,在容器内,您
应该能够对已安装的绑定使用 docker
命令
就像您从主机执行它们一样(您也可以
需要 chmod
容器内的套接字以允许非 root
用户执行此操作。SSHD
,然后从容器 1 中安装 ssh
并运行脚本。这样做的优点是,您不需要在容器内部进行任何更改,因为它们是在 Docker 而不是裸机中运行的。缺点是您需要将 SSHD 设置添加到 Dockerfile 或启动脚本中。我能想到的大多数其他想法只是选项(2)的变体,用其他一些工具代替了 SSHD。
还要注意 Docker 网络有点奇怪(至少在 Mac 主机上),因此您需要确保容器使用相同的 docker 网络并且能够通过它进行通信。
要完全明确的是,不要在实验室或严格控制的开发环境之外使用选项 1。它采用对主机上的 Docker 运行时具有完全权限的安全套接字,并从容器授予对其进行未经检查的访问。这样做可以轻松地突破 Docker 沙箱并危害主机系统。我认为它唯一可以接受的地方是作为完整堆栈集成测试设置的一部分,该设置仅由开发人员临时运行。这是一种在某些非常特定的情况下可以成为有用的捷径的技巧,但其缺点也不能被夸大。
我专门为这个用例编写了一个 python 包。
Flask-Shell2HTTP 是一个 Flask 扩展,只需 5 行代码即可将命令行工具转换为 RESTful API。
示例代码:
from flask import Flask
from flask_executor import Executor
from flask_shell2http import Shell2HTTP
app = Flask(__name__)
executor = Executor(app)
shell2http = Shell2HTTP(app=app, executor=executor, base_url_prefix="/commands/")
shell2http.register_command(endpoint="saythis", command_name="echo")
shell2http.register_command(endpoint="run", command_name="./myscript")
可以轻松调用,
$ curl -X POST -H 'Content-Type: application/json' -d '{"args": ["Hello", "World!"]}' http://localhost:4000/commands/saythis
您可以使用它来创建 RESTful 微服务,该微服务可以异步执行带有动态参数的预定义 shell 命令/脚本并获取结果。
支持文件上传、回调fn、反应式编程等。我建议您查看示例。
从容器运行
docker
命令并不简单,也不是一个好主意(在我看来),因为:
所以,这给我们留下了两个解决方案:
之前已经提到过,但一个合理的、半黑客的选项是在两个容器中安装 SSH,然后使用 ssh 在另一个容器上执行命令:
# install SSH, if you don't have it already
sudo apt install openssh-server
# start the ssh service
sudo service start ssh
# start the daemon
sudo /usr/sbin/sshd -D &
假设您不想始终是 root,您可以添加默认用户(在本例中为“foobob”):
useradd -m --no-log-init --system --uid 1000 foobob -s /bin/bash -g sudo -G root
#change password
echo 'foobob:foobob' | chpasswd
在源容器和目标容器上执行此操作。现在您可以从container_1到container_2执行命令了。
# obtain container-id of target container using 'docker ps'
ssh foobob@<container-id> << "EOL"
echo 'hello bob from container 1' > message.txt
EOL
您可以使用 ssh-agent 自动设置密码,或者您可以使用
sshpass
使用一些更 hacky 的东西(首先使用 sudo apt install sshpass
安装它):
sshpass -p 'foobob' ssh foobob@<container-id>
我相信
docker exec -it <container_name> <command>
即使在容器内也应该可以工作。
您还可以尝试安装到您尝试执行命令的容器中的
docker.sock
:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...