Обзор
При сборке образов Docker часто происходит неожиданное увеличение их объема. Большинство причин связаны с необоснованно созданными уровнями. В этой статье я поделюсь своим опытом оптимизации образов с помощью команды docker history, чтобы проверить "родословную" изображений и сделать их более легкими.
Используя эту команду, вы сможете точно определить, что делает изображение тяжелым, и создать более эффективные образы.
docker history: Проверка родословной изображения
docker history — это команда, которая показывает, как был создан конкретный образ и его состав. Вы можете видеть, какие уровни (layer) были созданы для каждой команды Dockerfile, а также время создания и размер каждого уровня.
Основное использование очень простое.
docker history [опции] <имя образа:тег>
Например, команда для проверки истории локального образа my-app:latest выглядит следующим образом.
docker history my-app:latest
В результате вы увидите уровни изображения в порядке от верхнего (новейшего) до базового (самого старого).
IMAGE CREATED CREATED BY SIZE
a6215f271958 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f28242cf608f6... 7.81MB
-
CREATED BY: Команда Dockerfile, которая создала этот уровень
-
SIZE: Объем, занимаемый этим уровнем
Полезный совет: Просмотр всей команды с флагом --no-trunc
По умолчанию вывод команды docker history может быть обрезан, если команда в столбце CREATED BY слишком длинная. В этом случае использование --no-trunc позволяет увидеть полную команду без обрезки, что необходимо для точного анализа.
docker history --no-trunc my-app:latest
Почему важен анализ уровней: реальный опыт оптимизации
Образы Docker по сути создают один уровень для каждой строки команды в Dockerfile. А каждый уровень представляет собой "изменение" относительно предыдущего уровня.
Проблема в том, что ненужное разделение уровней может привести к резкому увеличению объема изображения.
Пример: Ловушки COPY и RUN chown
При написании Dockerfile часто копируют файлы проекта в контейнер (COPY), а затем меняют права на эти файлы для определенного пользователя (например, appuser) с помощью (RUN chown).
Неэффективный метод: 2 уровня
Сначала я написал Dockerfile следующим образом.
# 1. Сначала копируем файлы (скопированы с правами root)
COPY . .
# 2. Изменение прав (выполняется отдельной командой)
RUN chown -R appuser:appgroup /app
После проверки истории собранного изображения с помощью docker history я обнаружил, что было создано два уровня.
IMAGE CREATED BY SIZE
<layer_id_2> /bin/sh -c chown -R appuser:appgroup /app 150MB <-- (Проблема!)
<layer_id_1> /bin/sh -c #(nop) COPY dir:abc in /app 150MB
Здесь возникает серьезная проблема.
-
Команда
COPY . .добавила файлы размером 150MB в уровень 1. -
Команда
RUN chownпросто скопировала файлы из уровня 1 размером 150MB, изменив только информацию о правах, и сохранила в уровень 2.
Содержимое файлов одно и то же, но один из них хранится с правами root, а другой с правами appuser, в разных уровнях. В результате общий объем изображения составляет 300MB (150MB + 150MB).
Эффективный метод: 1 уровень
Эту проблему можно легко решить, используя флаг --chown для команды COPY.
# 1. Копируем и указываем права одновременно
COPY --chown=appuser:appgroup . .
После внесения таких изменений в Dockerfile снова проверьте с помощью docker history.
IMAGE CREATED BY SIZE
<layer_id_1> /bin/sh -c #(nop) COPY --chown=appuser... dir:abc 150MB
Создан только один уровень, а общий объем изображения уменьшился до 150MB. Просто объединив две команды в одну, я сократил объем изображения почти вдвое.
Заключение
docker history — это не просто способ просмотра истории создания изображения, а основной инструмент анализа для оптимизации изображений.
После изменения Dockerfile полезно привычно запускать docker history --no-trunc, чтобы убедиться, что уровни созданы так, как задумано, и нет ли ненужных уровней, занимающих место. Эта маленькая привычка поможет создавать легкие и эффективные изображения.
Комментариев нет.