我已经看到了RUN
在a 中使用命令的两种不同方法Dockerfile
,我将其命名为v1和v2.
每行一个命令
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 ...
这两种方法都有其优点,使用缓存的不同方法最为明显.还有什么其他原因可以使用一种方法而不是另一种方法?
NB如果这个问题被认为过于模糊或对意见持开放态度,我会向社区的意愿屈服; 但是,我在这里发布它是因为我希望有很好的情况来分组命令,而不是好的情况 - 我想知道它们是什么.
要回答这个问题,首先必须了解"提交"的概念,以及Docker的缓存.最后,我提供了一个经验法则供您使用.
这是一个例子:
# Dockerfile FROM ubuntu/latest RUN touch /commit1 RUN touch /commit2
运行时docker build .
,docker会执行以下操作:
它从ubuntu/latest
图像中启动一个容器.
它touch /commit1
在容器中运行第一个command(),并创建一个新图像.
它重用#2中创建的图像来启动新容器.
它在第二touch /commit2
个容器中运行第二个command(),并创建一个新图像.
您需要了解的是,如果您将命令分组到一个RUN
语句中,那么它们将在同一个容器中执行,并且将对应于单个提交.
相反,如果在单个RUN
语句中断开命令,它们将不会在同一容器中运行,以后的命令将重用先前命令创建的映像.
运行时docker build .
,docker会重用先前创建的图像.换句话说,如果您编辑上述Dockerfile以包含RUN touch /commit3
在最后,并运行a docker build .
,那么Docker将重用#4中创建的映像.
这很重要,因为当你RUN apt-get update
在Dockerfile中包含它时,不能保证它会在几秒钟之前运行RUN apt-get install php5
.
如你所知,提交RUN apt-get update
可能是在一个月前创建的.APT缓存不再是最新的,但Docker仍在重用该提交.
通常更容易在一个RUN
命令中对所有内容进行分组,并在您希望开始利用缓存时开始分解(例如,加快构建过程).
执行此操作时,请确保不要分隔必须在彼此的特定时间间隔内运行的命令(例如,更新和升级).
一个好的做法是避免命令的副作用(即在安装所需的软件包后清理APT缓存).
在您的示例中,v2
是正确的,并且v1
是错误的(因为它对缓存起反作用apt-get update
).