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

JoB*_*324 18 docker

我已经看到了RUN在a 中使用命令的两种不同方法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
...
Run Code Online (Sandbox Code Playgroud)

V2

每行多个命令

FROM ubuntu/latest
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
    apt-get -y install \
        php5-dev \
        libcurl4-openssl-dev
...
Run Code Online (Sandbox Code Playgroud)

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

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

Tho*_*zco 26

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

提交

这是一个例子:

# Dockerfile
FROM ubuntu/latest
RUN touch /commit1
RUN touch /commit2
Run Code Online (Sandbox Code Playgroud)

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

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

您需要了解的是,如果您将命令分组到一个RUN语句中,那么它们将在同一个容器中执行,并且将对应于单个提交.

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

高速缓存

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

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

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

经验法则

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

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

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

结论

在您的示例中,v2是正确的,并且v1是错误的(因为它对缓存起反作用apt-get update).

  • @hbogert 缓存考虑了父映像,因此除非映像历史严格相同,否则 Docker 不会在其他地方重用给定层。不过,您可以使用“docker build --no-cache”使整个缓存失效。 (2认同)