如何使用Docker访问输出文件

时间:2018-05-15 14:20:02

标签: c++ 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"]

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

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

这些输入文件位于/home/user/tmp/的主机中。在原始存储库(repo/)中,可执行文件位于其根目录中,生成的输出文件保存在同一文件夹中(,它们看起来像repo/program并且repo/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放置相同。

2 个答案:

答案 0 :(得分:2)

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

因为你搭载:

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

将使用您的图片打开交互式shell,然后运行./program some-file.text some-other-file.txt,然后运行ls您会看到输出文件result.md作为program的兄弟。这是在你的挂载点之外,这就是你在主机上没有看到它的原因。

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

我通过docker runinfileoutfile为我的程序提供了2个参数,这两个参数都与作为工作目录的/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

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;
}

RES / in.txt:

hello
world

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

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

答案 1 :(得分:0)

我想发布我现在正在使用的Dockerfile,希望它对某些人有用。不需要为输出文件指定名称或路径。输出文件总是写在$PWD中。

FROM alpine:3.4

LABEL version="1.0"
LABEL description="some nice description"
LABEL maintainer="user@home.com"

RUN apk update && apk add \
  gcc \
  g++ \
  make \
  git \
  && git clone https://gitlab.com/myuser/myrepo.git \
  && cd myrepo \
  && make \
  && cp program /bin \
  && rm -r /myrepo \
  && apk del g++ make git

WORKDIR /tmp

ENTRYPOINT ["program"]

我只需要运行:

docker run --rm -v $PWD:/tmp image file1 file2

内部在映像中,工作目录为tmp,并且无法更改,这是传递给卷-v选项的目录。运行映像后,所有输出文件将保存在主机的相应工作目录中。