Привет всем, первый пост на dev.to, желаю быть более активным в будущем!
Сегодня я хочу рассказать о небольшом совете, который я недавно придумал для уменьшения размера образов Docker, в моем случае я смог уменьшить размер в два раза!
Предположим, что вы работаете с таким языком, как Ruby или Python, даже если эти языки не компилируются, им часто нужны некоторые системные библиотеки для правильной работы, в частности, если вы работаете с базами данных (MySQL, SQLite, Postgres), вам нужно скомпилировать gem или библиотеку для конкретной архитектуры вашей машины.
В моем случае я работаю с Ruby и пытаюсь установить гем SQLite, который, к сожалению, требует системную библиотеку build-base
.
Вот проект, над которым я работаю:
Faenz Analytics
Поэтому я решил установить его, скомпилировать SQLite gem и удалить все, что мне больше не нужно, вот мой Dockerfile:
FROM ruby:3.0.4-alpine3.15
WORKDIR /faenz-analytics
RUN apk update &&
apk add make &&
apk add build-base && # this takes 200Mb of space!!
apk add sqlite-dev
# ...some instructions
RUN bundle install # installing Ruby gems
RUN apk del build-base
# ...some other instructions
Все просто, верно? Мы установили build-base
, скомпилировали и установили гемы и удалили build-base
, чтобы уменьшить размер изображения.
Проблема в том, что это не работает! Размер изображения такой же, как если бы мы не удалили build-base
. Давайте выясним, почему.
Мы написали три инструкции RUN
, каждая из которых генерирует слой, и эти слои объединяются Docker для создания конечного образа:
- первая
RUN
устанавливает системные библиотеки - второй
RUN
устанавливает gems/библиотеки Ruby или любого другого используемого вами языка - третий
RUN
удаляет системные библиотеки
поскольку мы установили системные библиотеки в один из слоев, они займут некоторое место и увеличат размер изображения, мы никак не сможем уменьшить размер изображения со следующими слоями.
Это как сумма без отрицательных чисел. Размер может только увеличиваться или оставаться неизменным от слоя к слою.
Что? Не сдавайтесь, мы справимся 🚀.
Вот решение: поместите эти операции в один слой!
FROM ruby:3.0.4-alpine3.15
WORKDIR /faenz-analytics
RUN apk update &&
apk add make &&
apk add sqlite-dev
# ...some instructions
RUN apk add build-base &&
bundle install &&
apk del build-base
# ...some other instructions
Группировка операций в одной инструкции RUN
позволяет Docker не тратить место на хранение build-base
в слое. Слой создается в конце инструкции, поэтому мы собираемся установить, использовать build-base
и предварительно удалить его, чтобы слой не содержал его вообще.
С помощью этого маленького совета размер моего изображения уменьшился с 400 Мб до 170 Мб, менее чем в два раза!
Если вы хотите утрировать с микро оптимизацией, вы можете применить то же решение к apk update
(или apt-get update
для образов debian/ubuntu), удалив кэш, созданный этой командой:
RUN apk update &&
add build-base &&
# install other dependencies here...
bundle install &&
apk del build-base &&
rm -rf /var/cache/apk &&
rm -rf tmp/cache
Я не эксперт по Docker, поэтому, если вы знаете лучшее решение или хотите поделиться похожими советами по уменьшению размера изображения, пожалуйста, оставьте комментарий, я весь внимание 🙏