У нас есть следующий блок в нашем Dockerfile
:
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y groupinstall "Development Tools"
RUN yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Мне сказали, что мы должны объединить эти RUN
команды, чтобы сократить созданные слои докеров:
RUN yum -y update \
&& yum -y install epel-release \
&& yum -y groupinstall "Development Tools" \
&& yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Я очень новичок в докере и не уверен, что полностью понимаю различия между этими двумя версиями указания нескольких команд RUN. Когда можно объединить RUN
команды в одну и когда имеет смысл иметь несколько RUN
команд?
docker
dockerfile
alecxe
источник
источник
Ответы:
Образ Docker на самом деле является связанным списком слоев файловой системы. Каждая инструкция в Dockerfile создает уровень файловой системы, который описывает различия в файловой системе до и после выполнения соответствующей инструкции.
docker inspect
Субкоманда может быть использована на Docker изображение , чтобы раскрыть его природу бытия связанного списка файловых слоев.Количество слоев, используемых в изображении, важно
Это имеет несколько последствий для того, как изображения должны быть построены. Первый и самый важный совет, который я могу дать:
Причина этого заключается в том, что все предыдущие шаги будут кэшироваться, и соответствующие слои не нужно будет загружать снова и снова. Это означает более быстрые сборки и более быстрые выпуски, что, вероятно, то, что вы хотите. Интересно, что на удивление сложно оптимально использовать докер кеш.
Мой второй совет менее важен, но я считаю его очень полезным с точки зрения обслуживания:
Dockerfile следуя этот совет будет выглядеть
и так далее. Совет по связыванию нескольких команд
&&
имеет ограниченную область действия. Гораздо проще писать с помощью скриптов, где вы можете использовать функции и т. Д., Чтобы избежать избыточности или для целей документирования.Люди, заинтересованные в препроцессорах и желающие избежать небольших накладных расходов, вызванных
COPY
шагами, и на самом деле генерируют Dockerfile, гдепоследовательности заменяются
где
…
- версия в кодировке base64apt_setup.sh
.Мой третий совет - для людей, которые хотят ограничить размер и количество слоев при возможной стоимости более длинных сборок.
Файл, добавленный некоторой инструкцией докера и удаленный более поздней инструкцией, отсутствует в результирующей файловой системе, но он упоминается два раза в слоях докера, составляющих изображение докера в процессе построения. Один раз с именем и полным содержимым в слое в результате добавления инструкции к нему, и один раз как уведомление об удалении в слое в результате удаления инструкции.
Например, предположим, что нам временно нужен компилятор C и некоторое изображение, и рассмотрим
(Более реалистичным примером будет создание некоторого программного обеспечения с помощью компилятора, а не просто подтверждение его присутствия с
--version
флагом.)Фрагмент Dockerfile создает три слоя, первый из которых содержит полный пакет gcc, так что даже если он не присутствует в конечной файловой системе, соответствующие данные все еще остаются частью образа таким же образом, и их необходимо загружать, выгружать и распаковывать всякий раз, когда Окончательное изображение.
with
-Idiom является распространенной формой в функциональном программировании , чтобы изолировать собственность ресурсов и ресурсов высвобождения из логики его использования. Эту идиому легко перенести в сценарии оболочки, и мы можем перефразировать предыдущие команды как следующий сценарий, который будет использоватьсяCOPY & RUN
как в Совете № 2.Сложные команды можно превратить в функцию, чтобы их можно было передавать в
with_c_compiler
. Также возможно связывать вызовы несколькихwith_whatever
функций, но, возможно, не очень желательно. (Используя более эзотерические особенности оболочки, можно, конечно,with_c_compiler
принимать сложные команды принятия, но во всех аспектах предпочтительнее заключать эти сложные команды в функции.)Если мы хотим игнорировать Совет № 2, полученный фрагмент Dockerfile будет
который не так легко читать и поддерживать из-за запутывания. Посмотрите, как вариант сценария оболочки делает акцент на важной части, в
gcc --version
то время как&&
вариант цепочки скрывает эту часть в середине шума.источник
Каждая инструкция, которую вы создаете в своем Dockerfile, приводит к созданию нового слоя изображения. Каждый слой приносит дополнительные данные, которые не всегда являются частью результирующего изображения. Например, если вы добавляете файл в один слой, но позже удаляете его в другом слое, размер окончательного изображения будет включать в себя добавленный размер файла в виде специального «белого» файла, хотя вы его удалили.
Допустим, у вас есть следующий Dockerfile:
Полученный размер изображения будет
Напротив, с «похожим» Dockerfile:
Полученный размер изображения будет
Вы получите еще меньший размер, если очистите кэш yum одним оператором RUN.
Таким образом, вы хотите сохранить баланс между удобочитаемостью / простотой обслуживания и количеством слоев / размером изображения.
источник
Эти
RUN
заявления представляют собой , каждый слой. Представьте, что кто-то загружает пакет, устанавливает его и хочет удалить его. Если использовать триRUN
оператора, то размер изображения не будет уменьшаться, поскольку существуют отдельные слои. ЕслиRUN
выполнить все команды одним оператором, размер образа диска может быть уменьшен.источник