Очистите свои образы Docker, оставив ненужные инструменты

В этой короткой статье мы создаем образ в несколько этапов, чтобы значительно уменьшить размер нашего образа докера. В итоге у нас будет изображение, которое делает то же самое, но почти в 10 раз меньше по размеру! Мы делаем это, оставляя позади инструменты, которые мы используем для создания образа.

Сначала мы создадим Dockerfile для сборки образа «обычным» способом. Затем мы обновляем этот файл, используя дополнительный этап, оставляя ненужные артефакты. Наконец, мы продолжим оптимизацию, поэкспериментировав с различными образами докеров. Посмотрим, сколько жира мы сможем срезать; Давайте кодировать!

Прежде чем мы начнем

Мы используем много терминальных команд. Ознакомьтесь с этой статьей, если вы не знакомы.

Настраивать

Представьте, что мы создаем приложение, которому нужны географические данные. Open StreetMap предоставляет нам эти геоданные: через geofabrik.de мы можем скачать геоданные по странам в формате .osm.pbf. Затем мы можем использовать инструмент под названием Osmium, чтобы объединить эти файлы вместе. Представьте, что нам нужен только этот объединенный файл для передачи в наше приложение.

Подводя итог: нам нужно использовать curl (для загрузки) и osmium (для слияния) только один раз: когда мы получим объединенный файл, нам больше не нужны эти инструменты. В двухэтапной сборке мы загружаем эти инструменты на первом этапе, используем их там, а затем переносим только результат (объединенный файл) на следующий этап, оставляя инструменты позади.

Прежде чем мы увидим двухэтапную сборку, давайте посмотрим на «обычный» способ.

1. Нормальная сборка

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

FROM ubuntu:20.04
# BUNDLE LAYERS
RUN apt-get update -y && apt install -y --no-install-recommends \
  curl \
  osmium-tool \
 && rm -rf /var/lib/apt/lists/*
RUN mkdir /osmfiles \
 && mkdir /merged \
 && curl https://download.geofabrik.de/europe/monaco-latest.osm.pbf -o /osmfiles/monaco.osm.pbf \
 && curl https://download.geofabrik.de/europe/andorra-latest.osm.pbf -o /osmfiles/andorra.osm.pbf \
 && osmium merge /osmfiles/monaco.osm.pbf /osmfiles/andorra.osm.pbf -o /merged/merged.osm.pbf

Этот dockerfile делает именно то, что нам нужно: устанавливает curl и osmium, скачивает файлы и объединяет их. В итоге мы получаем объединенный файл, который находится в /merged.

Обратите внимание, что после получения объединенного файла мы ничего не делаем. В этой статье мы упростим этот файл dockerfile и не будем делать с ним какие-либо действия.

Давайте проверим размер этого изображения:

testimg:latest        a88a8848201b   16 seconds ago       96.9MB

Как видите, размер изображения составляет около 97 МБ. В следующей части мы обновим наш dockerfile несколькими этапами.

2. Реализация многоэтапной сборки

В предыдущем примере мы использовали наши инструменты сборки (curl и osmium) только один раз. После того, как они используются, они остаются в нашем образе. Аналогия: вы покупаете новую машину, но обнаруживаете, что все инструменты, которые использовались для сборки машины, все еще лежат в багажнике и занимают драгоценное место!

В этой части мы сосредоточимся на том, чтобы отказаться от инструментов, которые мы использовали для сборки автомобиля. Давайте проверим новый Dockerfile и пройдемся по коду.

FROM ubuntu:20.04 AS final
FROM ubuntu:20.04 as build
# BUNDLE LAYERS
RUN apt-get update -y && apt install -y --no-install-recommends \
  curl \
  osmium-tool \
 && rm -rf /var/lib/apt/lists/*
RUN mkdir /osmfiles \
 && mkdir /merged \
 && curl http://download.geofabrik.de/europe/monaco-latest.osm.pbf -o /osmfiles/monaco.osm.pbf \
 && curl http://download.geofabrik.de/europe/andorra-latest.osm.pbf -o /osmfiles/andorra.osm.pbf \
 && osmium merge /osmfiles/monaco.osm.pbf /osmfiles/andorra.osm.pbf -o /merged/merged.osm.pbf
FROM final
RUN mkdir /merged
COPY --from=build /merged /merged

Как видите, мы используем два этапа: один называется build, а другой называется final. Установите curl и osmium на нашу сборку. Используйте их для создания объединенного файла и, наконец, просто скопируйте папку merged на этап final.

Как только мы вводим FROM final, мы «входим» в нашу последнюю стадию, поэтому все, что после FROM final, происходит там. То же самое касается FROM ubuntu:20.04 as build в строке 2. Обратите внимание, что curl и osmium устанавливаются только на этапе сборки. Как только мы достигнем конца нашего файла dockerfile, мы сохраним только ту стадию, на которой мы находимся. сцена остается позади. Давайте проверим размер нашего нового контейнера:

testimgbetter:latest        7342ee3948e8   3 seconds ago    75.1MB

Наш новый образ 75 МБ: мы сэкономили более 20 МБ или чуть меньше 20 %, оставив инструменты, которые нам больше не нужны. Это уже очень хорошее улучшение. Давайте найдем, как мы можем оптимизировать больше.

3. Многоэтапный с меньшим конечным изображением

В предыдущей части мы использовали образ ubuntu:20.04 как для сборки, так и для финальной стадии. Для стадии сборки это довольно логично; здесь мы делаем сложные вещи: устанавливаем пакеты, загружаем материал, клонируем git, в других случаях, возможно, даже используем cmake или make для компиляции кода! Однако последний этап не обязательно должен быть таким умным, как этап сборки.

Идея этой части заключается в том, что вам нужно большое, насыщенное изображение, такое как ubuntu:20.04, для сложной стадии сборки. Затем мы можем скопировать результаты с этапа сборки на этап финальный, основанный на гораздо более простом изображении. В нашем случае мы можем использовать даже очень маленькое изображение, такое как Alpine. Немного подкорректируем наш dockerfile:

FROM alpine:3.14 AS final

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

testimgbetter                                                latest        8ad3278671e1   17 minutes ago   7.95MB

Мы перешли с 75 МБ на чуть менее 8 МБ: снижение составило почти 90 %!

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

Заключение

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

Примеры в этой статье довольно минимальны; оставив только curl и osmium. Есть примеры, когда я использовал более громоздкий этап сборки и сэкономил более 1,5 ГБ, увеличив размер изображения с 1,8 ГБ до 0,3 ГБпросто оставив артефакты, которые нам больше не нужны!

Я надеюсь, что эта статья была понятной, но если у вас есть предложения/пояснения, прокомментируйте, чтобы я мог внести улучшения. А пока ознакомьтесь с моими другими статьями на всевозможные темы, связанные с программированием, например:

Удачного кодирования!

— Майк

P.S. Нравится, что я делаю? "Подписывайтесь на меня"!