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.
Chippendales
Однажды в детстве я наткнулся на передачу про нечто под названием Chippendales. Я тогда особо не вникал, просто сразу захотел ее...
Абстракции и наследование в Си - стреляем по ногам красиво
TL;DR Иногда нет-нет да и хочется что-нибудь абстрагировать и обобщить в коде на Си. К примеру, хочешь ты принтануть содержимо...
Удел барабанщика
Наткнулся на ролик, где барабанщик Арьен ван Весенбек отрабатывает свою партию. Никогда так пристально не следил за ударными, и ...
Необязательные рекомендации
Все рекомендации насчет вашей личной жизни, здоровья, финансов, работы, бизнеса, направленные на широкую аудиторию, по умолчанию...
Немножко из книги Гоггинса
Читаю сейчас первую книгу Дэвида Гоггинса Can't Hurt Me , узнал пару интересных фактов. 💭 "Морские котики" - часто встречающее...
Привет с Большого Бодуна
Попытались тут посмотреть новую "Дюну", и вообще не поняли, в чем соль. Не то чтобы я целиком и полностью понял первый фильм, но...