5 приёмов уменьшения образа Docker. Реальный пример уменьшения с 328MB до 56MB.

При работе с Docker и создании собственных образов вы можете быть удивлены тем, как много места они занимают на диске. В этой статье мы рассмотрим 5 способов уменьшения размера образов Docker. В качестве примера мы возьмем создание образа с socks-сервером Dante, но не будем устанавливать его из готовых пакетов, а скомпилируем вручную.

Начало. Решение «в лоб». Размер образа — 328MB.

Создадим простой файл конфигурации Dante danted.conf.

internal: 0.0.0.0 port = 1080
internal: :: port = 1080
external: eth0
errorlog: stderr
logoutput: stdout

socksmethod: username

user.privileged: root
user.unprivileged: nobody

client pass {
        from: 0/0 to: 0/0
        session.max: 200
        log: error connect disconnect
}

socks pass {
        from: 0/0 to: 0/0
        log: error connect disconnect
}

Также создадим Dockerfile будущего образа.

FROM debian:stable
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y wget gcc make
WORKDIR /root/
RUN wget ftp://www.inet.no/dante/files/dante-1.4.2.tar.gz
RUN tar zxvf dante-1.4.2.tar.gz
WORKDIR /root/dante-1.4.2
RUN ./configure
RUN make
RUN make install
COPY danted.conf /etc/
RUN useradd testuser
RUN echo "testuser:pass123pass" | chpasswd
RUN echo "precedence ::ffff:0:0/96  100" >> /etc/gai.conf
EXPOSE 1080
CMD sockd -f /etc/danted.conf

Соберем образ и увидим что он весит аж 328M.

sudo docker build -t localhost/debian-danted:testing .
sudo docker save -o danted.tar localhost/debian-danted:testing
du -h danted.tar
#328M    danted.tar

Так как же нам уменьшить размер образа?

Способ #1. Используем более компактные образы ОС. Размер образа — 260MB.

Если ваше приложение никак не привязано к ОС, имеет смысл рассмотреть альтернативные базовые образы, например alpine. Это очень компактный и популярный образ ОС для использования в Docker.
Если же ваше приложение каким либо образом завязано на ОС, например на Debian, можно использовать более компактный образ, такой как debian:stable-slim.

Изменим базовый образ в Dockerfile на debian:stable-slim.

FROM debian:stable-slim
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y wget gcc make
WORKDIR /root/
RUN wget ftp://www.inet.no/dante/files/dante-1.4.2.tar.gz
RUN tar zxvf dante-1.4.2.tar.gz
WORKDIR /root/dante-1.4.2
RUN ./configure
RUN make
RUN make install
COPY danted.conf /etc/
RUN useradd testuser
RUN echo "testuser:pass123pass" | chpasswd
RUN echo "precedence ::ffff:0:0/96  100" >> /etc/gai.conf
EXPOSE 1080
CMD sockd -f /etc/danted.conf
sudo docker build -t localhost/debian-danted:testing .
sudo docker save -o danted.tar localhost/debian-danted:testing
du -h danted.tar
#260M    danted.tar

Так-то лучше.

Способ #2. Не устанавливаем рекомендуемые пакеты. Размер образа — 253MB.

Передаём утилите apt параметр —no-install-recommends, а те пакеты, которые действительно нужны (libc-dev) перечисляем вручную.

FROM debian:stable-slim
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y --no-install-recommends wget gcc make libc-dev
WORKDIR /root/
RUN wget ftp://ftp.inet.no/pub/socks/dante-1.4.2.tar.gz
RUN tar zxvf dante-1.4.2.tar.gz
WORKDIR /root/dante-1.4.2
RUN ./configure
RUN make
RUN make install
COPY danted.conf /etc/
RUN useradd testuser
RUN echo "testuser:pass123pass" | chpasswd
RUN echo "precedence ::ffff:0:0/96  100" >> /etc/gai.conf
EXPOSE 1080
CMD sockd -f /etc/danted.conf
sudo docker build -t localhost/debian-danted:testing .
sudo docker save -o danted.tar localhost/debian-danted:testing
du -h danted.tar
#253M    danted.tar

Способ #3. Удаляем неиспользуемые файлы, но только в том же Docker-слое. Размер образа — 121MB.

По умолчанию Docker создаёт отдельный слой на каждую строку Dockerfile. В слое содержатся изменения внесенные относительно предыдущего слоя, а в случае с первой строкой, относительно базового образа. Если удалять неиспользуемые файлы в следующем слое, предыдущий слой так и останется неизменным — данные из него никуда не удалятся и останутся на диске. Это позволяет Docker не проматывать все строки заново при ребилде образа, но, в некоторых случаях, может значительно увеличить размер образа.

Переместим установку, компиляцию и удаление в один слой.

FROM debian:stable-slim
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends wget gcc make libc-dev && \
	wget ftp://ftp.inet.no/pub/socks/dante-1.4.2.tar.gz -P /root && cd /root && tar zxvf dante-1.4.2.tar.gz && \
	cd /root/dante-1.4.2 && ./configure && make && make install && \
	rm -r /root/dante* && apt-get -y remove wget gcc make libc-dev && apt-get -y autoremove --purge && apt-get -y clean
COPY danted.conf /etc/
RUN useradd testuser && echo "testuser:pass123pass" | chpasswd
RUN echo "precedence ::ffff:0:0/96  100" >> /etc/gai.conf
EXPOSE 1080
CMD sockd -f /etc/danted.conf
sudo docker build -t localhost/debian-danted:testing .
sudo docker save -o danted.tar localhost/debian-danted:testing
du -h danted.tar
#121M    danted.tar

Способ #4. Экспериментальный параметр squash. Размер образа — 120MB.

При билде образа мы можем использовать экспериментальный параметр squash. При использовании этого параметра все промежуточные слои «схлапываются» в один финальный слой. Финальный слой полностью отвязывается от промежуточных, которые могут быть удалены. Такое «схлапывание» позволяет сэкономить немного места.
Т.к. параметр экспериментальный, необходимо разрешить его в конфиге Docker /etc/docker/daemon.json.

{
  "experimental": true,
}

Перезапустим Docker.

sudo systemctl restart docker

Пересоберем образ с параметром squash.

sudo docker build --squash -t localhost/debian-danted:testing .
sudo docker save -o danted.tar localhost/debian-danted:testing
du -h danted.tar
#120M    danted.tar

Способ #5. Используем сжатие файловой системы btrfs. Размер образа — 56MB.

Хорошо. Мы сделали всё, чтобы уменьшить образ для его передачи по сети. Но если мы хотим хранить множество образов в локальном репозитории и делать это еще более компактно? Для этих целей мы можем использовать файловую систему со сжатием — btrfs.
Для примера создадим временный файл и посмотрим какое количество дискового пространства удастся сэкономить в этот раз.

sudo apt install btrfs-progs
sudo fallocate -l 2G /root/btrfs.tmp
sudo mkfs.btrfs /root/btrfs.tmp
sudo mount /root/btrfs.tmp /var/lib/docker -o compress-force=zstd

Подключим драйвер btrfs в конфиге Docker /etc/docker/daemon.json.

{
  "experimental": true,
  "storage-driver": "btrfs"
}

Перезапустим Docker, соберем образ и удалим лишнее.

sudo systemctl restart docker
sudo docker build --squash -t localhost/debian-danted:testing .
sudo docker run --restart=always -it -d --name danted localhost/debian-danted:testing
sudo docker image prune -a
sudo docker image rm debian:stable-slim

Посмотрим хорошо ли удалось сжать образ.

sudo apt install btrfs-compsize
sudo compsize /var/lib/docker/
Processed 7481 files, 2121 regular extents (3468 refs), 4906 inline.
Type       Perc     Disk Usage   Uncompressed Referenced
TOTAL       46%       56M         121M         192M
none       100%      643K         643K         879K
zstd        46%       56M         120M         191M

56MB. Так куда лучше.

Ах, да. Проверка.

#sudo docker run --restart=always -it -d --name danted localhost/debian-danted:testing
curl --proxy socks5://testuser:pass123pass@172.17.0.2:1080 innerlife.io

Здесь вы должны увидеть содержимое моего сайта, что значит что контейнер с Dante запущен и успешно работает.

1 комментарий к “5 приёмов уменьшения образа Docker. Реальный пример уменьшения с 328MB до 56MB.”

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *