Главная

Tuesday, 18 August 2020

Оптимизация размеров образов Docker.

Всем привет.

Образы Docker могуть быть очень большими. Многие легко превышают 1 Гб в размере. Как они становятся такими? Должны ли они быть такими? Можем ли мы сделать их меньше, не жертвуя функциональностью?

Все дело в слоях. Образ Docker  похож на супер бигмак, где каждый инградиент этажности увеличивает его массу в килобайтах. Концепция слоев затрагивает различные низкоуровневые технические детали о вещах вроде корневой файловой системы (rootfs), механизма копирования при записи (copy-on-write) и каскадно-объединенного монтирования (union mount). Эта азбука достаточно хорошо раскрыта в другом месте, поэтому я не буду пересказывать ее здесь. Для Важным является понимание того, что каждая инструкция в Dockerfile приводит к созданию нового слоя образа. Бутерброд одним словом!

Зная, что образ - это не что иное, как коллекция других образов, можно прийти к очевидному выводу: размер образа равен сумме размеров образов, его составляющих.

Посмотрим на вывод команды docker history imagename:

$ docker history aformat

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT

d1ea947a9058        6 days ago                                                          119MB               merge sha256:f1fe0e102e804d28b6ae83ba4a3d1beb730eaea48aefc5b4510a3e03e5fe1c76 to sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e

<missing>           6 days ago          /bin/sh -c tree -L 1                            0B                  

<missing>           6 days ago          /bin/sh -c echo "******************* Hello w…   0B                  

<missing>           6 days ago          /bin/sh -c rm -rf /var/cache/apk/*              0B                  

<missing>           6 days ago          /bin/sh -c apk add tree                         0B                  

<missing>           6 days ago          /bin/sh -c apk add git && apk add npm && apk…   0B                  

<missing>           10 days ago         /bin/sh -c apk --no-cache add --update bash     0B                  

<missing>           10 days ago         /bin/sh -c #(nop)  MAINTAINER Nyukers <nyuke…   0B                  

<missing>           2 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B                  

<missing>           2 months ago        /bin/sh -c #(nop) ADD file:c92c248239f8c7b9b…   5.57MB           

Мы можем увидеть все слои образа aformat вместе с командами, которые привели к их созданию, и их размером.

Что же следует учесть для уменьшения размера образа Docker?

1. Выбираем только необходимую базу.

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

$ docker images

REPOSITORY   TAG      IMAGE ID       CREATED         VIRTUAL SIZE

scratch      latest   511136ea3c5a   13 months ago   0 B

busybox      latest   a9eb17255234   7 weeks ago     2.433 MB

debian       latest   e8d37d9e3476   4 days ago      85.18 MB

ubuntu       latest   ba5877dc9bec   4 days ago      192.7 MB

centos       latest   1a7dc42f78ba   2 weeks ago     236.4 MB

fedora       latest   88b42ffd1f7c   10 days ago     373.7 MB

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

Хотелось бы, чтобы размер образов отображался в хранилище Docker. Но сейчас, к сожалению, чтобы узнать размер, образ нужно скачать.

2. Группируйте однотипные команды.

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

FROM alpine:latest

RUN apk --no-cache add --update bash

RUN apk add git npm py-pip

RUN rm -rf /var/cache/apk/*

RUN chmod +x gitstart.sh

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

Мы можем исправить это, проведя небольшой рефакторинг нашего Dockerfile:

FROM alpine:latest

RUN apk --no-cache add --update bash &&\

apk add git npm py-pip &&\

rm -rf /var/cache/apk/* &&\

chmod +x gitstart.sh

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

3. «Схлопывайте» ваши образы.

Следует отметить, что Docker-engine начиная с версии 1.13 в экспериментальном режиме содержит возможность сборки уже сжатых образов. Для этого в команду сборки необходимо добавить параметр --squash, например:

docker build --squash -t aformat:latest .

Чтобы включить експериментальный режим docker-engine в Ubuntu 20.04 необходимо в конфигурационном файле /lib/systemd/system/docker.service добавить параметр --experimental=true.

Теперь строчка конфига выглядит так:

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --experimental=true

После изменения конфигурационного файла выполняем:

sudo systemctl daemon-reload

sudo systemctl restart docker

Теперь можно сразу собирать сжатые docker-образы командой:

docker build --squash -t  aformat:latest .

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

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

Все метаданные, обычно, сохраняемые вместе с образом, теряются в процессе запуска/эскпорта/импорта. Открываемые порты, переменные окружения, команда по умолчанию — все, что может быть объявлено в оригинальном образе, теряется.

Успехов.


No comments:

Post a Comment

А что вы думаете по этому поводу?