Docker RUN命令:何时组命令,什么时候不?

我已经看到在Dockerfile中使用RUN命令的两种截然不同的方法,我将命名为v1和v2。

V1

每行一个命令

 FROM ubuntu/latest ENV DEBIAN_FRONTEND noninteractive RUN apt-get update RUN apt-get -y install php5-dev RUN libcurl4-openssl-dev ... 

V2

每行多个命令

 FROM ubuntu/latest ENV DEBIAN_FRONTEND noninteractive RUN apt-get update && \ apt-get -y install \ php5-dev \ libcurl4-openssl-dev ... 

两种方法都有其优点,使用caching的方法是最明显的。 还有什么其他原因可以使用另一种方法呢?

如果这个问题被认为太模糊或有意见,我会鞠躬社会的意愿; 不过,我把它张贴在这里,因为我认为有好的情况下组合命令,好的情况下不 – 我想知道他们是什么。

要回答这个问题,你必须首先理解“提交”的概念,以及Docker的caching。 最后,我提供一个经验法则供您使用。

提交

这是一个例子:

 # Dockerfile FROM ubuntu/latest RUN touch /commit1 RUN touch /commit2 

当你运行docker build . ,docker工作如下:

  1. 它从ubuntu/latest映像启动一个容器。
  2. 它运行容器中的第一个命令( touch /commit1 ),并创build一个新的图像。
  3. 它会重用#2中创build的映像来启动一个新的容器。
  4. 它运行第二个容器中的第二个命令( touch /commit2 ),并创build一个新的图像。

你需要在这里理解的是,如果你在一个单独的RUN语句中分组命令,那么它们将全部在同一个容器中执行,并且将对应于单个提交。

相反,如果在单独的RUN语句中将命令分解,则它们将不会在同一个容器中运行,以后的命令将重新使用先前命令创build的映像。

高速caching

当你运行一个docker build . ,docker工人重新使用之前创build的图像。 换句话说,如果你编辑了前面提到的Dockerfile,在最后包含了RUN touch /commit3 ,并且运行了RUN touch /commit3 docker build . ,那么Doc​​ker会重用在#4中创build的映像。

这一点很重要,因为当你在你的Dockerfile中包含RUN apt-get update ,那么不能保证在RUN apt-get install php5之前运行它几秒钟。

对于你所知道的, RUN apt-get update的提交可能是在一个月前创build的。 APTcaching不再是最新的,但是Docker仍在重用这个提交。

经验法则

将所有内容分组在一个单独的RUN命令中通常会比较容易,并且当您想要开始利用caching(例如,加速构build过程)时,就可以开始分解它们了。

当你这样做的时候,只要确保你不要分开必须在一定时间间隔内运行的命令(例如更新和升级)。

一个好的做法是避免命令的副作用(例如,在安装所需的软件包后清理APTcaching)。

结论

在你的例子中, v2是正确的, v1是错误的(因为cachingapt-get update反作用)。