Search code examples
dockerdockerfile

DockerFile one-line vs multi-line instruction


To my knowledge of the way docker build works is that for each line of instruction, it creates a separate image/layer. However, it is very efficient in managing to reuse the layers or avoid rebuilding those layers if nothing has changed.

So does it matter if I put below instruction either on same line or multi-line? For convenience, I would prefer the single line option unless it is not an efficient option.

Multi-Line Instruction

RUN apt-get -y update
RUN apt-get -y install ...

Single-Line Instruction

RUN apt-get -y update && apt-get -y install

Solution

  • In this specific case it is important to put apt-get update and apt-get install together. More broadly, fewer layers is considered "better" but it almost never has a perceptible difference.

    In practice I tend to group together "related" commands into the same RUN command. If I need to configure and install a package from source, that can get grouped together, and even if I change make arguments I don't mind re-running configure. If I need to configure and install three packages, they'd go into separate RUN lines.

    The important difference in this specific apt-get example is around layer caching. Let's say your Dockerfile has

    FROM ubuntu:18.04
    RUN apt-get update
    RUN apt-get install package-a
    

    If you run docker build a second time, it will decide it's already run all three of these commands and the input hasn't changed, so it will run very quickly and you'll get an identical image out.

    Now you come back a day or two later and realize you were missing something, so you change

    FROM ubuntu:18.04
    RUN apt-get update
    RUN apt-get install package-a package-b
    

    When you run docker build again, Docker decides it's already run apt-get update and can jump straight to the apt-get install line. In this specific case you'll have trouble: Debian and Ubuntu update their repositories fairly frequently, and when they do the old versions of packages get deleted. So your apt-get update from two days ago points at a package that no longer exists, and your build will fail.

    You'll avoid this specific problem by always putting the two apt-get commands together in the same docker run line

    FROM ubuntu:18.04
    RUN apt-get update \
     && DEBIAN_FRONTEND=noninteractive \
        apt-get install --assume-yes --no-install-recommends \
          package-a \
          package-b