将货物依赖项缓存在Docker卷中

Mar*_*ark 3 compilation docker rust-cargo docker-volume

我正在Docker(rust:1.33.0)中构建一个Rust程序。

每次代码更改时,它都会重新编译(良好),同时也重新下载所有依赖项(不良)。

我以为我可以通过添加来缓存依赖项VOLUME ["/usr/local/cargo"]编辑我也尝试过CARGO_HOME没有运气这个目录。

我认为将其作为卷可以保留下载的依赖项,这些依赖项似乎位于此目录中。

但这没有用,每次仍会下载它们。为什么?


Docker文件

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"]
Run Code Online (Sandbox Code Playgroud)

刚建docker build .

货代

[package]
name = "mwe"
version = "0.1.0"
[dependencies]
log = { version = "0.4.6" }
Run Code Online (Sandbox Code Playgroud)

代码:你好世界

更改后第二次运行的输出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
Run Code Online (Sandbox Code Playgroud)

BMi*_*tch 6

Dockerfile中的一个卷在这里适得其反。这将在每个构建步骤以及运行容器时再次安装一个匿名卷。完成该步骤后,将在每个构建步骤中丢弃该卷,这意味着对于需要这些依赖项的任何其他步骤,您将需要再次下载全部内容。

为此的标准模型是分4个步骤复制您的依赖项规范,运行依赖项下载,复制您的代码,然后编译或运行您的代码。这样,泊坞窗就可以高效地缓存图层。我对铁锈或货物不甚了解,但我相信这样会:

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"]
Run Code Online (Sandbox Code Playgroud)

另一个选择是使用BuildKit(在18.09中可用)打开一些实验性功能,以便Docker将这些依赖项保存为类似于构建的命名卷的内容。该目录可以在各个版本之间重用,但永远不会添加到映像本身,从而使其对于诸如下载缓存之类的事情很有用。

# 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"]
Run Code Online (Sandbox Code Playgroud)

请注意,以上假设货物在/root/.cargo中缓存文件。您需要对此进行验证并进行适当调整。我也没有将mount语法与json exec语法混合在一起以了解该部分是否有效。您可以在此处阅读有关BuildKit实验功能的更多信息:https : //github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md

从18.09和更高版本中打开BuildKit就像export DOCKER_BUILDKIT=1从该shell运行构建一样简单。

  • 我得到了很多有用的答案,但我认为这是最有用的答案:首先要解释匿名卷为什么不起作用,建议“货物提取”,尤其是对于看起来将是一半的最佳解决方案而言一年,即使我今天无法正常工作。 (2认同)

β.ε*_*.βε 5

我会说,更好的解决方案是使用 docker多阶段构建,就像这里那里所指出的那样

通过这种方式,您可以为自己创建第一个映像,这将构建您的应用程序和依赖项,然后仅在第二个映像中使用第一个映像中的依赖项文件夹

这是受到您对@Jack Gore 的回答的评论以及上面链接的两个问题评论的启发。

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
Run Code Online (Sandbox Code Playgroud)

PS:只运行一次会减少你生成的层数;更多信息在这里