Docker RUN命令:何时分组命令,何时不?

时间:2014-09-19 22:32:20

标签: docker

我在RUN中看到过使用Dockerfile命令的两种不同方法,我将其命名为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
...

这两种方法都有其优点,使用缓存的不同方法最为明显。还有什么其他原因可以使用一种方法而不是另一种方法?

N.B。如果这个问题被认为过于模糊或对意见持开放态度,我向社会的意愿屈服;但是,我在这里发布它是因为我希望有很好的情况来分组命令,而不是很好的情况 - 我想知道它们是什么。

1 个答案:

答案 0 :(得分:25)

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

提交

以下是一个例子:

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

当您运行docker build .时,docker会执行以下操作:

  1. ubuntu/latest图片启动容器。
  2. 它在容器中运行第一个命令(touch /commit1),并创建一个新图像。
  3. 它重用#2中创建的图像来启动新容器。
  4. 它在第二个容器中运行第二个命令(touch /commit2),并创建一个新图像。
  5. 您需要了解的是,如果您将命令分组到一个RUN语句中,那么它们将在同一个容器中执行,并且将对应于单个提交。

    相反,如果您在单个RUN语句中断开命令,它们将不会在同一容器中运行,以后的命令将重用先前命令创建的映像。

    缓存

    当您运行docker build .时,docker会重用之前创建的图像。换句话说,如果您编辑上述Dockerfile以在最后包含RUN touch /commit3,并运行docker build .,那么Doc​​ker将重用#4中创建的图像。

    这很重要,因为当您在Dockerfile中包含RUN apt-get update时,不能保证这将在RUN apt-get install php5之前运行几秒钟。

    大家知道,RUN apt-get update的提交可能是在一个月前创建的。 APT缓存不再是最新的,但Docker仍在重用该提交。

    经验法则

    通常更容易在一个RUN命令中对所有内容进行分组,并在您希望开始利用缓存时开始分解(例如,加快构建过程)。

    执行此操作时,请确保不要将必须在彼此的特定时间间隔内运行的命令(例如,更新和升级)分开。

    一个好的做法是避免命令的副作用(即在安装所需的软件包后清理APT缓存)。

    结论

    在您的示例中,v2是正确的,而v1是错误的(因为它会对缓存apt-get update产生反作用)。