| name | rust-ci-deploy |
| description | Rust CI/CD 與部署技能。涵蓋 GitHub Actions Rust 工作流模板(build/test/clippy/fmt/coverage)、 GitLab CI Rust 設定、cross-compilation(cross-rs、target triple)、 cargo-dist 自動發布(binary distribution)、cargo-release 版本管理、 Docker multi-stage build、快取策略(Swatinem/rust-cache)、 MSRV(最低支援版本)測試、security audit(cargo-audit/cargo-deny)。 觸發關鍵詞:Rust CI, GitHub Actions Rust, GitLab CI Rust, cargo-dist, cargo-release, cross compile, Docker Rust, rust-cache, cargo-audit, cargo-deny, MSRV, binary release, CI pipeline
|
Rust CI/CD 與部署
適用場景
- 為 Rust 專案建立 GitHub Actions 或 GitLab CI 持續整合流程
- 需要跨平台交叉編譯(Linux / macOS / Windows / ARM)
- 使用 cargo-dist 自動產生跨平台 binary 並發布到 GitHub Releases
- 使用 cargo-release 管理版本號、changelog、git tag
- 建立 Docker multi-stage build 減小映像體積
- 設定 CI 快取加速編譯(Swatinem/rust-cache)
- 執行安全稽核(cargo-audit / cargo-deny)
- 測試 MSRV(最低支援 Rust 版本)相容性
核心知識
1. CI 流程設計原則
典型 Rust CI pipeline 階段:
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐
│ Check │──▶│ Test │──▶│ Security │──▶│ Coverage │──▶│ Release │
│ fmt+clip │ │ matrix │ │ audit │ │ llvm-cov │ │ dist │
└─────────┘ └─────────┘ └──────────┘ └──────────┘ └─────────┘
關鍵決策:
- Build Matrix:至少涵蓋
stable + MSRV + {linux, macos, windows}
- 快取策略:使用
Swatinem/rust-cache@v2 快取 ~/.cargo 與 target/
- 安全掃描:
cargo-audit 檢查 CVE、cargo-deny 檢查授權與重複依賴
- 失敗快速:將
cargo fmt --check 與 cargo clippy 放最前面
2. GitHub Actions 完整模板
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- run: cargo fmt --all --check
- run: cargo clippy --all-targets --all-features
test:
needs: check
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, "1.75.0"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}-${{ matrix.rust }}
- run: cargo test --all-features --workspace
coverage:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- uses: taiki-e/install-action@cargo-llvm-cov
- uses: Swatinem/rust-cache@v2
- run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
- uses: codecov/codecov-action@v4
with:
files: lcov.info
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: taiki-e/install-action@cargo-audit
- run: cargo audit
3. GitLab CI 範本
image: rust:latest
variables:
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- .cargo/registry/
- .cargo/git/
- target/
stages:
- check
- test
- release
fmt-clippy:
stage: check
script:
- rustup component add rustfmt clippy
- cargo fmt --all --check
- cargo clippy --all-targets --all-features -- -D warnings
test:
stage: test
script:
- cargo test --all-features --workspace
parallel:
matrix:
- RUST_VERSION: ["stable", "1.75.0"]
release:
stage: release
only:
- tags
script:
- cargo build --release
artifacts:
paths:
- target/release/myapp
4. Cross-Compilation Target 清單
| Target Triple | 平台 | 工具 | 備註 |
|---|
x86_64-unknown-linux-gnu | Linux x64 | 原生 | 最常見 |
x86_64-unknown-linux-musl | Linux x64 靜態 | musl-tools | 無 glibc 依賴 |
aarch64-unknown-linux-gnu | Linux ARM64 | cross-rs | Raspberry Pi 4, AWS Graviton |
x86_64-apple-darwin | macOS x64 | osxcross | Intel Mac |
aarch64-apple-darwin | macOS ARM64 | osxcross | Apple Silicon |
x86_64-pc-windows-msvc | Windows x64 | MSVC | Windows 原生 |
x86_64-pc-windows-gnu | Windows x64 | MinGW | GNU 工具鏈 |
wasm32-unknown-unknown | WebAssembly | wasm-pack | 瀏覽器 / WASI |
使用 cross-rs 進行交叉編譯:
cargo install cross --git https://github.com/cross-rs/cross
cross build --release --target aarch64-unknown-linux-gnu
cross build --release --target x86_64-unknown-linux-musl
5. Docker Multi-Stage Build
# === 階段 1:建置 ===
FROM rust:1.82-slim AS builder
WORKDIR /app
# 先複製依賴檔,利用 Docker 層快取
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release && rm -rf src
# 複製完整原始碼並重新建置
COPY src/ src/
RUN touch src/main.rs && cargo build --release
# === 階段 2:執行(極小映像)===
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/myapp /usr/local/bin/myapp
ENTRYPOINT ["myapp"]
靜態連結版(更小映像):
FROM rust:1.82-slim AS builder
RUN rustup target add x86_64-unknown-linux-musl
RUN apt-get update && apt-get install -y musl-tools
WORKDIR /app
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl
FROM scratch
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/myapp /myapp
ENTRYPOINT ["/myapp"]
6. 發布流程
cargo-dist(自動二進位發布)
[workspace.metadata.dist]
cargo-dist-version = "0.27.0"
ci = "github"
installers = ["shell", "powershell", "homebrew"]
targets = [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
]
tap = "user/homebrew-tap"
publish-jobs = ["homebrew"]
初始化與使用:
cargo install cargo-dist
cargo dist init
cargo dist build
cargo dist generate
cargo-release(版本管理 + 發布)
[workspace.metadata.release]
sign-commit = false
sign-tag = false
push-remote = "origin"
pre-release-commit-message = "chore: release v{{version}}"
tag-message = "v{{version}}"
tag-prefix = ""
pre-release-replacements = [
{ file = "CHANGELOG.md", search = "Unreleased", replace = "{{version}} - {{date}}" },
]
使用流程:
cargo install cargo-release
cargo release patch --dry-run
cargo release patch --execute
cargo release minor --execute
cargo release major --execute
7. 快取策略最佳實踐
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}-${{ hashFiles('**/Cargo.lock') }}
cache-on-failure: true
workspaces: |
. -> target
cache-directories: |
~/.cargo/bin/
8. Security Audit 設定
[advisories]
vulnerability = "deny"
unmaintained = "warn"
[licenses]
allow = ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC"]
unlicensed = "deny"
[bans]
multiple-versions = "warn"
deny = [
{ name = "openssl", wrappers = ["openssl-sys"] },
]
[sources]
unknown-registry = "deny"
unknown-git = "deny"
程式碼範例
範例檔案位於 examples/ 目錄,以 .rs 檔案內嵌 YAML / Dockerfile / TOML 模板:
basic.rs — 最小 GitHub Actions workflow(build + test + clippy)
intermediate.rs — 完整 CI pipeline(matrix + coverage + audit + cache)
advanced.rs — cargo-dist + cross-compilation + Docker + release automation
常見錯誤對照表
| 錯誤訊息 / 情境 | 原因 | 修復方式 |
|---|
Cache miss: key not found | 快取 key 未命中,可能因 Cargo.lock 變更或 OS 不匹配 | 確認 Swatinem/rust-cache 的 key 包含 matrix.os;檢查 Cargo.lock 是否已提交 |
error: package X requires rustc 1.XX.0 (MSRV 失敗) | 程式碼或依賴使用了高於 MSRV 的特性 | 在 Cargo.toml 設定 rust-version = "1.75.0";CI 矩陣加入 MSRV 版本測試 |
linking with cc failed: exit code: 1 (cross compile) | 缺少目標平台的 linker 或系統函式庫 | 使用 cross-rs 取代手動設定;或安裝 gcc-aarch64-linux-gnu 等交叉編譯工具 |
The job exceeded the maximum time limit (CI timeout) | 未快取導致每次全量編譯;或依賴樹過大 | 啟用 Swatinem/rust-cache@v2;使用 cargo check 取代完整 build 做初步檢查 |
tag 'v1.2.3' already exists (release tag 衝突) | cargo-release 的 tag 與既有 tag 重複 | 確認 Cargo.toml 版本號已正確遞增;使用 --dry-run 預先檢查 |
Error: denied by license: GPL-3.0 (cargo-deny) | 依賴使用了不在允許清單的授權 | 在 deny.toml 的 [licenses].allow 加入該授權,或替換依賴 |
No artifacts found for pattern (cargo-dist 發布) | Release workflow 未正確上傳 artifacts | 確認 cargo dist generate 已重新產生 workflow;檢查 target 列表是否正確 |
Cargo.toml 依賴與設定模板
[package]
name = "myapp"
version = "0.1.0"
edition = "2021"
rust-version = "1.75.0"
[workspace.metadata.dist]
cargo-dist-version = "0.27.0"
ci = "github"
installers = ["shell", "powershell", "homebrew"]
targets = [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
]
[workspace.metadata.release]
sign-commit = false
sign-tag = false
push-remote = "origin"
pre-release-commit-message = "chore: release v{{version}}"
tag-message = "v{{version}}"
開發依賴(CI 工具)
參考來源