- 新增 Go、Node.js、Rust 服务的 Dockerfile 模板 - 新增 Rust 快速参考指南 - 新增 Rust 后端工作流模板 - 优化 create-runner.md,明确 host 网络模式为缓存必需条件 - 更新 gitea skill 主文档
444 lines
9.4 KiB
Markdown
444 lines
9.4 KiB
Markdown
# 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 <container>`)
|
||
|
||
### Runner 无法连接
|
||
|
||
- [ ] 检查 Runner 是否在运行(`/gitea-list-runners`)
|
||
- [ ] 检查 Runner labels 是否匹配 workflow 中的 `runs-on`
|
||
- [ ] 检查网络连接
|
||
- [ ] 查看 Runner 日志(`~/.config/gitea/runners/<runner-name>/*.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)
|