【问题标题】:Copy contents from host OS into Docker image without rebuilding image将内容从主机操作系统复制到 Docker 映像中而不重建映像
【发布时间】:2021-09-08 13:08:26
【问题描述】:

我正在构建一个新图像并将主机操作系统文件夹 D:\Programs\scrapy 中的内容复制到其中,如下所示:docker build . -t scrapy

Dockerfile

FROM mcr.microsoft.com/windows/servercore:ltsc2019
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

RUN mkdir root
RUN cd root
WORKDIR /root
RUN mkdir scrapy
COPY scrapy to /root/scrapy

    

现在,当我将新内容添加到主机操作系统文件夹“D:\Programs\scrapy”时,我还想将其添加到图像文件夹“root/scrapy”,但我不想构建一个全新的图像(这需要相当长的时间)。 那么如何保留现有图像并仅覆盖图像文件夹“root/scrapy”的内容。
另外:我不想每次运行时都复制新内容容器(所以不在运行时),我只想有一个单独的命令来向现有图像添加更多文件,然后在另一个时间基于该图像运行一个新容器。

我在这里检查过:How to update source code without rebuilding image(但不确定 OP 是否会尝试和我做同样的事情)

更新 1

检查What is the purpose of VOLUME in Dockerfiledocker --volume format for Windows

我尝试了以下命令,都导致错误:

docker:来自守护程序的错误响应:无效的卷规范:''。请参阅“docker run --help”。

其中<pathiused> 是例如D:/Programs/scrapy:/root/scrapy

docker run -v //D/Programs/scrapy:/root/scrapy scrapy

docker run -v scrapy:/root/scrapy scrapy

docker run -it -v //D/Programs/scrapy:/root/scrapy scrapy

docker run -it -v scrapy:/root/scrapy scrapy

根据@Makariy 的反馈使用cp 命令更新

docker images -a 给出:

REPOSITORY                             TAG        IMAGE ID       CREATED        SIZE
scrapy                                 latest     e35e03c8cbbd   29 hours ago   5.71GB
<none>                                 <none>     2089ad178feb   29 hours ago   5.71GB
<none>                                 <none>     6162a0bec2fc   29 hours ago   5.7GB
<none>                                 <none>     116a0c593544   29 hours ago   5.7GB
mcr.microsoft.com/windows/servercore   ltsc2019   d1724c2d9a84   5 weeks ago    5.7GB

我运行 docker run -it scrapy 然后 docker container ls 给出:

CONTAINER ID   IMAGE     COMMAND                    CREATED              STATUS              PORTS     NAMES
1fcda458a14c   scrapy    "c:\\windows\\system32…"   About a minute ago   Up About a minute             thirsty_bassi

如果我运行docker cp D:\Programs\scrapy scrapy:/root/scrapy,我会得到:

错误:没有这样的容器:路径:scrapy:\root

所以我在一个单独的 PowerShell 实例中运行 docker cp D:\Programs\scrapy thirsty_bassi:/root/scrapy,它在 PowerShell 中没有任何输出,所以我认为它应该做点什么。

但是在我的容器实例中,当我转到 /root/scrapy 文件夹时,我只能看到构建映像时已经添加的文件,而不是我想要添加的新文件。

另外,我想我在这里将文件添加到容器中,但是没有办法将它添加到图像中吗?不重建整个图像?

更新 2

我的文件夹结构:

D:\Programs
    Dockerfile
    \image_addons
    Dockerfile
        \scrapy

PS D:\Programs&gt;docker build . -t scrapybase

成功搭建95676d084e28
成功标记 scrapybase:latest

PS D:\Programs\image_addons&gt; docker build -t scrapy .

第 2/2 步:将 scrapy 复制到 /root/scrapy 复制失败:在构建上下文中找不到文件或被 .dockerignore 排除:stat to:文件不存在

Dockerfile A

FROM mcr.microsoft.com/windows/servercore:ltsc2019
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
WORKDIR /root/scrapy

Dockerfile B

FROM scrapybase
COPY scrapy to /root/scrapy

【问题讨论】:

  • Docker 镜像是静态的,如果你需要动态的话。你最好在运行时尝试volume

标签: image docker copy containers


【解决方案1】:

您也可以使用 docker cp 手动将文件从主机复制到正在运行的容器中

docker cp ./path/to/file containername:/another/path

Docs

【讨论】:

  • 能否请您使用我的实际路径提供完整的命令?我一直在尝试一些命令(例如docker cp D/Programs/scrapy scrapy:/root/scrapy)和docker cp ./D/Programs/scrapy scrapy:/root/scrapy,但收到类似“CreateFile D:\Programs\.D: The system cannot find the file specified.”之类的错误。
  • 试试 docker cp D:\Programs\scrapy scrapy:/root/scrapy
  • 谢谢。查看我尝试过的最新更新。可以看看吗?
  • 是的,如果不重建,您将无法向图像添加新文件
【解决方案2】:

如果你想要它又快又脏,请回答

docker run -it -v c:/programs/test:/root/test ubuntu:latest cat /root/test/myTestFile.txt

快速更新一个文件: 如果您不必构建代码(我不知道您使用的是什么语言),您可以使用初始代码构建一些基本映像,并且当您只想更改一个文件时(我再次假设您不这样做)不需要为此再次编译您的项目,否则由于compiled programming language 的性质,如果您这样做是不可能的):

FROM previous-version-image:latest
COPY myfile dest/to/file

那么因为你的CMDENTRYPOINT 是从前面的阶段保存的,所以不需要声明它们。 (如果你不记得使用docker history &lt;docker-image-name&gt; 来查看虚拟 dockerfile 以获取此阶段的图像)。

注意不要重复使用这种方法,否则你会得到一个非常大的图像,其中包含许多无用的层。仅用于快速测试和调试。

解释

通常人们将它用于 docker 容器上的前端开发,但基本思想仍然存在,您创建基本工作映像并安装依赖项和目录布局设置,最后一个 Dockerfile 命令是开发服务器启动命令。

示例:

Dockerfile:

# pull the base image
FROM node:slim

# set the working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# copy dependencies files
COPY package.json ./

COPY package-lock.json ./

# install app dependencies
RUN npm install

# add app
COPY . ./

# start development server
CMD ["npm", "start"]

启动命令:

docker run -it --rm \
-v ${PWD}:/app \       <mount current working directory in host to container in path /app>
-v /app/node_modules \ <or other dependency directory if exists>
-p 80:3000 \           <ports if needs exposing>
ps-container:dev

我不确定该用例是否 100% 适合您,因为它需要始终使用 bind-mount 挂载代码,并且在需要导出时必须将其导出为图像和源另一方面,它允许您进行快速更改,而无需等待每次添加新内容时构建图像并最终构建包含所有需要的最终图像。

问题提供的代码的更相关示例:

如您所见,主机上有一个包含一些文本的文件

使用 bind-mount 访问文件的命令:

docker run -it -v c:/programs/test:/root/test ubuntu:latest cat /root/test/myTestFile.txt

希望你能从我在这里提供的内容中找到适合你的东西。

感谢this tutorialthis example 提供示例和信息。

编辑:

假设您的原始 Dockerfile 如下所示:

FROM python:latest
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD python /app/app.py

这将在我们添加图层和更改 python 文件的基础上构建您的初始图像。 我们将使用的下一个 Dockerfile(我们称之为 Dockerfile.fix 文件)将复制我们想要更改的文件,而不是镜像中已经存在的文件

FROM previous-image-name
COPY app.py .

现在使用这个 Dockerfile 构建后,最终的图像 Dockerfile 看起来(有点)像这样:

FROM python:latest
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD python /app/app.py
FROM previous-image-name
COPY app.py .

每次我们想要更改文件时,我们都会使用第二个 Dockerfile

【讨论】:

  • 谢谢。快速而肮脏的似乎仅在运行时动态添加文件夹内容?如果是这样:我真正想要的是使用单个命令将文件夹内容添加到图像中,然后在单独的命令中运行基于该图像的新容器。我想要这个的原因是,每当我在主机操作系统中更新一个小文本文件时,我只想快速将它添加到基础映像中,而无需重建完整映像。这可能吗?
  • 更新答案,勾选“快速更新一个文件”部分?,它仍然需要您构建映像,但构建时间要短得多,只更改一个文件
  • 谢谢!我在哪里放置该代码,它是否不仅支持复制单个文件,还支持复制整个文件夹?
  • 是的,如果需要,您可以再次复制整个代码,并且您需要将其复制到 CMD 运行时命令期望的位置。你在容器中使用什么语言?
  • 对于菜鸟问题​​很抱歉!我使用图像创建一个容器来执行 Scrapy 命令。不确定“容器中的语言”是什么意思,我使用 Windows 映像并使用 Scrapy/Python 3.8 运行 Python 脚本。所以不需要任何编译,基本上我需要能够快速地将.py 脚本文件从主机操作系统复制到图像/容器,以便快速测试/更新单个脚本。现在你的命令建议看起来像 Docker 命令FROM scrapy:latest COPY myfile dest/to/file,那么我应该在主机操作系统的 Powershell 中执行它吗?在容器的命令提示符下?其他地方?
【解决方案3】:

如果不(至少部分地)重建 Docker 映像,就无法更改它。但是您不必重建全部,您只需重建复制您的scrapy 内容的图层即可。

您可以优化您的构建以拥有两个图像:

  • 第一个图像是您不想每次都重建的静态图像。我们就叫它scrapy-base吧。
  • 第二张也是最后一张图片基于第一张图片scrapy-base,仅用于复制您的动态scrapy 内容

scrapy-base 的 Dockerfile:

FROM mcr.microsoft.com/windows/servercore:ltsc2019
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

RUN mkdir root
RUN cd root
WORKDIR /root
RUN mkdir scrapy

然后像这样构建它:

docker build -t scrapy-base .

这个命令只需要运行一次。如果您只更改本地 scrapy 文件夹的内容,则无需构建此映像。 (如您所见,构建根本不使用它)

scrapy 的 Dockerfile:

FROM scrapy-base

COPY scrapy /root/scrapy

使用构建命令:

docker build -t scrapy .

第二个构建命令将重新使用之前的静态图像,并且只复制内容,而无需重新构建整个图像。即使有很多文件,它也应该很快。你不需要有一个正在运行的容器。

【讨论】:

  • 谢谢。请参阅更新 2,我收到错误:COPY failed: file not found in build context or excluded by .dockerignore: stat to: file does not exist,为什么?
  • 我的错,COPY 指令错了,应该是COPY scrapy /root/scrapy。我编辑了答案
【解决方案4】:

对于您的场景:

docker run -v D:/test:/root/test your-image

thread 中提供了许多有价值的详细信息

【讨论】:

  • 谢谢!我清理了我最初的帖子有点太多了,测试文件夹实际上位于主机操作系统上的 Programs 文件夹中。无论如何,我用我的尝试更新了我的帖子,其中之一是你的,也是基于你分享的链接,但都导致错误。你能看看吗?
猜你喜欢
  • 1970-01-01
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-06
相关资源
最近更新 更多