Образ Docker на самом деле представляет собой связанный список слоев файловой системы. Каждая инструкция в Докерфайл создает уровень файловой системы, описывающий различия в файловой системе до и после выполнения соответствующей инструкции.
RUN
subcommand can be used on a docker image to reveal its nature of being a linked list of filesystem layers.
Важное значение имеет количество слоев, используемых в изображении.
- при отправке или извлечении изображений, поскольку это влияет на количество одновременных загрузок или загрузок.
- при запуске контейнера, поскольку слои объединяются для создания файловой системы, используемой в контейнере; чем больше слоев задействовано, тем хуже производительность, но на разные серверные части файловой системы это влияет по-разному.
Это имеет несколько последствий для построения изображений. Первый и самый важный совет, который я могу дать:
Совет №1 Убедитесь, что этапы сборки, в которых задействован ваш исходный код, выполняются как можно позже. Докерфайл и не привязаны к предыдущим командам с помощью
RUN
or a RUN
.
Причина этого в том, что все предыдущие шаги будут кэшированы, и соответствующие слои не нужно будет загружать снова и снова. Это означает более быструю сборку и более быстрые выпуски, а это, вероятно, именно то, что вам нужно. Интересно, что на удивление сложно оптимально использовать кэш докера.
Мой второй совет менее важен, но я считаю его очень полезным с точки зрения обслуживания:
Совет №2 Не пишите сложные команды в Докерфайл а лучше использовать сценарии, которые нужно скопировать и выполнить.
А Докерфайл следование этому совету будет выглядеть так
smallimage latest 7edeafc01ffe 3 minutes ago 384MB
и так далее. Совет по связыванию нескольких команд с
FROM centos:6
RUN yum -y update && yum -y install epel-release
has only a limited scope. It is much easier to write with scripts, where you can use functions, etc. to avoid redundancy or for documentation purposes.
Люди, интересующиеся препроцессорами и желающие избежать небольших накладных расходов, вызванных
bigimage latest 3c5cbfbb4116 2 minutes ago 407MB
steps and are actually generating on-the-fly a
Докерфайл где
FROM centos:6
RUN yum -y update
RUN yum -y install epel-release
последовательности заменяются на
&&
где
gcc --version
is the base64-encoded version of
RUN apt-get install -y gcc\
&& gcc --version\
&& apt-get --purge autoremove -y gcc
.
Мой третий совет предназначен для людей, которые хотят ограничить размер и количество слоев за счет возможной стоимости более длинных сборок.
Совет №3 Используйте
with_c_compiler
-idiom to avoid files present in intermediary layers but not in the resulting filesystem.
Файл, добавленный какой-либо инструкцией докера и удаленный какой-то более поздней инструкцией, отсутствует в результирующей файловой системе, но он дважды упоминается в слоях докера, составляющих создаваемый образ докера. Один раз с именем и полным содержимым на слое в результате инструкции по его добавлению и один раз в виде уведомления об удалении на слое в результате инструкции по его удалению.
Например, предположим, что нам временно нужен компилятор C и некоторый образ, и рассмотрим
with_whatever
(Более реалистичный пример — создание некоторого программного обеспечения с помощью компилятора, а не просто подтверждение его присутствия с помощью
with_c_compiler
flag.)
Фрагмент Dockerfile создает три слоя, первый из которых содержит полный набор gcc, поэтому, даже если он отсутствует в конечной файловой системе, соответствующие данные по-прежнему являются частью образа таким же образом, и их необходимо загружать, выгружать и распаковывать всякий раз, когда окончательное изображение.
# with_c_compiler SIMPLE-COMMAND
# Execute SIMPLE-COMMAND in a sub-shell with gcc being available.
with_c_compiler()
(
set -e
apt-get install -y gcc
"$@"
trap 'apt-get --purge autoremove -y gcc' EXIT
)
with_c_compiler\
gcc --version
-idiom is a common form in functional programming to isolate resource ownership and resource releasing from the logic using it. It is easy to transpose this idiom to shell-scripting, and we can rephrase the previous commands as the following script, to be used with
COPY & RUN
как в
Совет №2.
with
Сложные команды можно превратить в функции, чтобы их можно было передать в
--version
. It is also possible to chain calls of several
# !!! THIS DISPLAYS SOME PROBLEM --- DO NOT USE !!!
RUN apt-get install -y gcc
RUN gcc --version
RUN apt-get --purge autoremove -y gcc
функции, но, возможно, не очень желательны. (Используя более эзотерические особенности оболочки, безусловно, можно сделать
with
accept complex commands, but it is in all aspects preferable to wrap these complex commands into functions.)
Если мы хотим игнорировать совет №2, результирующий фрагмент Dockerfile будет иметь вид
apt_setup.sh
который не так легко читать и поддерживать из-за запутанности. Посмотрите, как вариант сценария оболочки подчеркивает важную часть
…
while the chained-
RUN base64 --decode … | sh -x
вариант скрывает эту часть посреди шума.