As the other answers already said, every command generates a layer and it's usually desirable to have the minimum amount of layers per image.
Each layer is only a set of differences from the layer before it. The layers are stacked on top of each other. When you create a new container, you add a new writable layer on top of the underlying layers.
This means that unless you're going to "squash" your image (which translates in using the --squash
option during the build), you end up having an image consuming space for nothing.
Example
# Dockerfile
FROM ubuntu
RUN apt-get update
RUN apt-get install -y --no-install-recommends dnsutils
RUN echo $( dig somewhere.nowhere )
RUN apt-get remove --purge dnsutils
RUN rm -rf /var/lib/apt/lists/*
COPY magicalScript.sh /
CMD /magicalScript.sh
In this case you'll have layers containing only overhead:
- 1 with cache coming from
apt-get update
- 1 with
dnsutils
installed,
- 1 containing the removal of the
dnsutils
- 1 containing the removal of the cache
The problem is that all those layers remain there and consume space for no reason at all.
Why squash
is not always a good solution? Because the layers represents a cache as well. And it's extremely useful when you need to perform a lot of builds and you need them to be as fast as possible.
Usually it's good practice to group together operation related the installation of new packages on the OS:
# Dockerfile
FROM ubuntu
RUN useradd docker \
&& mkdir /home/docker \
&& chown docker:docker /home/docker \
&& addgroup docker staff
RUN apt-get update \
&& apt-get install -y --no-install-recommends ed less locales vim-tiny wget ca-certificates fonts-texgyre \
&& rm -rf /var/lib/apt/lists/*
RUN echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \
&& locale-gen en_US.utf8 \
&& /usr/sbin/update-locale LANG=en_US.UTF-8
CMD ["mySpecialCommand"]