Rust 系统编程语言完全教程 / 第24章:Docker 与部署
第24章:Docker 与部署
24.1 基本 Dockerfile
使用官方 Rust 镜像
# 基础镜像
FROM rust:1.79-bookworm as builder
WORKDIR /app
# 先复制依赖文件,利用 Docker 缓存
COPY Cargo.toml Cargo.lock ./
# 创建空 src/lib.rs 以缓存依赖
RUN mkdir src && echo "" > src/lib.rs && cargo build --release && rm -rf src
# 复制源码并构建
COPY src ./src
RUN cargo build --release
# 运行阶段
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/
EXPOSE 8080
CMD ["my-app"]
24.2 多阶段构建优化
分离依赖编译和源码编译
FROM rust:1.79-bookworm AS chef
RUN cargo install cargo-chef
WORKDIR /app
# 准备阶段:分析依赖
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
# 构建阶段:只编译依赖(利用缓存)
FROM chef AS builder
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
# 编译应用
COPY . .
RUN cargo build --release
# 运行阶段
FROM debian:bookworm-slim AS runtime
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates && \
rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/my-app /usr/local/bin/
EXPOSE 8080
ENTRYPOINT ["my-app"]
24.3 静态链接(musl)
使用 musl 实现完全静态链接
FROM rust:1.79-bookworm AS builder
# 安装 musl 工具链
RUN apt-get update && apt-get install -y musl-tools
# 添加 musl 目标
RUN rustup target add x86_64-unknown-linux-musl
WORKDIR /app
COPY . .
# 使用 musl 目标构建
RUN cargo build --release --target x86_64-unknown-linux-musl
# 运行阶段:使用 scratch(空镜像)
FROM scratch
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/my-app /my-app
EXPOSE 8080
ENTRYPOINT ["/my-app"]
Cargo.toml 配置
# .cargo/config.toml
[target.x86_64-unknown-linux-musl]
rustflags = ["-C", "target-feature=+crt-static"]
# 使用 mold 链接器加速
[target.x86_64-unknown-linux-musl]
linker = "musl-gcc"
24.4 交叉编译
常见目标平台
| 目标 | 说明 |
|---|
x86_64-unknown-linux-musl | Linux x64 静态链接 |
aarch64-unknown-linux-musl | Linux ARM64 静态链接 |
x86_64-unknown-linux-gnu | Linux x64 动态链接 |
x86_64-pc-windows-gnu | Windows x64 |
x86_64-apple-darwin | macOS x64 |
aarch64-apple-darwin | macOS ARM64 (M1/M2) |
wasm32-unknown-unknown | WebAssembly |
使用 cross 工具
# 安装 cross
cargo install cross
# 交叉编译到 ARM64
cross build --release --target aarch64-unknown-linux-musl
# 交叉编译到 Windows
cross build --release --target x86_64-pc-windows-gnu
Docker 交叉编译(ARM64)
# 构建阶段
FROM --platform=linux/amd64 rust:1.79-bookworm AS builder
RUN apt-get update && apt-get install -y \
gcc-aarch64-linux-gnu \
musl-tools \
&& rm -rf /var/lib/apt/lists/*
RUN rustup target add aarch64-unknown-linux-musl
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-gnu-gcc
WORKDIR /app
COPY . .
RUN cargo build --release --target aarch64-unknown-linux-musl
# 运行阶段(ARM64)
FROM --platform=linux/arm64 scratch
COPY --from=builder /app/target/aarch64-unknown-linux-musl/release/my-app /my-app
ENTRYPOINT ["/my-app"]
24.5 优化二进制大小
Cargo.toml 配置
[profile.release]
opt-level = "z" # 优化大小
lto = true # 链接时优化
codegen-units = 1 # 单编译单元
strip = true # 去除符号
panic = "abort" # panic 直接终止
进一步压缩
# 安装 UPX
sudo apt install upx-ucl
# 压缩二进制文件
upx --best target/release/my-app
# 对比大小
ls -lh target/release/my-app
使用 sstrip + UPX
FROM rust:1.79-bookworm AS builder
RUN apt-get update && apt-get install -y \
musl-tools \
upx-ucl \
&& rm -rf /var/lib/apt/lists/*
RUN rustup target add x86_64-unknown-linux-musl
WORKDIR /app
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl
# 压缩二进制
RUN upx --best /app/target/x86_64-unknown-linux-musl/release/my-app
FROM scratch
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/my-app /my-app
ENTRYPOINT ["/my-app"]
24.6 完整部署示例
Web 服务 Dockerfile
# ===== 构建阶段 =====
FROM rust:1.79-bookworm AS builder
RUN apt-get update && \
apt-get install -y musl-tools pkg-config libssl-dev && \
rm -rf /var/lib/apt/lists/*
RUN rustup target add x86_64-unknown-linux-musl
WORKDIR /app
# 缓存依赖
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs && \
cargo build --release --target x86_64-unknown-linux-musl && \
rm -rf src
# 编译应用
COPY . .
RUN touch src/main.rs # 确保重新编译
RUN cargo build --release --target x86_64-unknown-linux-musl
# ===== 运行阶段 =====
FROM alpine:3.19 AS runtime
RUN addgroup -g 1000 app && \
adduser -u 1000 -G app -s /bin/sh -D app
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/my-app /usr/local/bin/
# 复制配置文件
COPY config/ /etc/my-app/
USER app
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --quiet --tries=1 --spider http://localhost:8080/health || exit 1
CMD ["my-app", "--config", "/etc/my-app/config.toml"]
Docker Compose
version: '3.8'
services:
api:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- RUST_LOG=info
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
timeout: 5s
retries: 5
volumes:
pgdata:
24.7 CI/CD 集成
GitHub Actions
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Cross-compile ARM64
uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ghcr.io/${{ github.repository }}:latest
24.8 本章小结
| 要点 | 说明 |
|---|
| 多阶段构建 | 分离构建和运行环境,减小镜像 |
| musl | 静态链接,最小运行时依赖 |
| 交叉编译 | 使用 cross 或 Docker 交叉编译 |
| 二进制优化 | LTO、strip、UPX 压缩 |
| 安全运行 | 使用非 root 用户,scratch 镜像 |
扩展阅读
- Docker 官方文档 — Docker 使用指南
- cross 文档 — 交叉编译工具
- Rust 死二进制 — 二进制大小优化