在这个官方泊坞窗userguide中,其中一个建议是最小化Dockerfile中的层数。
我认为它减少了图片的总大小,但发现了有关图层最大限制的内容:Number of commands in Dockerfile
但由于缓存,分割单独的命令非常有用。
例如,有一个像这样的Dockerfile:
# 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
这只是一层,所以一旦构建,它就会缓存。但是,如果我改变phpredis的版本,例如,每个步骤将再次构建。
我可以将它们分成单独的RUN指令吗?那你可以告诉我吗?
答案 0 :(得分:4)
Dockerfile" design"主要取决于您的需求和您想要平衡的内容。最小化层数被认为是最佳实践,但正如您已经提到的,缓存通过显式创建新层来工作。具有有限数量的层的链接问题可能会成为更大的Dockerfiles的问题,但这也取决于系统上配置的存储驱动程序。您的示例Dockerfile(即使每个脚本都在其自己的RUN
语句中)也没有达到图层的限制,因此您不必担心。
那就是说,我想你还没有完全理解层缓存是如何工作的(也许你没有发布完整的Dockerfile?)。 Docker不知道脚本在RUN
语句中将产生哪些文件系统更改。因此,当您使用精确的Dockerfile重新运行Docker构建时,Docker不会再次运行您的脚本。您提到phpredis版本可能会更改的示例,但Dockerfile并未反映该变量。我建议在相关的ENV
语句之前声明一些RUN
变量。例如:
# 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
phpredis.sh
应该使用环境变量。每次更改ENV ...
语句时,Docker都会在该步骤之后重新运行每个语句,包括phpredis.sh
脚本。
也许最近宣布的multi stage builds也有助于重新设计保持图像微小的方式,并减少对cleanup.sh
脚本的需求。
答案 1 :(得分:1)
如果您有第二个RUN包含
/scripts/phpredis.sh \
&& /scripts/cleanup.sh
第一个RUN将被缓存。
最近的Docker版本如1.13,你有
docker build --squash
参见文档
https://docs.docker.com/engine/reference/commandline/build/#options