让我们说我有一个包含多个项目的存储库:
Root
├── bar
│ ├── Dockerfile
│ └── index.js
├── baz
│ ├── Dockerfile
│ └── index.js
├── foo
│ ├── Dockerfile
│ └── index.js
└── shared
└── utils.js
└── shared.js
Foo
,Bar
和Baz
项目共享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,哪些不是?
答案 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从一开始就知道你想要什么,那肯定不会那么麻烦但是事实仍然是 如果你的目标是你需要告诉它你想要什么建立最佳规模和最佳时间 。但是,有多种方法可以获得最佳构建时间和/或构建大小。
如果我在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%的时间内运行,并且可能需要更少的时间来找到运行应用程序所需的依赖项,而不是设计代码以逃避这种差距。
但是,如果依赖容器发生故障,那么其他应用程序也会崩溃,从长远来看可能不会产生稳定的系统。此外,每次需要添加新的依赖项或项目时,都必须停止并启动每个容器。
由于它是实时挂载,您可以添加依赖项和文件来同时更新所有需要它们的应用程序作为额外奖励。但是,当您希望将项目扩展到本地系统之外并且受到本地篡改时,卷不能很好地工作。
~~~~~~~~~~~~~~~~~~
底线是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)
fuser
和lsof
来监视打开的文件。
lsof
不要求您指定TARGET FILENAME,以便更适合您的目的。有关lsof
的使用,请参阅以下示例:linux-lsof-usage
如果您在使用lsof
时遇到问题 - 可以通过在主机上将docker设置为抱怨模式来解决此问题:
sudo aa-complain /etc/apparmor.d/docker