我正在用Rust开发一个API,并且正在用Docker管理环境,包括外部数据库。每次我对API代码进行更改时,货物都会重新构建,并且由于Docker没有缓存任何与ADD
语句有关的内容来将Rust目录复制到容器中,因此它会重新下载所有的包,这是一个相当漫长的过程,因为我使用的是Nickel。它似乎有很多依赖项。
有没有办法在运行cargo build
之前引入这些依赖项?至少这样,如果依赖项发生变化,它将只安装所需的,类似于Cargo在本地编译。
下面是我目前使用的Dockerfile:
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
这是我的货物
[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"] }
5条答案
按热度按时间nnt7mjpx1#
如果源代码没有改变,Docker会缓存从
ADD
(最好是COPY
)指令构建的层。你可以利用它,通过先复制Cargo.toml
,然后进行构建来缓存依赖项。但不幸的是,您需要构建一些东西,因此可以使用一个源文件和清单中的一个虚拟
lib
目标来完成构建:在Dockerfile中单独构建虚拟对象:
这一层的输出将被缓存,并安装所有依赖项,然后你可以继续添加剩下的代码(在同一个
Dockerfile
中):dummy
的东西是丑陋的,但它意味着你的正常构建将是快速的,因为它来自缓存层,当你改变Cargo.toml
中的依赖关系时,Docker将拿起它并构建一个具有更新的依赖关系的新层。bq9c1y662#
这个问题到现在已经有一年半的历史了。仍然没有
cargo build --deps-only
选项,但是我想我应该分享我的解决方案,它是相当轻量级的。你不需要修改你的任何主机文件来做到这一点:这将构建依赖项并缓存它们。稍后当你复制实际的源文件时(或者在我的例子中,使用
--volumes
),它将覆盖伪文件,所以伪文件完全是临时的。如果需要,你也可以在构建之后显式地使用rm
。wpx232ag3#
您也可以让建置失败,而不加入虚拟档案:
如果您想要优化构建,请不要忘记在这两个位置添加
--release
。dw1jzc5e4#
我对此做了一些深入研究,似乎最好的解决方案是分多个阶段进行。最长的一个阶段是初始索引下载。还要注意,依赖关系预构建步骤使
target/
的可预测性降低,因此为了得到更清晰的结果,删除它可能是有意义的。不过,它应该可以很好地用于开发/增量构建。我用alpine做了这个,但是它对任何其他的Rust基础都是一样的--只需要把系统包步骤改为另一个包管理器,比如
apt
。9avjhtql5#
您可以创建一个中间映像,并从它构建您的最终映像。例如:
使用
docker build -t mybaseimage .
建置docker build -t finalimage .
这样,只会重新构建mybase映像