# Rust 服务 Dockerfile 模板 Rust 项目的 Docker 容器化模板,支持多种构建场景。 ## 模板类型 ### 1. CI 构建镜像(Dockerfile.ci) **适用场景**:在 CI/CD 中使用,二进制文件已在外部构建完成。 **优点**: - 镜像体积最小(~20MB) - 构建速度快 - 适合生产环境 ```dockerfile FROM alpine:3.21 # 安装运行时依赖 RUN apk add --no-cache ca-certificates tzdata curl && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime WORKDIR /app # 复制编译好的二进制文件(由 CI workflow 构建) COPY your-binary-name . # 环境变量 ENV TZ=Asia/Shanghai ENV RUST_LOG=info # 暴露端口 EXPOSE 9090 # 健康检查 # 根据你的服务实际情况修改端点和端口 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD curl -sf http://localhost:9090/healthz || exit 1 CMD ["./your-binary-name"] ``` **使用说明**: 1. 将 `your-binary-name` 替换为实际的二进制文件名 2. 修改 `EXPOSE` 端口号 3. 修改 `HEALTHCHECK` 的端点和端口 4. 在 CI workflow 中先构建二进制,再构建镜像 ### 2. 完整构建镜像(Dockerfile) **适用场景**:本地开发、无 CI 环境、独立构建。 **优点**: - 自包含构建流程 - 可在任何环境构建 - 利用 Docker 缓存加速 ```dockerfile # ============================================ # 构建阶段 # ============================================ FROM rust:1.83-alpine AS builder # 安装构建依赖 # musl-dev: musl libc 开发包(静态链接) # openssl-dev: OpenSSL 开发包(如果项目依赖 openssl) # pkgconfig: pkg-config 工具 RUN apk add --no-cache musl-dev openssl-dev pkgconfig # 配置 Cargo 镜像加速(使用 rsproxy.cn) RUN mkdir -p /root/.cargo && \ echo '[source.crates-io]' > /root/.cargo/config.toml && \ echo 'replace-with = "rsproxy-sparse"' >> /root/.cargo/config.toml && \ echo '[source.rsproxy-sparse]' >> /root/.cargo/config.toml && \ echo 'registry = "sparse+https://rsproxy.cn/index/"' >> /root/.cargo/config.toml WORKDIR /build # 先复制依赖文件,利用 Docker 层缓存 # 只要 Cargo.toml 和 Cargo.lock 不变,依赖层就会被缓存 COPY Cargo.toml Cargo.lock ./ # 创建虚拟 src 目录,预先下载和编译依赖 # 这样修改源码时不需要重新编译依赖 RUN mkdir src && \ echo "fn main() {}" > src/main.rs && \ cargo build --release --target x86_64-unknown-linux-musl && \ rm -rf src # 复制实际源码 COPY src ./src # 构建 Release 版本(musl 静态链接) RUN cargo build --release --target x86_64-unknown-linux-musl # ============================================ # 运行阶段 # ============================================ FROM alpine:3.21 # 安装运行时依赖 RUN apk add --no-cache ca-certificates tzdata curl && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime WORKDIR /app # 从构建阶段复制二进制文件 COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/your-binary-name . # 环境变量 ENV TZ=Asia/Shanghai ENV RUST_LOG=info # 暴露端口 EXPOSE 9090 # 健康检查 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD curl -sf http://localhost:9090/healthz || exit 1 CMD ["./your-binary-name"] ``` **使用说明**: 1. 将 `your-binary-name` 替换为 `Cargo.toml` 中的 `[[bin]]` name 2. 如果不需要 OpenSSL,可移除 `openssl-dev` 3. 修改端口和健康检查配置 ### 3. 依赖缓存优化版(Dockerfile.cache) **适用场景**:本地开发,频繁构建。 **优点**: - 最大化利用缓存 - 依赖只编译一次 - 适合迭代开发 ```dockerfile # ============================================ # 依赖缓存阶段 # ============================================ FROM rust:1.83-alpine AS dependencies RUN apk add --no-cache musl-dev openssl-dev pkgconfig # 配置 Cargo 镜像 RUN mkdir -p /root/.cargo && \ echo '[source.crates-io]' > /root/.cargo/config.toml && \ echo 'replace-with = "rsproxy-sparse"' >> /root/.cargo/config.toml && \ echo '[source.rsproxy-sparse]' >> /root/.cargo/config.toml && \ echo 'registry = "sparse+https://rsproxy.cn/index/"' >> /root/.cargo/config.toml WORKDIR /build # 只复制依赖文件 COPY Cargo.toml Cargo.lock ./ # 创建虚拟 main.rs,编译依赖 RUN mkdir -p src && \ echo "fn main() {}" > src/main.rs && \ cargo build --release --target x86_64-unknown-linux-musl # 删除虚拟源码编译产物 RUN rm -f target/x86_64-unknown-linux-musl/release/deps/your_binary_name* # ============================================ # 构建阶段 # ============================================ FROM rust:1.83-alpine AS builder RUN apk add --no-cache musl-dev openssl-dev pkgconfig WORKDIR /build # 从依赖阶段复制编译缓存 COPY --from=dependencies /root/.cargo /root/.cargo COPY --from=dependencies /build/target target # 复制所有文件 COPY . . # 构建项目 RUN cargo build --release --target x86_64-unknown-linux-musl # ============================================ # 运行阶段 # ============================================ FROM alpine:3.21 RUN apk add --no-cache ca-certificates tzdata curl && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime WORKDIR /app COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/your-binary-name . ENV TZ=Asia/Shanghai ENV RUST_LOG=info EXPOSE 9090 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD curl -sf http://localhost:9090/healthz || exit 1 CMD ["./your-binary-name"] ``` **使用说明**: 1. 将 `your_binary_name` 替换为二进制文件名(下划线形式) 2. 适合本地 `docker build` 使用 ### 4. 多平台构建版(Dockerfile.multiarch) **适用场景**:需要支持 ARM64 和 AMD64。 ```dockerfile # ============================================ # 构建阶段(支持多平台) # ============================================ FROM --platform=$BUILDPLATFORM rust:1.83-alpine AS builder # 安装构建依赖 RUN apk add --no-cache musl-dev openssl-dev pkgconfig clang # 配置 Cargo 镜像 RUN mkdir -p /root/.cargo && \ echo '[source.crates-io]' > /root/.cargo/config.toml && \ echo 'replace-with = "rsproxy-sparse"' >> /root/.cargo/config.toml && \ echo '[source.rsproxy-sparse]' >> /root/.cargo/config.toml && \ echo 'registry = "sparse+https://rsproxy.cn/index/"' >> /root/.cargo/config.toml # 安装目标架构支持 ARG TARGETARCH RUN case "$TARGETARCH" in \ "amd64") echo "x86_64-unknown-linux-musl" > /target.txt ;; \ "arm64") echo "aarch64-unknown-linux-musl" > /target.txt ;; \ *) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; \ esac && \ rustup target add $(cat /target.txt) WORKDIR /build COPY Cargo.toml Cargo.lock ./ COPY src ./src # 构建对应架构 RUN cargo build --release --target $(cat /target.txt) # 复制二进制到统一路径 RUN mkdir -p /app && \ cp target/$(cat /target.txt)/release/your-binary-name /app/ # ============================================ # 运行阶段 # ============================================ FROM alpine:3.21 RUN apk add --no-cache ca-certificates tzdata curl && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime WORKDIR /app COPY --from=builder /app/your-binary-name . ENV TZ=Asia/Shanghai ENV RUST_LOG=info EXPOSE 9090 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD curl -sf http://localhost:9090/healthz || exit 1 CMD ["./your-binary-name"] ``` **使用说明**: ```bash # 构建多平台镜像 docker buildx build --platform linux/amd64,linux/arm64 -t your-image:latest . ``` ## 高级配置 ### 健康检查配置 ```dockerfile # 存活探针(Liveness Probe) HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD curl -sf http://localhost:9090/healthz || exit 1 # 参数说明: # --interval=30s 每 30 秒检查一次 # --timeout=5s 单次检查超时 5 秒 # --start-period=10s 容器启动后 10 秒开始检查 # --retries=3 失败 3 次后认为不健康 ``` ### 多端点健康检查 ```dockerfile # 使用脚本检查多个端点 RUN echo '#!/bin/sh' > /healthcheck.sh && \ echo 'curl -sf http://localhost:9090/healthz || exit 1' >> /healthcheck.sh && \ echo 'curl -sf http://localhost:9090/readyz || exit 1' >> /healthcheck.sh && \ chmod +x /healthcheck.sh HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD ["/healthcheck.sh"] ``` ### 环境变量配置 ```dockerfile # 基础环境变量 ENV TZ=Asia/Shanghai ENV RUST_LOG=info ENV RUST_BACKTRACE=1 # 应用配置(可在 docker run 时覆盖) ENV CONFIG_FILE=production.yaml ENV HTTP_PORT=9090 ENV LOG_LEVEL=info # 数据库配置(敏感信息应通过运行时注入) # ENV DATABASE_URL=postgresql://... ``` ### 非 root 用户运行 ```dockerfile # 创建非特权用户 RUN addgroup -g 1000 appuser && \ adduser -D -u 1000 -G appuser appuser WORKDIR /app # 复制二进制文件 COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/your-binary-name . # 修改所有权 RUN chown -R appuser:appuser /app # 切换用户 USER appuser CMD ["./your-binary-name"] ``` ### 配置文件挂载 ```dockerfile # 在 Dockerfile 中创建配置目录 RUN mkdir -p /app/configs /app/logs # 在 docker run 时挂载 # docker run -v ./configs:/app/configs -v ./logs:/app/logs your-image ``` ## 构建命令示例 ### 本地构建 ```bash # 基础构建 docker build -t your-service:latest . # 指定 Dockerfile docker build -f Dockerfile.ci -t your-service:latest . # 传递构建参数 docker build --build-arg GIT_TAG=1.0.0 -t your-service:1.0.0 . # 查看构建过程 docker build --progress=plain -t your-service:latest . ``` ### 多平台构建 ```bash # 创建 buildx builder docker buildx create --name mybuilder --use # 构建并推送 docker buildx build \ --platform linux/amd64,linux/arm64 \ -t registry.example.com/your-service:latest \ --push \ . ``` ### 优化构建速度 ```bash # 使用 BuildKit 缓存 export DOCKER_BUILDKIT=1 # 使用外部缓存 docker build \ --cache-from=type=registry,ref=your-service:buildcache \ --cache-to=type=registry,ref=your-service:buildcache,mode=max \ -t your-service:latest \ . ``` ## 镜像大小优化 ### 1. 使用 Alpine 基础镜像 ```dockerfile # Alpine 镜像体积小(~5MB) FROM alpine:3.21 ``` ### 2. 静态链接(musl) ```dockerfile # 构建时使用 musl 目标,生成静态链接二进制 RUN cargo build --release --target x86_64-unknown-linux-musl ``` ### 3. Strip 二进制文件 ```toml # Cargo.toml [profile.release] strip = true # 去除符号表 ``` 或在 Dockerfile 中: ```dockerfile # 手动 strip RUN strip target/x86_64-unknown-linux-musl/release/your-binary-name ``` ### 4. 最小化层数 ```dockerfile # 合并多个 RUN 命令 RUN apk add --no-cache ca-certificates tzdata curl && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ addgroup -g 1000 appuser ``` ### 5. 使用 .dockerignore ``` # .dockerignore target/ .git/ .gitignore *.md tests/ benches/ ``` ## 安全建议 ### 1. 使用特定版本标签 ```dockerfile # 不推荐:使用 latest FROM alpine:latest # 推荐:使用特定版本 FROM alpine:3.21 ``` ### 2. 定期更新依赖 ```bash # 更新 Cargo 依赖 cargo update # 检查安全漏洞 cargo audit ``` ### 3. 最小权限原则 ```dockerfile # 使用非 root 用户 USER appuser # 只读文件系统(根据需要) # docker run --read-only your-service ``` ### 4. 不在镜像中包含敏感信息 ```dockerfile # 错误示例 # ENV DATABASE_PASSWORD=secret123 # 正确做法:通过运行时注入 # docker run -e DATABASE_PASSWORD=secret123 your-service ``` ## 常见问题 ### Q1: 镜像体积过大 **原因**: - 使用 `rust:latest` 作为运行镜像(>1GB) - 没有使用多阶段构建 - 包含 debug 符号 **解决方案**: ```dockerfile # 使用多阶段构建 + Alpine FROM rust:1.83-alpine AS builder # ... 构建步骤 ... FROM alpine:3.21 # 最终镜像只有 ~20MB COPY --from=builder /build/target/.../your-binary . ``` ### Q2: openssl 链接错误 **错误信息**: ``` error: linking with `cc` failed ld: library not found for -lssl ``` **解决方案**: ```dockerfile # 方案 1:安装 openssl-dev RUN apk add --no-cache openssl-dev # 方案 2:使用 rustls 替代 openssl # 在 Cargo.toml 中使用 rustls feature ``` ### Q3: 交叉编译失败 **错误信息**: ``` error: linker `aarch64-linux-musl-gcc` not found ``` **解决方案**: ```bash # 安装 musl 交叉编译工具链 rustup target add aarch64-unknown-linux-musl # 或使用 cargo-zigbuild cargo install cargo-zigbuild cargo zigbuild --target aarch64-unknown-linux-musl ``` ### Q4: 容器启动失败 **检查步骤**: ```bash # 查看日志 docker logs your-container # 进入容器调试 docker run -it --entrypoint /bin/sh your-image # 检查二进制是否可执行 docker run your-image ls -lh /app/ ``` ## 参考资源 - [Rust 官方 Docker 指南](https://docs.docker.com/language/rust/) - [Alpine Linux 包搜索](https://pkgs.alpinelinux.org/packages) - [Docker 多阶段构建文档](https://docs.docker.com/build/building/multi-stage/) - [cargo-zigbuild](https://github.com/rust-cross/cargo-zigbuild)