首页 > 解决方案 > 如何使用 Docker 访问输出文件

问题描述

我正在编写一个 C++ 程序,并想在其上使用 Docker。Dockerfile如下所示:

FROM gcc:7.2.0
ENV MYP /repo
WORKDIR ${MYP}
COPY . ${MYP}

RUN /bin/sh -c 'make'
ENTRYPOINT ["./program"]
CMD ["file1", "file2"]

该程序需要两个输入文件(file1file2),并按如下方式构建和执行:

docker build -t image .
docker run -v /home/user/tmp/:/repo/dir image dir/file1 dir/file2

这些输入文件位于主机中的/home/user/tmp/. 在原始存储库 ( repo/) 中,可执行文件位于其根目录中,生成的输出文件保存在同一文件夹中(它们看起来像repo/programrepo/results.md)。

当我运行上述docker run命令时,我可以从标准输出中看到可执行文件正在正确读取输入文件并生成预期结果。但是,我希望写入的输出文件(由程序生成std::ofstream)也保存在挂载目录/home/user/tmp/中,但事实并非如此。

我怎样才能访问这个文件?有没有一种直接的方法可以使用 docker 卷机制来获取它?

Docker 版本为 18.04.0-ce,构建 3d479c0af6。

编辑

关于程序如何保存输出文件的相关代码result.md如下:

std::string filename ("result.md"); // in the actual code this name is not hard-coded and depends on intput, but it will not include / chars
std::ofstream output_file;
output_file.open(filename.data(), std::ios::out);
output_file << some_data << etc << std::endl;
...
output_file.close();

在实践中,程序运行为program file1 file2,并且输出将保存在工作目录中,无论其program放置位置是否相同。

标签: c++docker

解决方案


您需要确保将文件保存到已安装的目录中。现在,看起来您的文件正在作为已安装目录之外的程序的兄弟文件保存。

由于您使用以下方式安装:

docker run -v /home/user/tmp/:/repo/dir image dir/file1 dir/file2

/repo/dir是您将看到更改的唯一文件夹。但是,如果您将文件保存到/repo,它们将保存在那里,但运行后在主机系统上看不到。

考虑如何打开输出文件:

std::string filename ("result.md"); // in the actual code this name is not hard-coded and depends on intput, but it will not include / chars
std::ofstream output_file;
output_file.open(filename.data(), std::ios::out);
output_file << some_data << etc << std::endl;
...
output_file.close();

由于您将输出文件设置为"result.md"没有路径,因此它将作为程序的同级打开。

如果你要跑

docker run -it --rm --entrypoint=/bin/bash image

这将使用您的图像打开一个交互式外壳,然后运行./program some-file.text some-other-file.txt,然后运行ls您会看到输出文件result.md作为program. 那在您的挂载点之外,这就是为什么您在主机上看不到它的原因。


考虑这个程序。该程序将采用输入文件和输出位置。它将读取 的每一行infile并将其包装在<p>. /some是存储库目录。 /some/res/是要挂载到的文件夹/repo/res/

我通过 为我的程序提供了 2 个参数,这docker run两个参数都相对于哪个是工作目录。infileoutfile/repo

然后我的程序保存到outfile挂载点 ( ) 内的位置/repo/res/。完成后docker run/some/res/out.txt被填充。


文件夹结构:

.
├── Dockerfile
├── README.md
├── makefile
├── res
│   └── in.txt
└── test.cpp

命令运行:

docker build -t image .
docker run --rm -v ~/Desktop/some/res/:/repo/res/ image ./res/in.txt ./res/out.txt

Dockerfile:

FROM gcc:7.2.0
ENV MYP /repo
WORKDIR ${MYP}
COPY . ${MYP}

RUN /bin/sh -c 'make'
ENTRYPOINT ["./test"]
CMD ["file1", "file2"]

生成文件:

test: test.cpp
    g++ -o test test.cpp

.PHONY: clean

clean:
     rm -f test

测试.cpp:

#include <fstream>
#include <iostream>
#include <string>

int main(int argc, char **argv) {
    if (argc < 3) {
        std::cout << "Usage: test [infile] [outfile]" << std::endl;
        return 1;
    }

    std::cout << "All args" << std::endl;
    for (int i = 0; i < argc; i++) {
        std::cout << argv[i] << std::endl;
    }

    std::string line;
    std::ifstream infile(argv[1]);
    std::ofstream outfile(argv[2]);

    if (!(infile.is_open() && outfile.is_open())) {
        std::cerr << "Unable to open files" << std::endl;
        return 1;
    }

    while (getline(infile, line)) {
        outfile << "<p>" << line << "</p>" << std::endl;
    }
    outfile.close();

    return 0;
}

水库/in.txt:

hello
world

res/out.txt(运行命令后):

<p>hello</p>
<p>world</p>

推荐阅读