用于 Rust 应用程序的小而快的 Docker 映像
以下步骤将使用 Rocket “hello world” 应用程序作为演示。
Dockerfile 正常来说基本配置将是:
代码语言:javascript复制# Dockerfile.plain
ARG BASE_IMAGE=rust:1.52.1-slim-buster
FROM $BASE_IMAGE
WORKDIR app
COPY . .
RUN cargo build --release
CMD ["./target/release/hello"]
然后构建镜像
代码语言:javascript复制time docker build -f Dockerfile.plain -t hello:0.1.0 .
我们可以看到生成1.38GB 的镜像,构建时间为12 分钟。
代码语言:javascript复制# build
real 12m13.412s
user 0m0.135s
sys 0m0.095s
REPOSITORY TAG IMAGE ID CREATED SIZE
hello 0.1.0 ac4e1a72ba05 2 minutes ago 1.38GB
rust 1.52.1-slim-buster 61cb3c65a6ba 3 weeks ago 621MB
接下来使用多阶段构建和 cargo-chef 来使镜像尺寸更小
代码语言:javascript复制# Dockerfile.chef
ARG BASE_IMAGE=rust:1.52.1-slim-buster
FROM $BASE_IMAGE as planner
WORKDIR app
RUN cargo install cargo-chef --version 0.1.20
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM $BASE_IMAGE as cacher
WORKDIR app
RUN cargo install cargo-chef --version 0.1.20
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
FROM $BASE_IMAGE as builder
WORKDIR app
COPY . .
# Copy over the cached dependencies
COPY --from=cacher /app/target target
COPY --from=cacher $CARGO_HOME $CARGO_HOME
RUN cargo build --release
FROM $BASE_IMAGE
COPY --from=builder /app/target/release/hello /
CMD ["./hello"]
它会生成628MB的图像大小,最后一次由于缓存的原因构建只需要1 分钟左右。
代码语言:javascript复制# first test omitted
# second test
real 19m32.836s
user 0m0.188s
sys 0m0.088s
# third test
real 1m52.982s
user 0m0.060s
sys 0m0.088s
REPOSITORY TAG IMAGE ID CREATED SIZE
hello 0.1.0 ca1a9e1e5948 About a minute ago 628MB
更可以通过 distroless 或者 scratch 镜像来再加速构建,但是这里如果是 scratch 必须将工具链目标更改为 musl。
scratch:
代码语言:javascript复制# Dockerfile.musl
ARG BASE_IMAGE=rust:1.52.1-slim-buster
FROM $BASE_IMAGE as planner
WORKDIR app
RUN cargo install cargo-chef --version 0.1.20
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM $BASE_IMAGE as cacher
WORKDIR app
RUN cargo install cargo-chef --version 0.1.20
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
FROM $BASE_IMAGE as builder
WORKDIR app
COPY . .
# Copy over the cached dependencies
COPY --from=cacher /app/target target
COPY --from=cacher $CARGO_HOME $CARGO_HOME
# We need static linking for musl
RUN rustup target add x86_64-unknown-linux-musl
# `cargo build` doesn't work in static linking, need `cargo install`
RUN cargo install --target x86_64-unknown-linux-musl --path .
FROM scratch
COPY --from=builder /usr/local/cargo/bin/hello .
CMD ["./hello"]
结果:
代码语言:javascript复制# first test ommitted
# second test
real 9m22.049s
user 0m0.113s
sys 0m0.103s
# third test
real 9m46.035s
user 0m0.120s
sys 0m0.085s
REPOSITORY TAG IMAGE ID CREATED SIZE
hello 0.1.0 332ce3b4f717 30 seconds ago 8.38MB
distroless:
代码语言:javascript复制# Dockerfile.distroless
ARG BASE_IMAGE=rust:1.52.1-slim-buster
FROM $BASE_IMAGE as planner
WORKDIR app
RUN cargo install cargo-chef --version 0.1.20
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM $BASE_IMAGE as cacher
WORKDIR app
RUN cargo install cargo-chef --version 0.1.20
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
FROM $BASE_IMAGE as builder
WORKDIR app
COPY . .
# Copy over the cached dependencies
COPY --from=cacher /app/target target
COPY --from=cacher $CARGO_HOME $CARGO_HOME
RUN cargo build --release
FROM gcr.io/distroless/cc-debian10
COPY --from=builder /app/target/release/hello /
CMD ["./hello"]
结果:
代码语言:javascript复制# first test ommitted
# second test
real 1m57.033s
user 0m0.045s
sys 0m0.038s
# third test
real 2m12.585s
user 0m0.093s
sys 0m0.096s
REPOSITORY TAG IMAGE ID CREATED SIZE
hello 0.1.0 118da37bdfe7 25 seconds ago 29MB
以上结果还是非常可观的。
结论 第一次尝试生成 1.38GB 的映像大小,构建时间为 12m。现在我们可以生成一个非常小的图像,并且构建速度非常快。选择权在你手中。如果您对 musl 目标没问题,请使用 scratch 镜像。否则,选择 distroless 。
- https://azzamsa.com/n/rust-docker/
什么时候不使用 Rust?
Rust 在软件可靠性和性能方面向前迈出了一大步,这直接转化为节省的金钱和时间。Rust 解决了我作为开发人员每天面临的许多问题,例如不变性和良好的抽象。但与所有技术一样,Rust 也有一些缺点并使之不会成为您项目的最佳选择。今天 Sylvain Kerkour 想探讨一下他认为 Rust 的不好用例。
- https://kerkour.com/why-not-rust