Rust Docker 部署
匹配构建与运行环境的多阶段 Dockerfile、锁文件、运行依赖、非 root 与信号边界。
#howto
#growing
#dev
#rust
[!info] related notes
Rust Docker 部署
这个概念为什么出现
Rust 编译重、产物可静态/动态链接差异大。
容器部署需先确保目标架构、动态链接依赖与运行镜像兼容,再优化缓存与体积。
[!abstract] 一句话理解 多阶段 Dockerfile:builder 编译 release 二进制,runtime 只拷贝产物与必要证书,以非 root 运行并配置信号感知。
多阶段构建示例
场景:单个二进制的 glibc 构建与运行
# syntax=docker/dockerfile:1
FROM rust:1.90-bookworm AS builder
WORKDIR /app
COPY . .
RUN cargo build --locked --release --bin my_app
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/my_app /usr/local/bin/my_app
USER 65534:65534
ENTRYPOINT ["/usr/local/bin/my_app"]
前提:项目有名为 my_app 的 bin target,已有并提交 Cargo.lock,且依赖的 MSRV 不高于 Rust 1.90。此处版本是可复现的教学基线,不声称是最新工具链;实际项目按 MSRV 与安全更新策略选择,并固定镜像 digest。
在构建上下文加入 .dockerignore,至少排除 target、.git、.env 与本地凭据;示例 COPY . . 不单独缓存依赖构建层。构建 docker build -t my_app .,运行 docker run --rm my_app;启动参数、端口、环境变量与挂载按应用的真实接口配置。
builder/runtime 显式使用同一 Debian 系列以降低 glibc 版本不兼容风险,仍需核对架构和二进制动态依赖。ca-certificates 的用途是提供 CA 信任库,安装时可能间接带入 OpenSSL,但不保证满足应用要求的 OpenSSL ABI、数据库客户端等全部动态库;有原生依赖时按实际链接结果核对并显式安装。
结合场景再看三个关注点
- 修改源码会使 COPY 后构建层失效;按需要使用 cargo-chef 或 BuildKit cache mount,不能把多阶段本身当依赖缓存
- musl/静态构建需单独验证;切换目标不保证所有原生依赖静态链接,scratch 还需考虑证书、时区与可写目录
- exec 形式 ENTRYPOINT 让程序直接接收信号;程序还必须实现停止协议,USER 非 root 和 Dockerfile 本身不会提供优雅关闭
工程实践
- 固定 base digest
- 非 root UID/GID;确认工作目录、挂载卷与临时文件路径的访问权限
- 只读根文件系统(若可行)
- 健康检查与资源 limit
- CI 缓存 sccache/cargo
本节总结
- 多阶段减小攻击面与体积
- 编译缓存是关键
- 与配置/信号协作
自测题
- 为何 runtime 不直接用 rust 镜像?
- 静态链接的取舍?
参考答案
- 体积与攻击面。
- 易 scratch 部署,但调试/glibc 特性/体积策略需评估。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Docker multi-stage | 官方 | 多阶段 |
| cargo-chef | 生态 | 依赖缓存 |