Reputation: 867
In this official docker userguide one of the advise was minimizing the number of layers in Dockerfile.
I thought that it is decrease the total size of an image, but found something about the max limit of layers: Number of commands in Dockerfile
But it is very helpful to divide separate commands because of caching.
For example, a have a Dockerfile like this:
# https://hub.docker.com/_/php/
FROM php:5.5.23-fpm
RUN /scripts/base.sh \
&& /scripts/composer.sh \
&& /scripts/mbstring.sh \
&& /scripts/bcmath.sh \
&& /scripts/mcrypt.sh \
&& /scripts/sockets.sh \
&& /scripts/zip.sh \
&& /scripts/phpredis.sh \
&& /scripts/cleanup.sh
This is only one layer, so once been built, it will cache. But if I change the version of phpredis for example, each steps will build again.
Can I divide them into separate RUN instructions? That can you advise to me?
Upvotes: 3
Views: 3873
Reputation: 3124
The Dockerfile "design" mainly depends on your needs and what you want to balance. Minimising the number of layers is considered to be a best practice, but as you already mentioned, caching works by explicitly creating a new layer. The linked issue with a limited number of layers might become a problem with bigger Dockerfiles, but that also depends on the configured storage driver on your system. Your example Dockerfile (even with each script in its own RUN
statement) doesn't reach the limit of layers, so you don't need to worry.
That said, I suppose you didn't fully understand how the layer caching works (maybe you didn't post the complete Dockerfile?). Docker doesn't know which file system changes your scripts will produce during a RUN
statement. Consequently, when you re-run the Docker build with that exact Dockerfile, Docker won't run your scripts again. You mentioned as example that the phpredis version might change, but the Dockerfile doesn't reflect that variable. I suggest to declare some ENV
variable before the relevant RUN
statement. Example:
# https://hub.docker.com/_/php/
FROM php:5.5.23-fpm
RUN /scripts/base.sh \
&& /scripts/composer.sh \
&& /scripts/mbstring.sh \
&& /scripts/bcmath.sh \
&& /scripts/mcrypt.sh \
&& /scripts/sockets.sh \
&& /scripts/zip.sh \
&& /scripts/cleanup.sh
ENV PHPREDIS_VERSION=1.2.3
RUN /scripts/phpredis.sh \
&& /scripts/cleanup.sh
The phpredis.sh
should use the environment variable. Every time you change the ENV ...
statement, Docker will re-run every statement after that step, including your phpredis.sh
script.
Maybe the recently announced multi stage builds also help to re-design the way you keep your images tiny and reduces the need for the cleanup.sh
script.
Upvotes: 4
Reputation: 32196
if you have a second RUN containing
/scripts/phpredis.sh \
&& /scripts/cleanup.sh
the first RUN will be cached.
With recent docker versions like 1.13, you have
docker build --squash
see the doc
https://docs.docker.com/engine/reference/commandline/build/#options
Upvotes: 1