Dockerfile RUN 层与脚本

标签 docker docker-compose dockerfile containers docker-registry

Docker 版本 19.03.12,内部版本 48a66213fe

所以在 dockerfile 中,如果我有以下几行:

RUN yum install aaa \
        bbb \
        ccc && \
        <some cmd> && \
        <etc> && \
         <some cleanup> 

这是最佳实践吗?我应该保留yum部分与当我调用其他<命令/脚本>时分开?

如果我想要一个更干净(相对于可追踪)的 Dockerfile,如果我将这些行放入 .sh 脚本中,就可以调用该脚本(即 COPY 后跟 RUN 语句)。即使 .sh 脚本内部没有任何更改,构建步骤是否每次都会运行?** 在这里寻找一些问题。

我在想,无论什么包稳定,都有一个单独的 RUN <those packages>即在依赖/频繁更改的一层和行中,即可以使用用户定义的(docker 构建时 CLI 级别参数)将它们保留在单独的 RUN 层中(这样我可以有效地使用层缓存)。

想知道您是否认为保留一个更干净的 Dockerfile(调用 RUN some.sh)会比可跟踪的 Dockerfile(其中 Dockerfile 中列出了生成该镜像的所有内容)效率低。

谢谢。

最佳答案

就最终的图像文件系统而言,如果您RUN,您将不会注意到任何差异。直接命令,或 RUN一个脚本,或有多个 RUN命令。层数和命令字符串的大小实际上根本没有任何区别。

你能观察到什么?

  • 特别是在“经典”Docker 构建系统上,每个 RUN命令成为图像层。在您的示例中,您 RUN yum install && ... && <some cleanup> ;如果这被分成多个 RUN命令,那么未清理的内容将作为图像的一部分提交并占用空间,即使它在后面的层中被删除。

    “更多层”本身并不一定是坏事,除非您有太多层以至于达到了内部限制。这里唯一真正的缺点是创建一个包含您计划删除的内容的图层,在这种情况下,其空间仍将位于最终图像中。

  • 作为更具体的示例,存在一种偶尔的模式:镜像会安装一些仅用于开发的软件包,运行安装步骤,然后卸载这些软件包。基于 Alpine 的示例可能如下所示

    RUN apk add --virtual .build-deps \
          gcc make \
     && make \
     && make install \
     && apk del .build-deps
    

    在这种情况下,您必须在同一个 RUN 中运行“安装”和“卸载”命令;否则 Docker 将创建一个包含仅构建包的层。

    (多阶段构建可能是一种更简单的方法来实现需要仅构建工具的相同目标,但不将它们包含在最终镜像中。)

  • RUN 的实际文本命令在 docker history 中可见和类似的检查命令。

而且......就是这样。如果您认为将安装步骤保留在单独的脚本中更易于维护(也许您有某种方法可以在非 Docker 上下文中使用相同的脚本),那么就这样做吧。我通常会默认保留 RUN 中列出的步骤。命令,并且通常尝试使这些设置步骤尽可能轻量。

关于Dockerfile RUN 层与脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70883712/

相关文章:

postgresql - 为什么我在运行 top 时看到 postgres 进程,尽管它只在 Docker 内部运行?

node.js - 无法在 docker 机器上安装 npm 模块

docker - 暴露 Docker 端口的问题

docker - GitLab 自动开发 : Dockerfile build-args

node.js - Azure Node expressjs应用程序随机崩溃,没有错误

maven - spotify dockerfile-maven Dockerfile

Docker 链接容器作为构建参数

docker - 如何重新启动 Docker 容器/镜像/机器?

node.js - 将 node.js 移动到 docker 容器,收到无法文件模块错误

bash - Dockerfile 中需要冗余 eval $(opam env)