tl;dr:如何使用docker传递文件I/O+参数?还是应该放弃使用脚本之类的容器?
我正在努力学习docker,我很难掌握一些常见I/O和参数传递情况的简单示例。我已经浏览了很多StackOverflow内容,比如here以及Docker文档,但这似乎太简单了,没有人愿意回答。最接近的是here,但答案没有帮助,而且似乎大多是说“不要对Docker这样做”。但是人们似乎在谈论容器,好像他们可以在独立的应用程序中做这类事情
简而言之,在Docker中,似乎所有I/O路径都需要硬编码,但我希望这些路径能够灵活,因为我希望尽可能灵活地使用容器作为脚本。
在某些情况下,人们通过让容器处于空闲状态,然后将参数传递给它(例如here或here)来解决这个问题,但出于简单的目的,这似乎相当复杂
我不是在寻找使用venvs/conda的方法,我想看看使用Docker是否可行。
假设我有一个名为test.py
的简单Python脚本:
#!/usr/bin/env python3
import argparse
def parse_args():
'''Parse CLI arguments
Returns:
dict: CLI arguments
'''
parser = argparse.ArgumentParser(description='Parse arguments for test')
parser.add_argument('--out_file', '-o', required=True, type=str, help='output file')
parser.add_argument('--in_file', '-i', required=True, type=str, help='input file')
args = parser.parse_args()
return vars(args)
args = parse_args()
with open(args["in_file"]) as input_handle:
print(input_handle.readline())
with open(args["out_file"], "w") as output_handle:
output_handle.write("i wrote to a file")
在Python中,我可以在一些输入文件上运行:
% cat ../input.txt
i am an input file
% python test.py -i ../input.txt -o output.txt
i am an input file
% cat output.txt
i wrote to a file%
让我们假设,无论出于何种原因,该脚本都需要进行docker化,同时保留参数/文件的传递方式,以便人们可以在没有docker的情况下运行它。我可以写一个非常简单的Dockerfile:
FROM continuumio/miniconda3
COPY . .
ENTRYPOINT ["python", "test.py"]
这将接受参数,但无法访问输入文件,即使完成,也无法访问输出:
% docker build .
Sending build context to Docker daemon 5.632kB
Step 1/3 : FROM continuumio/miniconda3
---> 52daacd3dd5d
Step 2/3 : COPY . .
---> 2e8f439e6766
Step 3/3 : ENTRYPOINT ["python", "test.py"]
---> Running in 788c40568687
Removing intermediate container 788c40568687
---> 15e93a7e47ed
Successfully built 15e93a7e47ed
% docker run 15e93a7e47ed -i ../input.txt -o output.txt
Traceback (most recent call last):
File "test.py", line 19, in <module>
with open(args["in_file"]) as input_handle:
FileNotFoundError: [Errno 2] No such file or directory: '../input.txt'
然后,我可以尝试使用/inputs/
卷挂载输入文件的目录,这让我大部分时间都在那里(尽管为一个文件传递两个参数很烦人),但这似乎不起作用:
docker run --volume /path/to/input_dir/:/inputs 15e93a7e47ed -i input.txt -o output.txt
Traceback (most recent call last):
File "test.py", line 19, in <module>
with open(args["in_file"]) as input_handle:
FileNotFoundError: [Errno 2] No such file or directory: 'input.txt'
我显然不了解如何在这里装入卷(可能设置WORKDIR
会做很多这方面的工作),但是即使我可以装入卷,也不清楚如何将输出装载到装入的卷上,以便从容器外部访问它们。使用docker cp
有一些manual solutions可以做到这一点,但整个要点是多少要自动化
似乎Dockerfile中的ENTRYPOINT
或CMD
的字符串操作是不可能的。这样的方法似乎不可行:
ENTRYPOINT ["python", "test.py", "-i data/{i_arg}", "-o data/{o_arg}"]
在这里,我可以将一个文件写入已装入的卷/data/
上的某个变量文件名中,我可以在运行时替换该文件
如果您真的想在Docker中运行此脚本,那么通常需要的最少选项集是:
正如最后一条注释所指出的,这使得容器可以访问同一路径上的当前目录,但是如果要访问的文件位于父目录中,则无法访问该目录
从根本上说,Docker容器旨在与主机系统完全隔离。容器通常无法访问主机文件或主机设备,或查看主机uid到名称的映射。这种隔离导致了您注意到的许多事情:因为容器已经被隔离,所以您不需要虚拟环境来进行额外的隔离;由于容器是隔离的,
/input
是比/home/docker/src/my-project/data/input
更容易记住的目录名由于容器与主机隔离,因此需要访问的任何主机文件(输入或输出)都需要绑定装载到容器中。在我的示例中,我绑定挂载当前目录。在您的示例中,您有单独的
/input
和/output
容器目录,这两个目录都需要绑定装载到容器中没有一种方法可以让这变得更容易,并且仍然使用Docker;在主机数据上运行进程不是它的设计目的。您的所有示例都是Python,Linux和MacOS系统通常都预装了Python,因此您可能会发现在虚拟环境中运行脚本要简单得多
相关问题 更多 >
编程相关推荐