Поиск по сайту:

Понимание контекста сборки Docker (почему следует использовать Dockerignore)


Контекст сборки Docker относится к файлам и каталогам, которые будут доступны для ядра Docker при запуске docker build. Все, что не включено в контекст сборки, не будет доступно для команд в вашем Dockerfile.

Вы должны проверять использование docker build, чтобы контексты сборки были небольшими. Случайное включение ненужных файлов может привести к чрезмерно большому контексту сборки, что приведет к увеличению продолжительности сборки.

Что такое контекст сборки?

Вот простая команда docker build:

docker build . -t my-image:latest

Это создает образ Docker, используя Dockerfile, найденный в вашем рабочем каталоге. Полученное изображение будет помечено как my-image:latest, хотя эта деталь не важна для этого руководства.

Внутри вашего Dockerfile вы, скорее всего, будете использовать COPY для добавления файлов и папок в ваш образ:

FROM httpd:latest

COPY index.html /usr/local/apache2/htdocs/index.html
COPY css/ /usr/local/apache2/htdocs/css/

В этом примере копируется файл index.html и каталог css в ваш контейнер. На первый взгляд кажется, что оператор COPY просто ссылается на путь, разрешенный относительно вашего рабочего каталога.

Это не совсем так. COPY может получить доступ только к ресурсам, доступным в контексте сборки. В этом примере контекстом сборки является рабочий каталог, поэтому файлы и папки в нем доступны. По умолчанию Docker использует содержимое каталога, переданного в docker build, в качестве контекста сборки.

Почему используется контекст сборки?

Контекст сборки важен, поскольку Docker CLI и Docker Engine могут работать на разных компьютерах. Когда вы запускаете docker build, интерфейс командной строки отправляет файлы и папки для сборки в механизм Docker. Этот набор файлов и папок становится контекстом сборки.

Кроме того, не каждый контекст сборки так же прост, как повторное использование вашего рабочего каталога. Docker также поддерживает URL-адреса репозитория Git в качестве пути, указанного для docker build. В этом случае контекст сборки становится содержимым указанного репозитория.

Поведение контекста сборки по умолчанию «включить все» подходит для многих небольших репозиториев. Проблемы становятся очевидными, когда вы добавляете в свой рабочий каталог файлы, которые не используются вашим Dockerfile. Такие ресурсы, как готовые двоичные файлы, файлы документации и библиотеки зависимостей, будут включены в контекст сборки, даже если они избыточны.

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

Docker самостоятельно пытается свести к минимуму избыточное копирование. Серверная часть сборки BuildKit, используемая начиная с Docker 18.09, добавила поддержку добавочной передачи. Это означает, что Docker обычно нужно копировать только файлы, добавленные или измененные с момента вашей последней сборки. Он по-прежнему будет копировать всю партию в первой сборке.

Исключение ресурсов из контекста сборки

Чтобы избавиться от расточительного копирования навсегда, вы должны указать Docker, что он может исключить из контекста сборки. Начнем с создания Dockerfile:

FROM node:latest
WORKDIR /my-app
COPY package.json package.json
COPY package-lock.json package-lock.json
COPY src/ .
RUN npm install

Этот простой Dockerfile может использоваться приложением, написанным на Node.js. Программы Node.js используют npm в качестве менеджера пакетов. Пакеты устанавливаются в папку node_modules. Когда вы запускаете npm install локально, во время разработки пакеты будут загружены в папку node_modules в вашем рабочем каталоге.

Dockerfile запускает сам npm install для получения зависимостей. Это гарантирует, что изображение будет полностью автономным. Нет необходимости копировать в папку local node_modules, так как она не используется Dockerfile.

Несмотря на это, Docker по-прежнему будет включать папку node_modules в контекст сборки по умолчанию. Чтобы исключить его, создайте файл .dockerignore в своем рабочем каталоге. Синтаксис этого файла аналогичен .gitignore.

node_modules/

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

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

Другие проблемы с контекстом сборки

Если не использовать .dockerignore, могут возникнуть и другие проблемы. Dockerfile с этой строкой особенно проблематичен:

COPY . /my-app

Это скопирует все в ваш рабочий каталог. Это может показаться хорошей идеей, пока вы не поймете, что ваша история .git и все секретные файлы также попадут в ваш контейнер.

Копирование нефильтрованного контекста сборки также препятствует эффективной работе кэширования слоя Docker. Поскольку что-то в вашем рабочем каталоге, вероятно, будет меняться между сборками, Docker потребуется каждый раз запускать инструкцию COPY. Это создаст новый слой — и новые слои для любых последующих инструкций — даже если интересующие вас активы не изменились.

Сжатие контекста сборки

Вы можете сжать контекст сборки для дальнейшего повышения производительности сборки. Передайте флаг --compress в docker build, чтобы применить сжатие gzip. Сжатие происходит до отправки контекста демону Docker.

docker build . -t my-image:latest --compress

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

Заключение

Контекст сборки Docker определяет файлы, которые будут доступны для копирования в вашем Dockerfile. Контекст сборки копируется в демон Docker перед началом сборки.

Контексты сборки по умолчанию включают содержимое каталога или репозитория Git, которое вы передали в docker build. Вы можете исключить элементы из контекста сборки, создав файл .dockerignore. Это повышает эффективность за счет уменьшения объема избыточных данных, передаваемых демону Docker.