【问题标题】:Building Dockerfile - Retaining files between intermediate containers构建 Dockerfile - 在中间容器之间保留文件
【发布时间】:2023-11-03 08:22:01
【问题描述】:

我正在使用keymetrics官方图片docker hub link here构建一个非常基本的容器

但这不是 node.js 或 pm2 的问题,而是 Docker 的问题,尤其是 docker build

Dockerfile (npm install) 中的一个步骤将节点包下拉到 node_modules 文件夹中——它可以工作。创建文件夹并下载文件并显示在构建输出中(如下)。

问题是,在该 RUN 命令完成后,中间容器被删除,我丢失了 node_modules 文件夹。

我的 dockerfile 有几个 ls -l 命令来阐明文件的情况。

唯一保留在工作目录 (/app) 中的文件是我使用 COPY 命令从主机复制的文件

这是我的 Dockerfile:

FROM keymetrics/pm2:latest

# Bundle APP files
COPY src src/
COPY package.json .
COPY pm2.json .

# Install app dependencies
ENV NPM_CONFIG_LOGLEVEL info
RUN pwd && ls -l /app && npm install && ls -l

# Show current folder structure in logs
RUN ls -l

CMD [ "pm2-docker", "start", "pm2.json" ]

构建命令: docker build -t localapps/pm2_test_app:0.0.4 .

构建输出

Sending build context to Docker daemon  13.31kB
Step 1/8 : FROM keymetrics/pm2:latest
 ---> 6aa333f957ec
Step 2/8 : COPY src src/
 ---> Using cache
 ---> 6b73b4463af5
Step 3/8 : COPY package.json .
 ---> Using cache
 ---> d27a2e75fdde
Step 4/8 : COPY pm2.json .
 ---> Using cache
 ---> 9864d9dd73a9
Step 5/8 : ENV NPM_CONFIG_LOGLEVEL info
 ---> Using cache
 ---> 9f711fe6bada
Step 6/8 : RUN pwd && ls -l /app && npm install && ls -l
 ---> Running in 668eb2e2c1e8
/app
total 12
-rw-r--r--    1 root     root           323 Nov  8 17:33 package.json
-rw-r--r--    1 root     root           123 Nov  8 16:59 pm2.json
drwxr-xr-x    2 root     root          4096 Nov  8 18:10 src
npm info it worked if it ends with ok
npm info using npm@5.5.1
npm info using node@v9.0.0
... <omitting useless npm logs> ...

added 8 packages in 2.001s
npm info ok
total 20
drwxr-xr-x   10 root     root          4096 Nov  8 19:49 node_modules
-rw-r--r--    1 root     root          1833 Nov  8 19:49 package-lock.json
-rw-r--r--    1 root     root           323 Nov  8 17:33 package.json
-rw-r--r--    1 root     root           123 Nov  8 16:59 pm2.json
drwxr-xr-x    2 root     root          4096 Nov  8 18:10 src
 ---> 0d749171a431
Removing intermediate container 668eb2e2c1e8
Step 7/8 : RUN ls -l
 ---> Running in fc2132121c96
total 12
-rw-r--r--    1 root     root           323 Nov  8 17:33 package.json
-rw-r--r--    1 root     root           123 Nov  8 16:59 pm2.json
drwxr-xr-x    2 root     root          4096 Nov  8 18:10 src
 ---> c689180648c9
Removing intermediate container fc2132121c96
Step 8/8 : CMD pm2-docker start pm2.json
 ---> Running in e70b2b89b3c8
 ---> 299c26f883e8
Removing intermediate container e70b2b89b3c8
Successfully built 299c26f883e8
Successfully tagged localapps/pm2_test_app:0.0.4

^^ 注意到node_modules 目录存在并且在步骤6 完成后可以继续吗?!

从构建输出证明npm install 运行并将包拉到适当的目录....

但是在第 7 步它就消失了?!此外,在最终图像上它消失了。应用程序不起作用,因为 node_modules 中的依赖项在最终图像中被破坏了。

为什么?如果没有 node_modules 目录,应用程序将无法运行,它们是依赖项。

我可以让这个工作的唯一方法是在构建之外运行npm_install,然后使用COPY 复制文件夹,这绝对不是一个有效的解决方案......但它是一个行之有效的解决方法。

我知道它使用了有意义的中间容器,但我怎样才能使在 RUN 命令中创建的文件保留到最后?

编辑: 进一步调查显示源图像 dockerfile found here 在其 dockerfile 中声明了 VOLUME - 这是我的问题所在吗?他们的示例表明,只需执行 npm install 即可开箱即用,但它不会,因为它会清除安装下载的文件。

【问题讨论】:

  • 修改 Dockerfile 中定义的卷内容的行为是相当不确定的,它取决于 docker 的版本,可能还取决于月相。最好修复源图像。

标签: node.js docker dockerfile pm2


【解决方案1】:

keymetrics/pm2 图像在其Dockerfile 中包含以下行:

VOLUME ["/app"]

这会破坏任何后续步骤和子图像修改/app 目录。来自docker's documentation

从 Dockerfile 中更改卷:如果任何构建步骤在声明后更改卷中的数据,这些更改将被丢弃。

您需要在不同的目录中运行您的构建,制作一个不包含该行的不同基础映像,或者说服上游作者删除该行。

我之前有blogged about the issues with volumes defined in Dockerfiles,这是其中一个问题。在他们的 Dockerfile 中包含这一行确实没有任何好处。

【讨论】:

  • 很好,谢谢——你知道为什么我使用COPY 命令明确复制的文件保留在卷中吗?那些没有被丢弃。
  • 这确实是一个未定义的场景,有些东西复制,有些东西没有。带有COPY 命令的单个文件似乎是可以复制的东西之一,但这也可能取决于 docker 的版本。我没有处理这个问题,而是删除了这条线并避免了所有潜在的问题。
  • 好的,我想我将只创建一个新的基础映像——您是否同意这可能是为我解决此问题的最简洁、最直接的方法?我仍会将此提交给 keymetrics,但这可能不会提供任何结果。
  • 这无疑是最快、最容易 fork 他们的 repo 并自己构建的方法。
  • 嘿,再次感谢 - 我创建了一个新来源,将 VOLUME 替换为 RUN mkdir /app 并且一切都在 100% 工作,非常感谢
【解决方案2】:

问题出在 pm2 的 docker 镜像的 new tags 中的 fixed

【讨论】: