在Dockerfile中的单个RUN指令中指定多个UNIX命令的目的

时间:2019-12-30 18:56:17

标签: docker dockerfile

我注意到许多Dockerfiles试图通过一条UNIX指令中的多个RUN命令来减少指令数量。那有什么原因吗?

  • 下面两个Dockerfile之间的结果也有区别吗?

Dockerfile1

FROM ubuntu 
MAINTAINER demousr@example.com 

RUN apt-get update 
RUN apt-get install –y nginx 
CMD ["echo", "Image created"] 

Dockerfile2

FROM ubuntu 
MAINTAINER demousr@example.com 

RUN apt-get update && apt-get install –y nginx 
CMD ["echo", "Image created"] 

2 个答案:

答案 0 :(得分:3)

大致来说,Docker映像包含一些元数据和一层数组,并且通过添加容器层(读写)在这些层上构建运行中的容器,基础映像中的层是只读的在那个时候。

可以根据配置的驱动程序以不同方式将这些层存储在磁盘中。例如,以下来自官方Docker文档的图像说明了OverlayFS storage driver考虑​​在这些不同层中更改的文件的方式: OverlayFS

接下来,Dockerfile指令RUNCOPYADD创建层,并且Docker网站上提到的最佳实践特别建议将连续的RUN命令合并到单个RUN命令,以减少层数,从而减小最终图像的大小

https://docs.docker.com/develop/dev-best-practices/

  

[…]尝试通过最小化Dockerfile中单独的RUN命令的数量来减少映像中的层数。为此,您可以将多个命令合并到单个RUN行中,并使用Shell的机制将它们组合在一起。 […]

另请参阅:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

此外,在您的示例中:

RUN apt-get update -y -q
RUN apt-get install -y nginx

如果您对此docker build -t your-image-name .做过Dockerfile,然后过了一会儿编辑Dockerfile,在nginx之后添加了另一个软件包,然后再次执行docker build -t your-image-name .,由于Docker缓存机制,apt-get update -y -q将不会再次执行,因此APT缓存将过时。因此,这是合并两个RUN命令的另一个好处。

答案 1 :(得分:2)

除了节省空间外,还涉及正确性

考虑您的第一个dockerfile(与使用apt的类似debian的系统一起使用时,这是一个常见错误):

FROM ubuntu 
MAINTAINER demousr@example.com 

RUN apt-get update 
RUN apt-get install –y nginx 
CMD ["echo", "Image created"] 

如果两个或两个以上的图像遵循此模式,则缓存命中 可能会由于缓存的元数据而导致图像无法构建

  • 假设我建立了一个与几周前相似的图像
  • 现在我正在构建此图像。在RUN apt-get update行之前一直存在一个缓存
  • docker build将重用该缓存层(因为dockerfile和基本映像相同),直到RUN apt-get update
  • 运行RUN apt-get install行时,它将使用缓存的apt元数据(现在已过期几周,可能会出错)