DevGang
Авторизоваться

Создавайте образы Docker быстрее, используя кэш сборки

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

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

Понимание кэша сборки Docker

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

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

Советы по эффективному использованию кэша сборки Docker

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

Разумно упорядочивайте свои слои

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

FROM node:20
 
WORKDIR /app
COPY . .
RUN npm install
RUN npm build

Это неэффективный Dockerfile. Команда COPY аннулирует кеш для всех последующих слоев при каждом изменении файла в нашем проекте, заставляя наши команды npm install и npm build выполняться, даже если ни одна из наших зависимостей не изменилась. Мы можем улучшить это, если будем более внимательно подходить к копированию исходного кода и установке наших зависимостей:

FROM node:20
 
WORKDIR /app
COPY package.json package-lock.json /app/
RUN npm install
COPY . .
RUN npm build

Мы переместили копию исходного кода после команды npm install. Мы копируем наши package.json и package-lock.json, чтобы установить наши зависимости. Затем мы копируем исходный код и запускаем npm build.

Это небольшое изменение, которое может существенно повлиять на время сборки. Теперь вместо того, чтобы каждое изменение исходного кода заставляло нас переустанавливать наши зависимости, нам нужно делать это только при изменении файлов package.json или package-lock.json.

Сохраняйте ваши слои небольшими и сфокусированными

Чем меньше вещей в нашей сборке, тем быстрее может быть сборка образа Docker. Сохраняя наши слои небольшими и сфокусированными, мы можем уменьшить размер нашего изображения, уменьшить размер кэша и уменьшить количество вещей, которые могут сделать кеш недействительным.

Вот несколько советов и хитростей, которые имеют отношение к эффективному использованию кэша сборки Docker.

Избегайте копирования файлов, которые не нужны

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

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

FROM node:20
 
WORKDIR /app
COPY package.json package-lock.json /app/
RUN npm install
COPY . .
RUN npm build

Кроме того, наш docker build вызывается с полным контекстом нашего

.git/
node_modules/
app/
  index.js
  package.json
  package-lock.json
README.md
Dockerfile

Наша команда COPY выполняет копирование во всем контексте сборки; мы можем легко визуализировать контекст сборки с помощью нашего  debug build context feature. В этом примере мы копируем множество ненужных файлов и каталогов, таких как .git, node_modules и наш README.

Гораздо лучше быть более конкретным с нашей командой COPY:

COPY ./app /app

Теперь мы копируем только папку приложения в нашу сборку и конечный образ.

Используйте .dockerignore, чтобы исключить файлы и каталоги

Иногда бывает сложно точно определить, какие файлы и каталоги необходимы в нашем конечном образе. Таким образом, мы можем использовать файл .dockerignore для явного определения файлов, которые, как мы знаем, должны быть исключены. Для нашего примера выше мы могли бы создать файл .dockerignore со следующим содержимым:

.git
node_modules
README.md

Избегайте ненужных зависимостей от менеджеров пакетов

Обычно мы устанавливаем зависимости в наши образы из менеджеров пакетов, таких как npm, pip, apt, apk и т. д. для образов Node, Python, Debian и Alpine. Важно помнить о том, какие зависимости мы устанавливаем и нужны ли они в нашем окончательном образе. Иногда мы можем использовать некоторые приемы, например --no-install-recommends, чтобы избежать установки менеджерами пакетов дополнительных ненужных зависимостей.

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

Используйте кэш RUN для детального управления

Также известно как монтирование кэша BuildKit. Этот специализированный кеш позволяет нам выполнять более детальное кэширование между сборками. Вот пример кэша RUN в действии с образом Ubuntu:

FROM ubuntu
RUN rm -f /etc/apt/apt.conf.d/docker-clean
RUN \
    --mount=type=cache,target=/var/cache/apt \
    apt update && apt-get --no-install-recommends install -y gcc

Уменьшите общее количество слоев

Чем больше слоев у нас в изображении, тем больше слоев нам приходится перестраивать при аннулировании кэша и тем больше возможностей для аннулирования кэша. Ниже приведены несколько полезных советов по уменьшению количества слоев в нашем изображении.

Комбинируйте несколько команд запуска, где это возможно

Проблема с файлами Dockerfile номер один, которую мы обнаружили в Depot, - это несколько последовательных команд запуска. Чем больше мы комбинируем команд RUN, тем меньше слоев будет в нашем изображении. Например, если бы у нас был такой файл Dockerfile:

RUN some-command-that-creates-big-file
RUN some-command-that-removes-big-file

Это создаст ненужный слой в нашем изображении, слой, который изначально загрузил большой файл. Мы можем объединить эти две команды в одну команду RUN:

RUN some-command-that-creates-big-file && \
    some-command-that-removes-big-file

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

Будьте внимательны к базовым изображениям

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

Также стоит рассмотреть возможность использования базовых изображений меньшего размера для повышения производительности сборки и уменьшения конечного размера изображения. Например, если мы создаем приложение Node.js, мы можем использовать изображение node:alpine вместо изображения node. Это может уменьшить количество слоев и конечный размер изображения в нашем изображении.

Воспользуйтесь преимуществами многоступенчатой сборки

Многоступенчатая сборка позволяет нам иметь несколько инструкций FROM в нашем Dockerfile. Это может быть полезно для уменьшения количества слоев в нашем конечном изображении. Например, если мы создаем Node.js приложение, у нас может быть файл Docker, подобный этому:

FROM node:20-alpine AS build
 
WORKDIR /app
COPY package.json yarn.lock tsconfig.json ./
RUN yarn install --immutable
COPY src/ ./src/
RUN yarn build
 
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/node_modules /app/node_modules
COPY --from=build /app/dist /app/dist
CMD ["node", "./dist/index.js"]

Вывод

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

Эффективное использование кэша сборки Docker может ускорить вашу внутреннюю разработку, конвейеры CI/CD и развертывания. С помощью Depot мы еще раз ускорили решение этой проблемы, автоматически сохранив ваш кэш в распределенном кластере хранения, которым может пользоваться вся ваша команда и рабочие процессы CI. Благодаря еще более быстрому кэшированию и встроенным процессорам Intel и Arm для сборок с нулевой эмуляцией, мы видели, что пользователи Depot получают в 30 раз более быстрые сборки образов Docker.

Если вы хотите узнать больше о том, как Depot может помочь вам оптимизировать сборки образов Docker, подпишитесь на нашу бесплатную пробную версию.

Источник:

#Golang #Docker
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу