Зависимости Cache Cargo в томе Docker - PullRequest
0 голосов
/ 02 марта 2019

Я создаю программу Rust в Docker (rust:1.33.0).

Каждый раз, когда изменяется код, он перекомпилируется (хорошо), что также перезагружает все зависимости (плохо).

Я думал, что смогу кешировать зависимости, добавив VOLUME ["/usr/local/cargo"]. edit Я также безуспешно пытался переместить этот каталог с CARGO_HOME.

Я думал, что создание этого тома сохранит загруженные зависимости, которые, похоже, находятся в этом каталоге.

Но это не сработало, они все равно загружаются каждый раз.Почему?


Dockerfile

FROM rust:1.33.0

VOLUME ["/output", "/usr/local/cargo"]

RUN rustup default nightly-2019-01-29

COPY Cargo.toml .
COPY src/ ./src/

RUN ["cargo", "build", "-Z", "unstable-options", "--out-dir", "/output"]

Построен всего за docker build ..

Cargo.toml

[package]
name = "mwe"
version = "0.1.0"
[dependencies]
log = { version = "0.4.6" }

Код: просто приветworld

Вывод второго запуска после изменения main.rs:

...
Step 4/6 : COPY Cargo.toml .
---> Using cache
---> 97f180cb6ce2
Step 5/6 : COPY src/ ./src/
---> 835be1ea0541
Step 6/6 : RUN ["cargo", "build", "-Z", "unstable-options", "--out-dir", "/output"]
---> Running in 551299a42907
Updating crates.io index
Downloading crates ...
Downloaded log v0.4.6
Downloaded cfg-if v0.1.6
Compiling cfg-if v0.1.6
Compiling log v0.4.6
Compiling mwe v0.1.0 (/)
Finished dev [unoptimized + debuginfo] target(s) in 17.43s
Removing intermediate container 551299a42907
---> e4626da13204
Successfully built e4626da13204

Ответы [ 4 ]

0 голосов
/ 13 марта 2019

Я бы сказал, что лучшим решением было бы прибегнуть к докеру многоэтапная сборка , как указано здесь и там

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

. @ ответ Джека Гора и два комментария к выпуску, ссылки на которые приведены выше.

FROM rust:1.33.0 as dependencies

WORKDIR /usr/src/app

COPY Cargo.toml .

RUN rustup default nightly-2019-01-29 && \
    mkdir -p src && \
    echo "fn main() {}" > src/main.rs && \
    cargo build -Z unstable-options --out-dir /output

FROM rust:1.33.0 as application

# Those are the lines instructing this image to reuse the files 
# from the previous image that was aliased as "dependencies" 
COPY --from=dependencies /usr/src/app/Cargo.toml .
COPY --from=dependencies /usr/local/cargo /usr/local/cargo

COPY src/ src/

VOLUME /output

RUN rustup default nightly-2019-01-29  && \
    cargo build -Z unstable-options --out-dir /output

PS: только один прогон сократит количество создаваемых вами слоев;больше информации здесь

0 голосов
/ 09 марта 2019

EDIT2 : Вот обзор возможностей.Прокрутите вниз, чтобы найти исходный ответ.

  • Добавьте файлы Cargo, создайте поддельные main.rs / lib.rs, затем скомпилируйте зависимости.После этого удалите фальшивый источник и добавьте настоящие.[Кэширует зависимости, но несколько поддельных файлов с рабочими пространствами]
  • Добавьте файлы Cargo, создайте поддельные main.rs / lib.rs, затем скомпилируйте зависимости.После этого создайте новый слой с зависимостями и продолжайте оттуда.[Аналогично выше]
  • Внешнее подключение тома для каталога кеша.[Кэширует все, полагается на то, что вызывающая сторона передает --mount]
  • Используйте RUN --mount=type=cache,target=/the/path cargo build в Dockerfile в новых версиях Docker.[Кэширует все, кажется хорошим способом, но в настоящее время слишком новым, чтобы работать для меня.Исполняемый файл не является частью изображения]
  • Использование cargo-build-deps .[Может работать для некоторых, но не поддерживает рабочие пространства Cargo (пока)].
  • Ожидание Выпуск груза 2644 .[Есть желание добавить это в Cargo, но пока нет конкретного решения].
  • Использование VOLUME ["/the/path"] в Dockerfile НЕ работает , это только для каждого слоя (для каждой команды).

Примечание: можно установить CARGO_HOME и ENV CARGO_TARGET_DIR в Dockerfile, чтобы контролировать, куда идет кэш загрузки и скомпилированный вывод.

Также обратите внимание: cargo fetch может по крайней мере кэшироватьзагрузка зависимостей, но не компиляция.

Рабочие пространства Cargo страдают от необходимости вручную добавлять каждый файл Cargo, а для некоторых решений приходится создавать дюжину поддельных main.rs / lib.rs.Для проектов с одним файлом Cargo решения работают лучше.


Для моего конкретного случая мне нужно работать с кэшированием, добавив

ENV CARGO_HOME /code/dockerout/cargo
ENV CARGO_TARGET_DIR /code/dockerout/target

Где /code - этокаталог, в который я монтирую свой код.

Это смонтированный извне, а не из Dockerfile.

EDIT1 : я не понимал, почему это работает, но @ b.enoit.be и @BMitch выяснили, что это потому, что тома, объявленные в Dockerfile, живут только для одного слоя (одна команда).

0 голосов
/ 12 марта 2019

Объем внутри Dockerfile здесь контрпродуктивен.Это будет монтировать анонимный том на каждом этапе сборки, и снова при запуске контейнера.Том на каждом шаге сборки сбрасывается после его завершения, а это значит, что вам нужно будет снова загрузить все содержимое для любого другого шага, нуждающегося в этих зависимостях.

Стандартная модель для этого - скопировать вашу спецификацию зависимости,запустите загрузку зависимостей, скопируйте код, а затем скомпилируйте или запустите код, выполнив 4 отдельных шага.Это позволяет Docker эффективно кэшировать слои.Я не знаком с ржавчиной или грузом конкретно, но я думаю, что это будет выглядеть так:

FROM rust:1.33.0

RUN rustup default nightly-2019-01-29

COPY Cargo.toml .
RUN cargo fetch # this should download dependencies
COPY src/ ./src/

RUN ["cargo", "build", "-Z", "unstable-options", "--out-dir", "/output"]

Другой вариант - включить некоторые экспериментальные функции с помощью BuildKit (доступно в 18.09), чтобы докер сохранил эти зависимостив том, что похоже на именованный том для вашей сборки.Этот каталог можно повторно использовать в разных сборках, но он никогда не будет добавлен к самому образу, что делает его полезным для таких вещей, как кэш загрузки.

# syntax=docker/dockerfile:experimental
FROM rust:1.33.0

VOLUME ["/output", "/usr/local/cargo"]

RUN rustup default nightly-2019-01-29

COPY Cargo.toml .
COPY src/ ./src/

RUN --mount=type=cache,target=/root/.cargo \
    ["cargo", "build", "-Z", "unstable-options", "--out-dir", "/output"]

Обратите внимание, что в приведенном выше примере предполагается, что груз кэширует файлы в / root /.грузы.Вам нужно будет проверить это и отрегулировать соответствующим образом.Я также не смешивал синтаксис монтирования с синтаксисом json exec, чтобы знать, работает ли эта часть.Вы можете прочитать больше об экспериментальных возможностях BuildKit здесь: https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md

Включение BuildKit с 18.09 и более новых версий так же просто, как export DOCKER_BUILDKIT=1, а затем запуск сборки из этой оболочки.

0 голосов
/ 03 марта 2019

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

Правила, которым Docker следует для кэширования слоя изображения, перечислены в официальной документации :

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

  • В большинстве случаев достаточно просто сравнить инструкцию в файле Docker с одним из дочерних изображений.Однако некоторые инструкции требуют более подробного изучения и объяснения.

  • Для инструкций ADD и COPY проверяется содержимое файла (-ов) на изображении и для каждого файла вычисляется контрольная сумма.,Время последнего изменения и последнего доступа к файлам не учитывается в этих контрольных суммах.Во время поиска в кэше контрольная сумма сравнивается с контрольной суммой в существующих изображениях.Если в файле (файлах) что-то изменилось, например, содержимое и метаданные, кэш-память становится недействительной.

  • Помимо команд ADD и COPY, проверка кеша не проверяетсяфайлы в контейнере для определения соответствия кэша.Например, при обработке команды RUN apt-get -y update файлы, обновленные в контейнере, не проверяются, чтобы определить, существует ли попадание в кэш.В этом случае для поиска совпадения используется только сама командная строка.

После того как кэш-память аннулирована, все последующие команды Dockerfile генерируют новые изображения, а кэш-память не используется.

Таким образом, проблема заключается в расположении команды COPY src/ ./src/ в Dockerfile.Всякий раз, когда происходит изменение в одном из ваших исходных файлов, кеш будет аннулирован, и все последующие команды не будут использовать кеш.Поэтому ваша команда cargo build не будет использовать кэш Docker.

Чтобы решить вашу проблему, вам нужно будет просто переупорядочить команды в файле Docker так:

FROM rust:1.33.0

RUN rustup default nightly-2019-01-29

COPY Cargo.toml .

RUN ["cargo", "build", "-Z", "unstable-options", "--out-dir", "/output"]

COPY src/ ./src/

Делая это таким образом, ваши зависимости будут переустанавливаться только при изменении в Cargo.toml.

Надеюсь, это поможет.

...