Улучшение кеширования Docker
Эта статья является второй частью нашего исследования кеширования Docker - если вы еще этого не сделали, ознакомьтесь с первой частью, где мы представили слои Docker и механизм кэширования. Теперь давайте посмотрим на Docker Compose и некоторые проблемы при одновременном использовании Docker и Docker Compose.
Docker Compose - отличный инструмент для разработчиков
Мы использовали команды docker build
и docker run
для локальной сборки / запуска нашего приложения из образа Docker. Если бы у нас был проект с несколькими компонентами (например, клиентом и сервером), создание и запуск каждого из них может быстро стать громоздким и неэффективным. К счастью, есть Docker Compose - инструмент командной строки, предназначенный для запуска приложений с несколькими контейнерами.
Docker Compose полностью отделен от Docker, но внутренне использует движок Docker для управления построением и запуском нескольких контейнеров. Обзор Docker Compose и инструкции по установке можно найти на официальном сайте.
Хотя каждый компонент по-прежнему будет иметь свой собственный файл Dockerfile, описывающий, как должен быть построен образ, теперь у нас также есть файл docker-compose.yml
- дескриптор YAML всех контейнеров, которые необходимо запускать вместе, и его свойства времени выполнения.
Примечание. Вы можете получить более подробную информацию о том, как использовать Docker Compose во время разработки, здесь.
Давайте посмотрим, как docker-compose.yml
будет выглядеть в нашем примере (который довольно прост, поскольку у нас есть только один компонент):
Мы просто определяем службу с именем hello-world-react-docker
, устанавливаем контекст сборки в каталог, содержащий Dockerfile, и открываем соответствующие порты - как мы это делали при использовании docker run
для запуска контейнера.
Примечание. stdin_open: true
- это обходной путь для открытой ошибки в сценариях реакции 3.4.1 на момент написания, когда команда React npm start
завершается с кодом состояния 0
, как только сервер разработки запускается.
Теперь запуск docker-compose up
создаст и соответствующие изображения, и запустит их, поэтому, войдя в браузер, вы снова увидите знакомую домашнюю страницу React. Ура, мы запускаем приложение React из образа Docker с помощью Docker Compose!
Проблема: совместное использование кеша между сборками Docker и Docker Compose
Итак, у нас есть образец приложения - мы можем упаковать его как образ Docker и запускать где угодно. Мы можем использовать стандартные команды Docker (build
и run
) или использовать более удобные для разработчиков docker-compose
для создания и тестирования нашего приложения локально.
Однако вы, возможно, заметили небольшую проблему - хотя мы сначала создали образ Docker с помощью команды docker build
(и кэшировали все соответствующие слои), сборка с использованием docker-compose
привела к перестроению всего образа (поэтому нам пришлось ждать npm install
закончить на несколько минут). Когда мы запускали последующие сборки с помощью Docker Compose, кеширование работало так, как ожидалось, с быстрым циклом сборки.
Посмотрите на вывод ниже - хотя образ был ранее собран с помощью Docker, сборка с помощью Docker Compose не использует кэшированный слой и перестраивает все (как мы видим, была запущена медленная команда npm install
).
Таким образом, Docker и Docker Compose по отдельности ведут себя должным образом, повторно используя кэшированные слои из предыдущей сборки. Но при использовании обоих инструментов и переключении между ними кеширование, похоже, не работает.
Почему это проблема? Что ж, давайте представим, что у вас есть проект, содержащий несколько контейнерных компонентов, создание которых с нуля требует времени. Вы работаете над одним компонентом, но другие разработчики в вашей команде постоянно вносят изменения в другие. Каждый коммит создается на CI-сервере, поэтому вы можете его скачать.
Это почему?
Что ж, причина скрыта глубоко в базе кода Docker Compose. Docker Compose использует клиентскую библиотеку Docker Python для взаимодействия с движком Docker - в то время как команды Docker для этого изначально - различные реализации приводят к различным идентификаторам изображений для образов, созданных с помощью любого инструмента, что оказывает описанный выше эффект на кэшированный слой.
Проблема сообщается и обсуждается в нескольких тикетах в проектах Docker и Docker Compose:
Решение: введите BuildKit
Хотя нет соглашения о том, как исправить это в текущей версии движка Docker, существует простое решение, использующее все еще экспериментальный (но вскоре массовый) движок Docker BuildKit.
BuildKit предлагает долгожданную новую архитектуру и рефакторинг движка Docker, что должно привести к множеству улучшений в производительности, управлении хранилищем и безопасности, включая добавление согласованности кеша между сборками образов Docker и Docker Compose.
Мы ожидаем, что BuildKit станет по умолчанию в следующих версиях Docker, но пока, хотя он все еще экспериментальный, его можно включить, просто установив переменную среды DOCKER_BUILDKIT=1
.
Примечание. На момент написания BuildKit доступен только для контейнеров Linux.
Давайте перестроим наше приложение с помощью команды docker build
:
Вы увидите гораздо более простой встроенный вывод процесса сборки, характерный для BuildKit, вместе с таймингами для каждого слоя - как и раньше, команда npm install
занимает больше всего времени. Вы заметите, что весь образ создается с нуля - BuildKit имеет другую стратегию хранения слоев, поэтому слои, созданные с помощью устаревших механизмов, не могут быть повторно использованы в качестве кеша.
Повторение команды приведет к гораздо более быстрой сборке, поскольку все слои будут кэшироваться и повторно использоваться без перестройки. Вы можете увидеть результат CACHED
перед этапом сборки, на котором использовалось кеширование слоев, в приведенном ниже фрагменте:
А что насчет Docker Compose? Ранее мы видели, что Docker Compose не использовал повторно кэшированные слои, созданные с помощью команды docker build
- давайте посмотрим, как это изменилось.
Чтобы включить BuildKit для Docker Compose, ему нужна дополнительная переменная среды COMPOSE_DOCKER_CLI_BUILD=1
. Давайте перестроим приложение с помощью Docker Compose:
У-у-у! Сборка была молниеносной, так как все слои были повторно использованы, хотя это была первая сборка Docker Compose образа. Слои, созданные с помощью команды docker build
, были повторно использованы из кеша, как видно по тегу CACHE
в выходных данных выше.
В этой статье я попытался пролить свет на кеширование Docker и проблемы, связанные с использованием инструментов Docker и Docker Compose во время разработки. Помните, какой бы движок или инструмент вы не использовали, ключевым моментом является структурирование дескрипторов Dockerfile таким образом, чтобы они учитывали кеширование слоев - убедитесь, что вы копируете / запускаете наиболее часто изменяемые файлы или команды в нижней части Dockerfile, используя несколько COPY
, ADD
, и RUN
команд в зависимости от жизненного цикла компонентов, на которые имеется ссылка!