在 Docker 中优化货物构建时间

Optimising cargo build times in Docker

我正在使用 Rust 开发 API,并且正在管理环境,包括使用 Docker 的外部数据库。每次我对 API 代码进行更改时,cargo 都会重建,并且由于 Docker 不会缓存与 ADD 语句有关的任何内容以将 Rust 目录复制到容器中,它会重新下载所有包,这是一个相当漫长的过程,因为我使用的是 Nickel,它似乎有很多依赖项。

有没有办法在 运行 cargo build 之前引入这些依赖项?至少这样,如果依赖项发生变化,它只会安装所需的内容,类似于 Cargo 在本地编译。

这是我目前使用的Docker文件:

FROM ubuntu:xenial
RUN apt-get update && apt-get install curl build-essential ca-certificates file xutils-dev nmap -y
RUN mkdir /rust
WORKDIR /rust
RUN curl https://sh.rustup.rs -s >> rustup.sh
RUN chmod 755 /rust/rustup.sh
RUN ./rustup.sh -y
ENV PATH=/root/.cargo/bin:$PATH SSL_VERSION=1.0.2h
RUN rustup default 1.11.0
RUN curl https://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz -O && \
    tar -xzf openssl-$SSL_VERSION.tar.gz && \
    cd openssl-$SSL_VERSION && ./config && make depend && make install && \
    cd .. && rm -rf openssl-$SSL_VERSION*
ENV OPENSSL_LIB_DIR=/usr/local/ssl/lib \
    OPENSSL_INCLUDE_DIR=/usr/local/ssl/include \
    OPENSSL_STATIC=1
RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN cargo build
EXPOSE 20000
CMD ./target/debug/api

这是我的 Cargo.toml

[profile.dev]
debug = true

[package]
name = "api"
version = "0.0.1"
authors = ["Vignesh Sankaran <developer@ferndrop.com>"]

[dependencies]
nickel = "= 0.8.1"
mongodb = "= 0.1.6"
bson = "= 0.3.0"
uuid = { version = "= 0.3.1", features = ["v4"] }

您可以创建中间图像并从中构建最终图像。 例如:

FROM ubuntu:xenial
RUN apt-get update && apt-get install curl build-essential ca-certificates file xutils-dev nmap -y
RUN mkdir /rust
...

使用 docker build -t mybaseimage .

构建
FROM mybaseimage
RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN cargo build
EXPOSE 20000
CMD ./target/debug/api

docker build -t finalimage .

这样只重建 mybaseimage

Docker 会缓存从 ADD(最好是 COPY)指令构建的层,前提是源没有改变。您可以利用它并通过首先复制 Cargo.toml 并进行构建来缓存您的依赖项。

但不幸的是,您需要构建一些东西,因此您可以使用清单中的单个源文件和虚拟 lib 目标来完成它:

[lib]
name = "dummy"
path = "dummy.rs"

在您的 Docker 文件中单独构建虚拟机:

COPY Cargo.toml /app/Cargo.toml
COPY dummy.rs /app/dummy.rs
RUN cargo build --lib

这一层的输出将被缓存,安装了所有依赖项,然后您可以继续添加其余代码(在同一个 Dockerfile 中):

COPY /src/ app/src/
RUN cargo build

dummy 的东西很难看,但这意味着您的正常构建会很快,因为它来自缓存层,并且当您更改 Cargo.toml 中的依赖项时 Docker 将拾取它并构建一个具有更新依赖项的新层。

除了添加虚拟文件,您还可以让构建失败:

RUN cargo build || true
COPY ...
RUN cargo build

如果您想要优化构建,请不要忘记将 --release 添加到这两个地方。

这个问题已经问了一年半了。仍然没有 cargo build --deps-only 选项,但我想我会分享我的解决方案,它相当轻巧。您无需修改​​任何主机文件即可执行此操作:

COPY Cargo.toml .
RUN mkdir src \
    && echo "// dummy file" > src/lib.rs \
    && cargo build

这将构建依赖项并缓存它们。稍后当您复制实际的源文件时(或者在我的例子中,使用 --volumes),它将覆盖虚拟文件,因此虚拟文件完全是临时的。如果需要,您也可以在构建后显式 rm 它。