Docker上下文中使用的文件列表

时间:2017-07-16 17:48:03

标签: docker

让我们说我有一个包含多个项目的存储库:

Root
 ├── bar
 │   ├── Dockerfile
 │   └── index.js
 ├── baz
 │   ├── Dockerfile
 │   └── index.js
 ├── foo
 │   ├── Dockerfile
 │   └── index.js
 └── shared
     └── utils.js
     └── shared.js

FooBarBaz项目共享shared文件夹中的一些库。目前,我将根文件夹作为context发送,以构建这三个Docker镜像以包含shared文件夹。

为了增加构建时间并缩短Docker镜像的部署时间,我需要获得发送到这些图像的最小context大小。

为了做到这一点,我计划为每个将用作context的图像创建一个临时文件夹。事实是,我需要知道每个图像使用哪些共享文件。

在这个例子中,它非常简单,因为共享文件很少,项目也很少。但实际上,有数百个共享文件和大约20个项目,我不想检查哪些项目使用了哪些共享文件。

以下是我的Dockerfile

的示例
FROM node:boron

RUN mkdir /app
WORKDIR /app

COPY package.json package.json
RUN yarn

COPY . .

RUN yarn release

CMD node release/server.js

我用以下代码构建Docker镜像:

docker build -t foo:latest ..

请注意指向..文件夹的Root。这将导致所有共享文件发送到上下文,甚至是那些不需要的文件。

是否有一种简单的方法可以知道哪些文件被发送context到Docker,哪些不是?

5 个答案:

答案 0 :(得分:3)

在开始之前,让我澄清一些误解,并为新旧用户定义一些术语。首先, docker images 或多或少是容器配置的快照。从文件系统到网络配置的所有内容都包含在图像中,可用于快速创建所述图像的新实例(容器)。

容器正在运行特定图片的实例,这就是所有魔法发生的地方。 Docker容器可以被视为微型虚拟机,但与虚拟机不同,系统资源是一致共享的,并且具有VM不具备的一些其他功能。 You can get more information about this in another stack overflow post.

构建图片可以通过保存容器(docker commit *container* *repoTag*)或构建 Dockerfile 来完成,这是自动构建说明,就像您要使用自己更改容器。它还为最终用户提供了一个正在运行的" Transaction"使应用程序运行所需的所有命令

  

减少我的Docker镜像的构建时间

如果我错了,请纠正我,但似乎您正在尝试为每个新容器构建图像。仅需要Docker镜像来旋转容器。是的,构建它们确实需要一段时间,特别是对于dockerfiles,但是一旦构建,使用您想要的应用程序启动容器真的需要花费大量时间,这实际上就是您所需要的。同样, docker镜像是以前容器配置的保存状态,加载保存状态不会也不应该消耗大量时间,所以你真的不应该关注dockerfiles构建时间

~~~~~~~~~~~~~~~~~~~~~~~~~~

尽管如此,努力减少Dockerfiles构建时间和容器结束文件大小仍然是一个有效的问题并转向自动依赖项解决方案是一种常见的方法。事实上,I asked a similar question nearly 2 years ago,所以它可能拥有一些可以帮助这项努力的信息。 然而...

  

为了减少构建时间并缩短Docker镜像的部署时间,我需要获取发送到这些图像的最小上下文大小。

回答我之前问题的人Taco会回复

  

Docker不会为您提供无痛的构建。 Docker不知道你想要什么。

是的,如果Docker从一开始就知道你想要什么,那肯定不会那么麻烦但是事实仍然是 如果你的目标是你需要告诉它你想要什么建立最佳规模和最佳时间 。但是,有多种方法可以获得最佳构建时间和/或构建大小。

  • 一个明显明显的一个,正如Andreas Wederbrand在中提到的那样 这篇文章非常相同,您可以从之前获取应用程序日志 运行以验证它做什么或不需要什么。假设你确实构建了一个 通过将所有可能的依赖项转储到其中来实现项目应用程序 您可以系统地取出所有依赖项,运行应用程序,
    检查其日志中的失败,添加依赖项,检查输出
    区别。如果输出相同,则删除失败的依赖关系,
    否则保持依赖。

如果我在dockerfile中编写了这个特定的命令,它可能会有点像这样,假设容器是从linux系统构建的:

#ASSUMING LINUX CONTAINER!
...
WORKDIR path/to/place/project
RUN mkdir dependencyTemp
COPY path/to/project/and/dependencies/ .
#Next part is written in pseudo code for the time being
RUN move all dependencies to dependencyTemp \
   && run app and store state and logs\
   && while [$appState != running]; do {\
   add dependency to folder && run app and store state and logs \
   if [$logsOriginal == $logsNew]; then remove dependency from folder \
   else keep dependency && logsOriginal = logsNew fi}

然而,这是非常低效的,因为您在内部启动和停止应用程序以查找应用程序所需的依赖项,从而导致非常长的构建时间。没错,它会在某种程度上解决自己找到依赖项并减少一些大小的问题,但它可能无法在100%的时间内运行,并且可能需要更少的时间来找到运行应用程序所需的依赖项,而不是设计代码以逃避这种差距。

  • 另一个解决方案/替代方案,虽然更复杂,但是link containers via networking。网络容器仍然是一个 对我来说是挑战,但它在你想要的东西中是直截了当的 完成它。假设您旋转了3个容器,其中2个容器 项目,另一个是依赖容器。通过网络,一个 容器可以引用依赖项容器并获取与当前设置类似的所有必需依赖项。与您的不同,依赖项不在应用程序上,这意味着您的其他应用程序可以使用最小的大小和时间构建。

但是,如果依赖容器发生故障,那么其他应用程序也会崩溃,从长远来看可能不会产生稳定的系统。此外,每次需要添加新的依赖项或项目时,都必须停止并启动每个容器。

  • 最后,如果您的容器将在本地保存,您可以 看看volumes。卷是安装文件系统的一种很好的方式 到活动容器,所以容器内的应用程序可以 那些没有显式的参考文件。这转化为a 更优雅的docker build,因为所有依赖关系都可以合法地存在 "共享"无需明确包含在内。

由于它是实时挂载,您可以添加依赖项和文件来同时更新所有需要它们的应用程序作为额外奖励。但是,当您希望将项目扩展到本地系统之外并且受到本地篡改时,卷不能很好地工作。

~~~~~~~~~~~~~~~~~~

底线是docker无法为您自动解决依赖关系,并且它的变通方法太复杂和/或耗时,甚至无法远程考虑您所需的解决方案,因为如果您弄清楚它会更快并自己指定依赖项。如果你想自己出去制定策略,那么就去吧。

答案 1 :(得分:1)

知道docker镜像中的应用程序是否使用特定文件的唯一方法是了解应用程序或分析之前运行的日志。

我会提出另一种解决问题的方法。它将减少构建时间和图像大小,但不一定会部署时间。

您将为包含共享库的所有其他图像构建基本映像。

FROM node:boron
COPY shared /shared

并且

docker build -t erazihel/base:1.0 .

您应该将所有其他图像基于该图像

FROM erazihel/base:1.0

RUN mkdir /app
WORKDIR /app

COPY package.json package.json
RUN yarn
RUN yarn release

CMD node release/server.js

由于docker图像是分层的,因此基本映像只在每个部署服务器上存在一次,而每个新的docker映像使用的附加层非常小。由于共享库没有COPY/ADD,因此构建时间也应该减少。

由于以下所有图像都小得多,因此没有任何成本具有一个大的基本图像。事实上,你可能会节省空间。

答案 2 :(得分:1)

您可以使用inotify。它是一个内核功能,可以在文件系统级别上嗅探正在发生的事情。

应该是这样的:

使用此脚本inotify.sh(不要忘记chmod +x inotify.sh):

#!/bin/sh
DIRTOMONITOR=/src
apk add --update inotify-tools || $(apt-get update && apt-get install -y inotify-tools)
inotifywait -mr --timefmt '%H:%M' --format '%T %w %e %f' -e ACCESS $DIRTOMONITOR &
"$@"

运行您的应用程序,例如:

docker run \
  -v $(pwd)/inotify.sh:/inotify.sh \
  --entrypoint /inotify.sh \
  <your-image> \
  node server.js

Watches established.
12:34 /src/ ACCESS server.js             <---------
Server running at http://localhost:4000

每个读/写文件都将显示为ACCESS

答案 3 :(得分:1)

  • 使用共享文件构建基本映像。
  • 从该基本图像构建其他图像。

如果子图像中未使用“共享”文件,则该文件不属于共享文件夹。

通过使用共享文件构建基本映像,您可以在其自己的文件夹/上下文中运行每个映像的构建,而不会出现您提到的问题。

答案 4 :(得分:0)

可以在容器中使用

fuserlsof来监视打开的文件。

lsof不要求您指定TARGET FILENAME,以便更适合您的目的。有关lsof的使用,请参阅以下示例:linux-lsof-usage

如果您在使用lsof时遇到问题 - 可以通过在主机上将docker设置为抱怨模式来解决此问题: sudo aa-complain /etc/apparmor.d/docker

参考文献: How to use fuser and lsof