Образ Docker на самом деле является связанным списком слоев файловой системы. Каждая инструкция в Dockerfile создает уровень файловой системы, который описывает различия в файловой системе до и после выполнения соответствующей инструкции. docker inspect
Субкоманда может быть использована на Docker изображение , чтобы раскрыть его природу бытия связанного списка файловых слоев.
Количество слоев, используемых в изображении, важно
- при нажатии или вытягивании изображений, так как это влияет на количество одновременных загрузок или загрузок.
- при запуске контейнера, так как слои объединяются для создания файловой системы, используемой в контейнере; чем больше уровней задействовано, тем ниже производительность, но это по-разному влияет на различные бэкэнды файловой системы.
Это имеет несколько последствий для того, как изображения должны быть построены. Первый и самый важный совет, который я могу дать:
Совет № 1 Убедитесь, что шаги сборки, в которых задействован ваш исходный код, выполняются в Dockerfile как можно позже и не привязаны к предыдущим командам, использующим a &&
или a ;
.
Причина этого заключается в том, что все предыдущие шаги будут кэшироваться, и соответствующие слои не нужно будет загружать снова и снова. Это означает более быстрые сборки и более быстрые выпуски, что, вероятно, то, что вы хотите. Интересно, что на удивление сложно оптимально использовать докер кеш.
Мой второй совет менее важен, но я считаю его очень полезным с точки зрения обслуживания:
Совет № 2 Не пишите сложные команды в Dockerfile, а используйте сценарии, которые нужно скопировать и выполнить.
Dockerfile следуя этот совет будет выглядеть
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
COPY install_pacakges.sh /root/
RUN sh -x /root/install_packages.sh
и так далее. Совет по связыванию нескольких команд &&
имеет ограниченную область действия. Гораздо проще писать с помощью скриптов, где вы можете использовать функции и т. Д., Чтобы избежать избыточности или для целей документирования.
Люди, заинтересованные в препроцессорах и желающие избежать небольших накладных расходов, вызванных COPY
шагами, и на самом деле генерируют Dockerfile, где
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
последовательности заменяются
RUN base64 --decode … | sh -x
где …
- версия в кодировке base64 apt_setup.sh
.
Мой третий совет - для людей, которые хотят ограничить размер и количество слоев при возможной стоимости более длинных сборок.
Совет № 3 Используйте with
-idiom, чтобы избежать файлов, присутствующих в промежуточных слоях, но не в результирующей файловой системе.
Файл, добавленный некоторой инструкцией докера и удаленный более поздней инструкцией, отсутствует в результирующей файловой системе, но он упоминается два раза в слоях докера, составляющих изображение докера в процессе построения. Один раз с именем и полным содержимым в слое в результате добавления инструкции к нему, и один раз как уведомление об удалении в слое в результате удаления инструкции.
Например, предположим, что нам временно нужен компилятор C и некоторое изображение, и рассмотрим
# !!! THIS DISPLAYS SOME PROBLEM --- DO NOT USE !!!
RUN apt-get install -y gcc
RUN gcc --version
RUN apt-get --purge autoremove -y gcc
(Более реалистичным примером будет создание некоторого программного обеспечения с помощью компилятора, а не просто подтверждение его присутствия с --version
флагом.)
Фрагмент Dockerfile создает три слоя, первый из которых содержит полный пакет gcc, так что даже если он не присутствует в конечной файловой системе, соответствующие данные все еще остаются частью образа таким же образом, и их необходимо загружать, выгружать и распаковывать всякий раз, когда Окончательное изображение.
with
-Idiom является распространенной формой в функциональном программировании , чтобы изолировать собственность ресурсов и ресурсов высвобождения из логики его использования. Эту идиому легко перенести в сценарии оболочки, и мы можем перефразировать предыдущие команды как следующий сценарий, который будет использоваться COPY & RUN
как в Совете № 2.
# 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
Сложные команды можно превратить в функцию, чтобы их можно было передавать в with_c_compiler
. Также возможно связывать вызовы нескольких with_whatever
функций, но, возможно, не очень желательно. (Используя более эзотерические особенности оболочки, можно, конечно, with_c_compiler
принимать сложные команды принятия, но во всех аспектах предпочтительнее заключать эти сложные команды в функции.)
Если мы хотим игнорировать Совет № 2, полученный фрагмент Dockerfile будет
RUN apt-get install -y gcc\
&& gcc --version\
&& apt-get --purge autoremove -y gcc
который не так легко читать и поддерживать из-за запутывания. Посмотрите, как вариант сценария оболочки делает акцент на важной части, в gcc --version
то время как &&
вариант цепочки скрывает эту часть в середине шума.