2016-08-30 2 views
18

Dockerfile.1 выполняет многократный RUN:Несколько RUN против однократного RUN в Dockerfile, что лучше?

FROM busybox 
RUN echo This is the A > a 
RUN echo This is the B > b 
RUN echo This is the C > c 

Dockerfile.2 присоединяется к ним:

FROM busybox 
RUN echo This is the A > a &&\ 
    echo This is the B > b &&\ 
    echo This is the C > c 

Каждый RUN создает слой, таким образом, я всегда считал, что меньше слоев лучше и, таким образом, Dockerfile.2 лучше.

Это, очевидно, верно, когда RUN удаляет что-то добавляется предыдущим RUN (т.е. yum install nano && yum clean all), но в тех случаях, когда каждый RUN добавляет что-то, есть несколько моментов, которые мы должны рассмотреть следующие вопросы:

  1. Layers предполагается, что просто добавьте diff выше предыдущего, поэтому, если более поздний слой не удалит что-то, добавленное в предыдущем, не должно быть большого дискового пространства, сохраняющего преимущество между обоими методами ...

  2. Слои вытаскиваются параллельно от Docker Hub , поэтому Dockerfile.1, хотя, вероятно, немного больше, теоретически будет загружаться быстрее.

  3. При добавлении 4-ое предложение (т.е. echo This is the D > d) и локально восстановление, Dockerfile.1 будет строить быстрее благодаря кэш, но Dockerfile.2 придется выполнить все 4 команды снова.

Итак, вопрос: Какой лучший способ сделать Dockerfile?

+1

Невозможно ответить в целом, так как это зависит от ситуации и использования изображения (оптимизируйте размер, скорость загрузки или скорость здания) – Henry

ответ

6

Я лично разбил слои на основе их потенциала для повторного использования в других изображениях и ожидаемого использования кеширования. Если у меня есть 4 изображения, все с одинаковым базовым изображением (например, debian), я могу собрать коллекцию общих утилит для большинства этих изображений в команду первого запуска, чтобы другие изображения извлекали выгоду из кеширования.

Далее я смотрю на любые компоненты, которые будут обновляться очень редко, возможно, только когда базовое изображение обновится и поместит их в файл Docker. К концу файла Docker я включаю любые команды, которые будут выполняться быстро и могут часто меняться, например. добавление пользователя с определенным UID узла или создание папок и изменение разрешений. Если контейнер включает в себя интерпретируемый код (например, JavaScript), который активно разрабатывается, он добавляется как можно дольше, так что перестройка запускает только одно изменение.

В каждой из этих групп изменений я консолидирую, насколько это возможно, чтобы свести к минимуму слои. Поэтому, если есть 4 разных папки исходного кода, они помещаются внутри одной папки, поэтому их можно добавить с помощью одной команды. Любой пакет, устанавливаемый из чего-то типа apt-get, объединяется в одно RUN, когда это возможно, чтобы минимизировать накладные расходы менеджера пакетов (обновление и очистка).

+0

Это кажется самым сбалансированным POV IMHO. – Yajo

1

Это зависит от того, как вы включаете в свои слои изображения.

Ключевой момент делится так много слоев, как это возможно:

Плохой пример:

Dockerfile.1

RUN yum install big-package && yum install package1 

Dockerfile.2

RUN yum install big-package && yum install package2 

Хороший пример:

Dockerfile.1

RUN yum install big-package 
RUN yum install package1 

Dockerfile.2

RUN yum install big-package 
RUN yum install package2 

Еще одно предложение является удаление не очень полезно, только если это происходит на том же слое, что и добавление/установка действия.

+0

Будут ли эти 2 действительно разделять 'RUN yum install big-package' из кеша? – Yajo

8

Официального ответ перечисленного в своих лучших практиках (официальные изображения должны придерживаться этих)

минимизировать количество слоя

Вам нужно найти баланс между читаемостью (и, таким образом, в долгосрочной перспективе ремонтопригодности) файла Docker и , минимизируя количество слоев, которые он использует. Будьте стратегически и осторожны о количестве слоев, которые вы используете.

С докер 1.10 COPY, ADD и RUN заявления добавить новый слой к изображению. Будьте осторожны при использовании этих утверждений. Попробуйте объединить команды в один оператор RUN. Отделите это, только если это необходимо для удобочитаемости.

Подробнее: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#/minimize-the-number-of-layers

Обновление: многоступенчатый в докер> 17,05

С многоступенчатой ​​сборки вы можете использовать несколько FROM заявления в вашем Dockerfile. Каждое заявление FROM представляет собой этап и может иметь свое собственное базовое изображение. На последнем этапе вы используете минимальное базовое изображение, например альпийское, копируете артефакты сборки с предыдущих этапов и устанавливаете требования времени выполнения. Конечным результатом этого этапа является ваш образ. Таким образом, здесь вы беспокоитесь о слоях, как описано выше.

Как обычно, докер имеет great docs на многоэтапных сборках. Вот краткий отрывок:

С многоэтапными сборками вы используете несколько операторов FROM в вашем файле Docker. Каждая инструкция FROM может использовать другую базу, и каждый из них начинает новый этап сборки. Вы можете выборочно копировать артефакты с одного этапа на другой, оставляя за собой все, что вы не хотите в конечном изображении.

Отличный блог об этом можно найти здесь: https://blog.alexellis.io/mutli-stage-docker-builds/

Чтобы ответить на ваши вопросы:

  1. Да, слои вроде сравнении. Я не думаю, что добавлены слои, если есть абсолютно нулевые изменения. Проблема в том, что как только вы устанавливаете/загружаете что-то в слой # 2, вы не можете удалить его в слое # 3. Поэтому, когда что-то написано на слое, размер изображения больше не может быть уменьшен, удалив его.

  2. Хотя слои можно вытаскивать параллельно, делая их потенциально более быстрыми, каждый слой, несомненно, увеличивает размер изображения, даже если они удаляют файлы.

  3. Да, кеширование полезно, если вы обновляете файл докеров. Но он работает в одном направлении. Если у вас 10 слоев, и вы меняете слой # 6, вам все равно придется перестроить все из уровня # 6- # 10. Поэтому не слишком часто, что это ускорит процесс сборки, но это гарантирует излишнее увеличение размера вашего изображения.


Благодаря @Mohan за напоминание мне, чтобы обновить этот ответ.

+0

Это уже устарело - см. Ответ ниже. – Mohan

+1

@Mohan Напоминание! Я обновил сообщение, чтобы помочь пользователям. –

5

Кажется, что ответы выше устарели. Примечания к документам:

До Докера 17.05, и даже больше, до Docker 1.10, было важно минимизировать количество слоев на вашем изображении. В следующих улучшений смягчили эту потребность:

[...]

Docker 17,05 и выше, добавить поддержку для многоступенчатой ​​сборки, которые позволяют копировать только артефакты, необходимые в конечное изображение. Это позволяет включать инструменты и отладочную информацию на этапах промежуточной сборки без увеличения размера окончательного изображения .

https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#minimize-the-number-of-layers

и

Обратите внимание, что этот пример также искусственно сжимает два запуска команд вместе с помощью оператора Bash & &, чтобы не создавать дополнительный слой в изображении. Это неустойчиво и трудно поддерживать.

https://docs.docker.com/engine/userguide/eng-image/multistage-build/

Лучшая практика, похоже, изменилась с использованием многоступенчатых строит и держа Dockerfile с читаемым.

+0

Хотя многоступенчатые сборки кажутся хорошим вариантом для сохранения баланса, фактическое исправление этого вопроса придет, когда опция 'docker image build --squash' выходит за пределы экспериментальной. – Yajo

+1

@Yajo - Я скептически отношусь к тому, что 'squash' проходит мимо экспериментального. Он имеет много трюков и только имеет смысл перед многоступенчатыми сборками. С многоступенчатыми сборками вам нужно только оптимизировать заключительный этап, который очень прост. –

+0

@Yajo Чтобы расширить это, только слои на последнем этапе имеют какое-то значение для размера конечного изображения. Поэтому, если вы разместите все ваши губбины-строители на более ранних этапах и на заключительном этапе просто установите пакеты и скопируйте файлы с более ранних этапов, все будет прекрасно работать, и сквош не нужен. – Mohan

Смежные вопросы