Docker Buildkit: Правильное использование --mount=type=cache
TL;DR Содержимое каталогов, смонтированных через
--mount=type=cache
, не сохраняется в docker-образе, поэтому кэшировать надо не целевые каталоги, а промежуточные.
В dockerfile:1.3
появилась возможность монтировать файловые системы во время построения образа, в том числе и в целях кэширования: можно кэшировать скачанные пакеты или промежуточные артефакты компиляции.
Например, пакет uwsgi
каждый раз компилируется при установке, и это время хочется сократить, закэшировав весь каталог с пакетами:
# syntax=docker/dockerfile:1.3
FROM python:3.10
RUN mkdir /pip-packages
RUN --mount=type=cache,target=/pip-packages \
pip install --target=/pip-packages uwsgi
> docker build -t pip-cache -f Dockerfile.pip .
# ...
[+] Building 14.6s (7/7) FINISHED
Выглядит, что все прошло успешно, но целевой каталог пуст:
> docker run -it --rm pip-cache ls -l /pip-packages
total 0
Что-то явно пошло не так. Во время сборки было видно, что uWSGI компилируется и устанавливается. Можно даже это проверить, добавив ls
в процесс сборки:
RUN --mount=type=cache,target=/pip-packages \
pip install --target=/pip-packages uwsgi \
&& ls -1 /pip-packages
> docker build -t pip-cache --progress=plain -f Dockerfile.pip .
<...>
#6 12.48 Successfully installed uwsgi-2.0.20
<...>
#6 12.91 __pycache__
#6 12.91 bin
#6 12.91 uWSGI-2.0.20.dist-info
#6 12.91 uwsgidecorators.py
#6 DONE 13.0s
<...>
Всё на месте. Но нет, в конечном образе снова пусто:
> docker run -it --rm pip-cache ls -l /pip-packages
total 0
А дело в том, что каталог /pip-packages
, находящийся внутри образа, и каталог, который указан в RUN --mount=type=cache,target=<dirname>
, разные. Попробуем что-нибудь положить в него заранее и посмотрим, как меняется его содержимое в процессе сборки:
RUN mkdir /pip-packages \
&& touch /pip-packages/foo \
&& ls -1 /pip-packages
RUN --mount=type=cache,target=/pip-packages \
ls -1 /pip-packages \
&& pip install --target=/pip-packages uwsgi \
&& ls -1 /pip-packages
RUN ls -1 /pip-packages
> docker build -t pip-cache --progress=plain -f Dockerfile.pip-track .
<...>
#5 [stage-0 2/4] RUN mkdir /pip-packages
&& touch /pip-packages/foo
&& ls -1 /pip-packages
#5 sha256:fb542<...>
#5 0.211 foo 👈1️⃣
#5 DONE 0.2s
#6 [stage-0 3/4] RUN --mount=type=cache,target=/pip-packages
ls -1 /pip-packages
&& pip install --target=/pip-packages uwsgi
&& ls -1 /pip-packages
#6 sha256:10ed6<...>
#6 0.292 __pycache__ 👈2️⃣
#6 0.292 bin
#6 0.292 uWSGI-2.0.20.dist-info
#6 0.292 uwsgidecorators.py
#6 2.802 Collecting uwsgi 🤔3️⃣
#6 3.189 Downloading uwsgi-2.0.20.tar.gz (804 kB)
#6 4.400 Building wheels for collected packages: uwsgi
<...>
#6 13.34 __pycache__ 👈4️⃣
#6 13.34 bin
#6 13.34 uWSGI-2.0.20.dist-info
#6 13.34 uwsgidecorators.py
#6 DONE 13.4s
#7 [stage-0 4/4] RUN ls -1 /pip-packages
#7 sha256:fb6f4<...>
#7 0.227 foo 👈5️⃣
#7 DONE 0.2s
<...>
- 1️⃣ файл
foo
успешно создан - 2️⃣ примонтировался каталог с результатами предыдущего
docker build
, и файлаfoo
там нет - 3️⃣ uWSGI снова скачивается, компилируется и устанавливается
- 4️⃣ в каталоге появилась обновленная сборка uWSGI
- 5️⃣ в каталоге остался только файл
foo
Это означает, что --mount=type=cache
работает только в контексте одной инструкции RUN
, заменяя директорию, созданную внутри образа RUN mkdir /pip-packages
, и затем возвращая ее обратно. При этом кэширование оказалось неэффективным, потому что pip
заново установил uWSGI с полной компиляцией.
В данном случае корректно было бы кэшировать не целевую директорию, а /root/.cache
, в которую pip
складывает все артефакты:
RUN --mount=type=cache,target=/root/.cache \
pip install --target=/pip-packages uwsgi
> docker build -t pip-cache -f Dockerfile.pip-right .
> docker run -it --rm pip-cache ls -1 /pip-packages
__pycache__
bin
uWSGI-2.0.20.dist-info
uwsgidecorators.py
Теперь все на месте, установленные пакеты никуда не делись.
Проверим эффективность кэширования, добавив пакет requests
:
RUN --mount=type=cache,target=/root/.cache \
pip install --target=/pip-packages uwsgi requests
👆
> docker build -t pip-cache --progress=plain -f Dockerfile.pip-right .
<...>
#6 6.297 Collecting uwsgi
#6 6.297 Using cached uWSGI-<...>.whl 👈
#6 6.561 Collecting requests
#6 6.980 Downloading requests-2.27.1-py2.py3-none-any.whl (63 kB)
<...>
pip
взял заранее собранный wheel-файл из /root/.cache
и установил из него готовый к использованию пакет.
Все исходники доступны на GitHub.
Яндекс.Лавка
До сих пор не могу привыкнуть к тому, насколько быстрой стала доставка Лавки у нас на районе. Буквально сегодняшний случай: Юля ...
Машина времени и пространства
Возможно, вы не задумывались, но машина времени должна перемещать человека не только во времени, но и в пространстве, учитывая п...
Today's Mission
Подписался на забавную страницу в инстаграме, @freakbait , там тебе каждый день дают своеобразные "миссии": развесить по город...
Безопасность персональных данных
Вчерашнее событие с публикацией слитых с Яндекс.Еды персональных данных напомнило о базовых правилах предоставления информации о...
Необязательные рекомендации
Все рекомендации насчет вашей личной жизни, здоровья, финансов, работы, бизнеса, направленные на широкую аудиторию, по умолчанию...
Хорошо там, где нас нет
Иногда хочется поменять что-то в своей жизни: переехать в другой город, страну, сменить работу, род занятий, увлечение, религию....