# Rust 项目 Gitea CI/CD 快速参考 快速设置 Rust 项目的 CI/CD 流程。 ## 最小化配置(3 步) ### 1. 创建 Dockerfile.ci 在项目根目录创建 `Dockerfile.ci`: ```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 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"] ``` **修改项**: - `your-binary-name` → 你的二进制文件名(通常和 `Cargo.toml` 中的 `name` 一致) - `9090` → 你的服务端口 ### 2. 创建 workflow 文件 创建 `.gitea/workflows/your-service.yml`: ```yaml name: Your Service - Build & Publish on: push: paths: - '**' # 修改为实际监听路径 tags: - 'v*' # 修改为实际 tag 格式 env: SERVICE_PREFIX: your-service # 修改为实际服务名 CARGO_INCREMENTAL: 0 CARGO_NET_RETRY: 10 RUSTUP_DIST_SERVER: https://rsproxy.cn RUSTUP_UPDATE_ROOT: https://rsproxy.cn/rustup jobs: build-and-publish: runs-on: ubuntu-latest # 修改为你的 Runner 标签 steps: - uses: actions/checkout@v4 - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://rsproxy.cn/rustup-init.sh | sh -s -- -y echo "$HOME/.cargo/bin" >> $GITHUB_PATH source "$HOME/.cargo/env" rustup target add x86_64-unknown-linux-musl - name: Build run: | cargo build --release --target x86_64-unknown-linux-musl cp target/x86_64-unknown-linux-musl/release/your-binary-name . - name: Docker Login uses: docker/login-action@v3 with: registry: ${{ github.server_url }} username: ${{ vars.REGISTRY_USERNAME }} password: ${{ secrets.RELEASE_TOKEN }} - name: Build & Push Image uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile.ci push: true tags: | ${{ github.server_url }}/${{ github.repository }}:latest ${{ github.server_url }}/${{ github.repository }}:${{ github.sha }} ``` **修改项**: - `your-service` → 你的服务名 - `your-binary-name` → 你的二进制文件名 - `ubuntu-latest` → 你的 Runner 标签 - `paths` → 触发构建的路径 - `tags` → 触发构建的 tag 格式 ### 3. 推送代码并打 tag ```bash git add .gitea Dockerfile.ci git commit -m "ci: 添加 CI/CD 配置" git push # 触发构建 git tag v0.1.0 git push origin v0.1.0 ``` ## 进阶配置 ### 添加交叉编译支持 如果你的 Runner 是 ARM64,但需要构建 x86_64 镜像: ```yaml - name: Install Zig and cargo-zigbuild run: | wget -q https://ziglang.org/download/0.13.0/zig-linux-aarch64-0.13.0.tar.xz tar -xf zig-linux-aarch64-0.13.0.tar.xz mv zig-linux-aarch64-0.13.0 /opt/zig echo "/opt/zig" >> $GITHUB_PATH cargo install cargo-zigbuild - name: Build run: | cargo zigbuild --release --target x86_64-unknown-linux-musl ``` ### 添加 Rust 缓存 ```yaml - name: Cache Rust dependencies uses: https://github.com/Swatinem/rust-cache@v2 with: workspaces: . -> target cache-targets: true ``` ### 添加版本号注入 **1. 创建 `build.rs`**: ```rust fn main() { if let Ok(git_tag) = std::env::var("GIT_TAG") { println!("cargo:rustc-env=GIT_TAG={}", git_tag); } println!("cargo:rerun-if-env-changed=GIT_TAG"); } ``` **2. 在 workflow 中设置环境变量**: ```yaml - name: Build env: GIT_TAG: ${{ github.ref_name }} run: cargo build --release ``` **3. 在代码中使用**: ```rust let version = option_env!("GIT_TAG").unwrap_or("dev"); println!("Version: {}", version); ``` ### 添加 Release 创建 ```yaml release: name: Create Release runs-on: ubuntu-latest needs: build-and-publish if: startsWith(github.ref, 'refs/tags/') steps: - name: Create Release run: | curl -X POST "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases" \ -H "Authorization: token ${{ secrets.RELEASE_TOKEN }}" \ -H "Content-Type: application/json" \ -d "{ \"tag_name\": \"${{ github.ref_name }}\", \"name\": \"Release ${{ github.ref_name }}\", \"body\": \"自动构建的 Release\" }" ``` ## 健康检查端点实现 如果你的服务还没有健康检查端点,快速添加: ### 使用 Axum ```rust use axum::{Router, routing::get}; #[tokio::main] async fn main() { let app = Router::new() .route("/healthz", get(|| async { "OK" })); let listener = tokio::net::TcpListener::bind("0.0.0.0:9090") .await .unwrap(); axum::serve(listener, app).await.unwrap(); } ``` ### 使用 Actix-web ```rust use actix_web::{web, App, HttpServer, HttpResponse}; #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .route("/healthz", web::get().to(|| async { HttpResponse::Ok().body("OK") })) }) .bind("0.0.0.0:9090")? .run() .await } ``` ### 使用 Rocket ```rust #[macro_use] extern crate rocket; #[get("/healthz")] fn healthz() -> &'static str { "OK" } #[launch] fn rocket() -> _ { rocket::build().mount("/", routes![healthz]) } ``` ## Cargo.toml 优化配置 ```toml [profile.release] opt-level = 3 # 最高优化级别 lto = true # 链接时优化 codegen-units = 1 # 单个代码生成单元 strip = true # 去除符号表 panic = 'abort' # panic 时直接退出 ``` ## .dockerignore 示例 创建 `.dockerignore` 减小构建上下文: ``` target/ .git/ .gitignore *.md tests/ benches/ examples/ .github/ .gitea/workflows/ Dockerfile* docker-compose.yml ``` ## 环境变量配置 ### 在 workflow 中 ```yaml env: RUST_LOG: info # 日志级别 CONFIG_FILE: production.yaml # 配置文件 DATABASE_URL: ${{ secrets.DATABASE_URL }} # 数据库连接 ``` ### 在 Dockerfile 中 ```dockerfile ENV RUST_LOG=info ENV CONFIG_FILE=production.yaml ``` ### 在运行时 ```bash docker run -e RUST_LOG=debug -e CONFIG_FILE=custom.yaml your-image ``` ## 常见 Runner 标签 | 标签 | 说明 | |------|------| | `ubuntu-latest` | Ubuntu 最新版本 | | `darwin-arm64` | macOS ARM64 | | `darwin-amd64` | macOS x86_64 | | `linux-amd64` | Linux x86_64 | | `linux-arm64` | Linux ARM64 | 查看可用 Runner: ```bash /gitea-list-runners ``` ## 触发条件参考 ### 推送到特定分支 ```yaml on: push: branches: - main - develop ``` ### 推送特定路径 ```yaml on: push: paths: - 'src/**' - 'Cargo.toml' - 'Cargo.lock' ``` ### 特定 tag 格式 ```yaml on: push: tags: - 'v*' # v1.0.0, v2.1.3 - 'device-rs-*' # device-rs-1.0.0 ``` ### Pull Request ```yaml on: pull_request: branches: - main ``` ### 定时触发 ```yaml on: schedule: - cron: '0 2 * * *' # 每天凌晨 2 点 ``` ## 调试技巧 ### 查看 workflow 日志 在 Gitea 仓库页面: 1. 点击 "Actions" 2. 选择对应的 workflow run 3. 查看每个 step 的日志 ### 本地测试构建 ```bash # 测试 Rust 构建 cargo build --release --target x86_64-unknown-linux-musl # 测试 Docker 构建 docker build -f Dockerfile.ci -t test:latest . # 测试容器运行 docker run -p 9090:9090 test:latest ``` ### 使用 act 本地运行 workflow ```bash # 安装 act(如果使用 Gitea Actions) # 注意:act 主要支持 GitHub Actions,Gitea Actions 可能有兼容性问题 # 列出可用的 actions act -l # 运行特定 job act -j build-and-publish ``` ## 完整配置示例 参考 BMS 项目的 device-rs: - Workflow: [device-rs.yml](https://git.voson.top/tianchu/bms/src/branch/main/.gitea/workflows/device-rs.yml) - Dockerfile: [Dockerfile.ci](https://git.voson.top/tianchu/bms/src/branch/main/device-rs/Dockerfile.ci) - 项目结构: [device-rs/](https://git.voson.top/tianchu/bms/src/branch/main/device-rs) ## 故障排查清单 ### 构建失败 - [ ] 检查 Rust 版本是否满足要求 - [ ] 检查依赖是否正确(`Cargo.lock` 是否提交) - [ ] 检查 musl 目标是否安装(`rustup target list --installed`) - [ ] 查看完整构建日志 ### Docker 推送失败 - [ ] 检查 Docker Registry 地址是否正确 - [ ] 检查 `REGISTRY_USERNAME` 变量是否设置 - [ ] 检查 `RELEASE_TOKEN` secret 是否正确 - [ ] 检查 Token 权限(需要 packages write 权限) ### 容器启动失败 - [ ] 检查二进制文件名是否正确 - [ ] 检查端口是否正确 - [ ] 检查健康检查端点是否存在 - [ ] 查看容器日志(`docker logs `) ### Runner 无法连接 - [ ] 检查 Runner 是否在运行(`/gitea-list-runners`) - [ ] 检查 Runner labels 是否匹配 workflow 中的 `runs-on` - [ ] 检查网络连接 - [ ] 查看 Runner 日志(`~/.config/gitea/runners//*.log`) ## 更多资源 - [完整 Workflow 模板](./workflow-templates/rust-backend.md) - [Dockerfile 模板详解](./dockerfile-templates/rust-service.md) - [Gitea Actions 文档](https://docs.gitea.com/usage/actions/quickstart) - [Rust CI 最佳实践](https://doc.rust-lang.org/cargo/guide/continuous-integration.html)