将 Docker 容器文件挂载到另一个容器

问题描述 投票:0回答:1

我正在开发一个代码运行器/编译器网络服务。它由 2 项服务组成:

  1. HTTP/Web - 用户在此处发送代码,我运行它,报告结果(Docker 化)。
  2. CodeRunner 容器 - 它从 /input 文件夹中获取文件并将 results.json 返回到 /output 文件夹。使用名称、输入文件夹、输出文件夹参数运行。不同的语言有不同的图像。 (通过锻炼)

流量:

  1. 我创建一个包含代码文件的“User_Solution-ID”文件夹(将代码放入Solution.cs文件中,配置.csproj)
  2. 我运行 CodeRunner 容器,将“User_Solution-ID”文件夹绑定到 /input 和 /output
  3. 我读取了 results.json 内容,响应用户并删除了该文件夹。

虽然当 HTTP/Web 在主机上运行时这可以完美工作,但在 Docker 中运行时我无法使其工作。

我用来从 Dockerized HTTP/Web 运行 CodeRunner 容器的脚本是:

#!/bin/bash

# Check if required arguments are provided
if [ $# -ne 4 ]; then
    echo "Usage: $0 <RunnerImage> <Exercise> <InputDirectory> <OutputDirectory>"
    exit 1
fi

# Assigning parameters to variables
RunnerImage="$1"
Exercise="$2"
InputDirectory="$3"
OutputDirectory="$4"

# Constructing JSON payload
json_payload="{\"Image\": \"$RunnerImage\", \"Cmd\": [\"$Exercise\", \"/input\", \"/output\"], \"HostConfig\": {\"Binds\": [\"$InputDirectory:/input\", \"$OutputDirectory:/output\"], \"NetworkMode\": \"none\"}}"

# Sending request to create container
response=$(curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d "$json_payload" -X POST http://localhost/v1.42/containers/create)

# Extracting container ID from response
container_id=$(echo "$response" | jq -r '.Id')

# Starting the container
curl --unix-socket /var/run/docker.sock -X POST "http://localhost/v1.42/containers/$container_id/start"

# Waiting for the container to finish
wait_response=$(curl --unix-socket /var/run/docker.sock -X POST "http://localhost/v1.42/containers/$container_id/wait")

# Extracting StatusCode from wait response
status_code=$(echo "$wait_response" | jq -r '.StatusCode')

echo "Container exited with status code: $status_code"

正如预期的那样,Docker 会将 $InputDirectory 和 $OutputDirectory 视为存在于主机上。

我该如何克服这个问题?

我尝试过:

  1. 为了测试,使用 Docker Compose 为我的 HTTP/Web 创建一个卷 input:/input,将我的代码放入其中(现在没有 User_Solution-ID 文件夹)并将该卷传递到容器,如下所示:
    {\"Binds\": [\"input:/input\"...
    。 据我所知,这不起作用,因为它遇到了一些命名冲突(Docker Compose 带有一些 Compose 名称的前缀卷路径)
  2. 使用 Docker Compose 为我的 HTTP/Web 创建卷 input:/app/input,但尝试将 input/User_Solution-ID 文件夹绑定到 CodeRunner 容器不起作用(绑定路径为 app/input/User_Solution-ID主机上不存在)

有哪些可能的解决方案?我考虑为每个代码文件夹创建一个卷并将其传递到 CodeRunner 容器。

bash docker docker-compose dockerfile containers
1个回答
0
投票

您无法将文件从一个容器装载到另一个容器。正如您在问题中注意到的,Docker 守护进程解析绑定安装路径,它们是主机系统上的目录,而不是调用 Docker 的上下文中的目录。 (在具有远程 Docker 守护进程或 Docker-in-Docker 容器的复杂环境中,绑定挂载位于 Docker 守护进程运行的上下文中,而不一定是本地系统中。)

它从 /input 文件夹中获取文件并将 results.json 返回到 /output 文件夹

主要读写本地文件的程序更容易作为本地进程运行。 Docker 容器具有独立的文件系统,您最终必须进行一些可能复杂的设置(包括使用户 ID 匹配)才能使用本地文件。

如果您可以将其作为子进程运行,那么这会容易得多。您需要在 Web 应用程序的 Dockerfile 中安装运行程序工具,然后您可以像调用任何其他子进程(如这个 shell 脚本)一样调用它。

# without doing anything Docker-related at all
"$Exercise" /input /output

否则,您需要在应用程序容器和运行器容器之间进行某种共享存储。主机目录或 Docker 命名卷都可以使用。我可能会在环境变量中传递此位置,因为它很容易依赖于特定的部署环境。由于您将路径作为命令行选项传递给运行程序,因此我将挂载整个共享存储,并在命令行上传递子路径。

使用命名卷的基本示例可能如下所示:

docker volume create shared
docker run -v shared:/shared ... web_app
然后,您的 Web 应用程序会将数据写入

/shared/input/$SOLUTION_ID

,并创建一个空的 
/shared/output/$SOLUTION_ID
 目录。当它启动运行器容器时,它看起来像

#!/bin/sh RunnerImage="$1" SharedVolume="$2" Exercise="$3" SolutionID="$4" exec docker run \ --rm \ -v "$SharedVolume:/shared" \ --net none \ "$RunnerImage" \ "$Exercise" "/shared/input/$SolutionId" "/shared/output/$SolutionId"
(您可以将其翻译为驱动 Docker HTTP API 的手动 

curl

 命令,但是 
docker run
 可以做同样的事情,而且要短得多。)

相同的解决方案适用于绑定安装的主机目录。在

docker run

 语法中,相同的 
-v
 选项也可以使用,但使用绝对 
/host/path
 目录名称。我相信 API 调用略有不同。

© www.soinside.com 2019 - 2024. All rights reserved.