feat(gitea): 添加 Dockerfile 模板和 Rust 支持,优化 runner 网络配置说明
- 新增 Go、Node.js、Rust 服务的 Dockerfile 模板 - 新增 Rust 快速参考指南 - 新增 Rust 后端工作流模板 - 优化 create-runner.md,明确 host 网络模式为缓存必需条件 - 更新 gitea skill 主文档
This commit is contained in:
@@ -18,5 +18,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mcp": {}
|
||||
}
|
||||
@@ -395,6 +395,7 @@ Runner 信息
|
||||
|------|---------|---------|
|
||||
| **Rust 后端** | [rust-backend.md](./workflow-templates/rust-backend.md) | **Rust API 服务、微服务、CLI 工具** |
|
||||
| Go 后端 | [go-backend.md](./workflow-templates/go-backend.md) | API 服务、微服务、CLI 工具 |
|
||||
| Rust 后端 | [rust-backend.md](./workflow-templates/rust-backend.md) | Rust API 服务、异步服务、IoT 设备服务 |
|
||||
| Node.js 前端 | [nodejs-frontend.md](./workflow-templates/nodejs-frontend.md) | React/Vue/Vite/Next.js |
|
||||
| Android 应用 | [android-app.md](./workflow-templates/android-app.md) | Kotlin/Java/Jetpack Compose |
|
||||
| 微信小程序 | [wechat-miniprogram.md](./workflow-templates/wechat-miniprogram.md) | 微信小程序 CI/CD |
|
||||
@@ -407,6 +408,31 @@ AI 会自动:
|
||||
|
||||
详见:[Workflow 生成器](./workflow-generator.md)
|
||||
|
||||
## Dockerfile 模板
|
||||
|
||||
提供多种 Dockerfile 模板,适配不同的构建场景:
|
||||
|
||||
| 类型 | 模板文档 | 适用场景 |
|
||||
|------|---------|---------|
|
||||
| Go 服务 | [go-service.md](./dockerfile-templates/go-service.md) | Go 后端服务容器化(CI 构建、完整构建、代码生成) |
|
||||
| Rust 服务 | [rust-service.md](./dockerfile-templates/rust-service.md) | Rust 后端服务容器化(CI 构建、完整构建、多平台) |
|
||||
| Node.js 前端 | [nodejs-frontend.md](./dockerfile-templates/nodejs-frontend.md) | 前端静态文件服务(Nginx + SPA 路由) |
|
||||
|
||||
**模板特性对比**:
|
||||
|
||||
| 特性 | Go 服务 | Rust 服务 | Node.js 前端 |
|
||||
|------|---------|-----------|-------------|
|
||||
| CI 构建版 | ✅ | ✅ | ✅ |
|
||||
| 完整构建版 | ✅ | ✅ | ✅ |
|
||||
| 健康检查脚本 | ✅ | ✅ | ✅(Nginx) |
|
||||
| 多阶段构建 | ✅ | ✅ | ✅ |
|
||||
| 镜像大小 | ~15MB | ~20MB | ~20MB |
|
||||
| 代码生成支持 | ✅ | ❌ | ❌ |
|
||||
| 多平台构建 | ❌ | ✅ | ❌ |
|
||||
| API 代理配置 | ❌ | ❌ | ✅(Nginx) |
|
||||
|
||||
详见各模板文档了解具体使用方法。
|
||||
|
||||
## API 调用
|
||||
|
||||
所有与 Gitea 服务器的交互都通过 API 完成,使用配置文件中的:
|
||||
@@ -466,9 +492,9 @@ Gitea Actions 提供的内置变量(推荐优先使用):
|
||||
|
||||
## 版本
|
||||
|
||||
- **Skill Version**: 1.3
|
||||
- **Skill Version**: 1.4
|
||||
- **Last Updated**: 2026-01-29
|
||||
- **整合内容**: gitea-runner + gitea-workflow + 增强仓库管理 + SSH 密钥管理 + Rust 模板
|
||||
- **整合内容**: gitea-runner + gitea-workflow + 增强仓库管理 + SSH 密钥管理 + 完整 Dockerfile 模板库
|
||||
- **主要改进**:
|
||||
- 仓库创建智能解析(优先使用指定组织)
|
||||
- **简化验证**:默认假设组织存在,API失败时提示创建组织
|
||||
@@ -477,6 +503,12 @@ Gitea Actions 提供的内置变量(推荐优先使用):
|
||||
- **简洁高效**:减少预先验证,API失败时给出具体解决方案
|
||||
- 工作目录概念澄清(配置 vs 仓库操作)
|
||||
- **SSH 密钥管理**:完整的密钥创建、部署和跨设备使用指南
|
||||
- **Rust 项目支持**:新增 Rust workflow 和 Dockerfile 模板,支持交叉编译、musl 静态链接、多平台构建
|
||||
- **完整 Dockerfile 模板库**:新增 Go 和 Node.js 前端 Dockerfile 模板,涵盖所有后端和前端容器化需求
|
||||
|
||||
## 快速参考
|
||||
|
||||
- [Rust 项目快速配置](./rust-quick-reference.md) - 3 步设置 Rust 项目 CI/CD
|
||||
|
||||
## 相关资源
|
||||
|
||||
|
||||
@@ -7,6 +7,15 @@ agent: general
|
||||
|
||||
本文档提供了多种创建 Gitea Actions Runner 的方式,支持 Host 模式和 Docker 模式。
|
||||
|
||||
## ⚠️ 重要:网络模式要求
|
||||
|
||||
**两种模式都必须使用 host 网络模式,否则缓存功能无法正常工作!**
|
||||
|
||||
- **Docker 模式**:Runner 容器和 Job 容器都使用 host 网络
|
||||
- **Self-host 模式**:Job 进程直接在宿主机运行,使用 127.0.0.1
|
||||
|
||||
原因:Gitea Actions 的缓存服务运行在 runner 本地,job 容器需要通过网络访问 runner 的缓存端口。只有在 host 网络模式下,job 容器才能访问到 runner 的缓存服务。
|
||||
|
||||
## 📦 快速使用
|
||||
|
||||
### 方法一:直接执行(推荐)
|
||||
@@ -108,6 +117,7 @@ cache:
|
||||
host: "host.docker.internal"
|
||||
port: 9040
|
||||
container:
|
||||
# 【关键】必须使用 host 网络!否则 job 容器无法访问 runner 的缓存服务
|
||||
network: "host"
|
||||
privileged: false
|
||||
options:
|
||||
@@ -123,6 +133,7 @@ YAML
|
||||
# 注意:不要使用 node:16-bullseye 等纯运行时镜像,它们不包含 docker 命令
|
||||
local labels="ubuntu-latest:docker://catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04,linux:docker://catthehacker/ubuntu:act-latest"
|
||||
|
||||
# 必须使用 --network host!这样 job 容器才能访问 runner 的缓存服务
|
||||
docker run -d \
|
||||
--name "$name" \
|
||||
--restart always \
|
||||
@@ -178,6 +189,7 @@ runner:
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "$runner_dir/cache"
|
||||
# Self-host 模式:job 进程直接在宿主机运行,使用 127.0.0.1 访问缓存
|
||||
host: "127.0.0.1"
|
||||
port: 0
|
||||
host:
|
||||
@@ -747,6 +759,7 @@ EOF
|
||||
|
||||
echo "启动 Docker 容器 (自动注册)..."
|
||||
|
||||
# 必须使用 --network host!这样 job 容器才能访问 runner 的缓存服务
|
||||
docker run -d \
|
||||
--name "$name" \
|
||||
--restart always \
|
||||
@@ -1074,7 +1087,7 @@ cache:
|
||||
host: "host.docker.internal"
|
||||
port: 9040
|
||||
container:
|
||||
# 使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问
|
||||
# 【关键】必须使用 host 网络!否则 job 容器无法访问 runner 的缓存服务
|
||||
network: "host"
|
||||
privileged: false
|
||||
options:
|
||||
@@ -1088,7 +1101,7 @@ EOF
|
||||
|
||||
echo "启动 Docker 容器 (自动注册)..."
|
||||
|
||||
# 使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问
|
||||
# 【关键】必须使用 --network host!否则 job 容器无法访问 runner 的缓存服务
|
||||
docker run -d \
|
||||
--name "$runner_name" \
|
||||
--restart always \
|
||||
|
||||
550
skill/gitea/dockerfile-templates/go-service.md
Normal file
550
skill/gitea/dockerfile-templates/go-service.md
Normal file
@@ -0,0 +1,550 @@
|
||||
# Go 服务 Dockerfile 模板
|
||||
|
||||
Go 后端服务的 Docker 容器化模板,支持多种构建场景。
|
||||
|
||||
## 模板类型
|
||||
|
||||
### 1. CI 构建镜像(Dockerfile.ci)
|
||||
|
||||
**适用场景**:在 CI/CD 中使用,二进制文件已在外部构建完成。
|
||||
|
||||
**优点**:
|
||||
- 镜像体积最小(~15MB)
|
||||
- 构建速度快
|
||||
- 适合生产环境
|
||||
|
||||
```dockerfile
|
||||
# CI 构建专用 Dockerfile
|
||||
# 将不常变化的层放在前面,最大化利用缓存
|
||||
# 使用固定版本避免 latest 导致的缓存失效和不确定性
|
||||
|
||||
FROM alpine:3.21
|
||||
|
||||
# 基础设置层 - 很少变化,可以长期缓存
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk add --no-cache tzdata wget netcat-openbsd && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
# 健康检查脚本 - 偶尔变化
|
||||
COPY docker-healthcheck.sh .
|
||||
RUN chmod +x docker-healthcheck.sh
|
||||
|
||||
# 应用二进制 - 每次构建都变化,放在最后
|
||||
COPY your-binary-name .
|
||||
|
||||
# 健康检查(根据实际服务修改端口和端点)
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD ./docker-healthcheck.sh
|
||||
|
||||
CMD ["./your-binary-name"]
|
||||
```
|
||||
|
||||
**使用说明**:
|
||||
1. 将 `your-binary-name` 替换为实际的二进制文件名
|
||||
2. 创建 `docker-healthcheck.sh` 健康检查脚本
|
||||
3. 在 CI workflow 中先构建二进制,再构建镜像
|
||||
|
||||
### 2. 完整构建镜像(Dockerfile)
|
||||
|
||||
**适用场景**:本地开发、无 CI 环境、独立构建。
|
||||
|
||||
**优点**:
|
||||
- 自包含构建流程
|
||||
- 可在任何环境构建
|
||||
- 利用 Docker 缓存加速
|
||||
|
||||
```dockerfile
|
||||
# ============================================
|
||||
# 构建阶段
|
||||
# ============================================
|
||||
FROM golang:1.25-alpine AS builder
|
||||
|
||||
# 安装构建依赖
|
||||
RUN apk add --no-cache git make
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /build
|
||||
|
||||
# 设置 Go 代理(国内加速)
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
ENV CGO_ENABLED=0
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=amd64
|
||||
|
||||
# 先复制依赖文件,利用 Docker 层缓存
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# 复制源码
|
||||
COPY . .
|
||||
|
||||
# 构建应用(根据项目需求修改)
|
||||
RUN go build -o app \
|
||||
-ldflags '-s -w -X main.GitTag=dev' \
|
||||
.
|
||||
|
||||
# ============================================
|
||||
# 运行阶段
|
||||
# ============================================
|
||||
FROM alpine:3.21
|
||||
|
||||
# 安装运行时依赖
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk add --no-cache tzdata wget netcat-openbsd && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 从构建阶段复制二进制文件
|
||||
COPY --from=builder /build/app .
|
||||
COPY --from=builder /build/docker-healthcheck.sh .
|
||||
|
||||
RUN chmod +x app docker-healthcheck.sh
|
||||
|
||||
# 暴露端口(根据实际服务修改)
|
||||
EXPOSE 8080
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD ./docker-healthcheck.sh
|
||||
|
||||
CMD ["./app"]
|
||||
```
|
||||
|
||||
**使用说明**:
|
||||
1. 将构建命令修改为项目实际的构建命令
|
||||
2. 调整 ldflags 参数(版本号注入、符号表去除等)
|
||||
3. 修改端口号
|
||||
|
||||
### 3. 代码生成支持版(Dockerfile.codegen)
|
||||
|
||||
**适用场景**:需要在容器中生成代码(如 Ent、Wire、oapi-codegen)。
|
||||
|
||||
```dockerfile
|
||||
# ============================================
|
||||
# 构建阶段
|
||||
# ============================================
|
||||
FROM golang:1.25-alpine AS builder
|
||||
|
||||
# 安装构建工具
|
||||
RUN apk add --no-cache git make
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
ENV CGO_ENABLED=0
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=amd64
|
||||
|
||||
# 复制依赖文件
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# 安装代码生成工具(根据项目需求选择)
|
||||
RUN go install entgo.io/ent/cmd/ent@latest && \
|
||||
go install github.com/google/wire/cmd/wire@latest && \
|
||||
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest && \
|
||||
go install golang.org/x/tools/cmd/stringer@latest
|
||||
|
||||
# 复制源码
|
||||
COPY . .
|
||||
|
||||
# 代码生成(根据项目需求修改)
|
||||
RUN go generate ./...
|
||||
# 或使用 go tool 调用
|
||||
# RUN go tool ent generate ./ent/schema
|
||||
# RUN go tool wire ./...
|
||||
# RUN go tool oapi-codegen -config oapi.yaml api.yaml
|
||||
|
||||
# 测试(可选)
|
||||
RUN go test ./...
|
||||
RUN go vet ./...
|
||||
|
||||
# 构建
|
||||
RUN go build -o app \
|
||||
-ldflags '-s -w' \
|
||||
.
|
||||
|
||||
# ============================================
|
||||
# 运行阶段
|
||||
# ============================================
|
||||
FROM alpine:3.21
|
||||
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk add --no-cache tzdata wget netcat-openbsd && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /build/app .
|
||||
COPY --from=builder /build/docker-healthcheck.sh .
|
||||
|
||||
RUN chmod +x app docker-healthcheck.sh
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD ./docker-healthcheck.sh
|
||||
|
||||
CMD ["./app"]
|
||||
```
|
||||
|
||||
## 健康检查脚本
|
||||
|
||||
### docker-healthcheck.sh(基础版)
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
# Docker 健康检查脚本
|
||||
|
||||
# 检查应用端口是否在监听
|
||||
if nc -z localhost 8080 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit 1
|
||||
```
|
||||
|
||||
### docker-healthcheck.sh(HTTP 端点版)
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
# Docker 健康检查脚本
|
||||
# 检查 HTTP 端点是否可访问
|
||||
|
||||
# 使用 /health 或 /metrics 端点
|
||||
if wget --spider --quiet --timeout=5 http://localhost:8080/health 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 备用:检查端口是否在监听
|
||||
if nc -z localhost 8080 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit 1
|
||||
```
|
||||
|
||||
### docker-healthcheck.sh(多端口版)
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
# Docker 健康检查脚本
|
||||
# 检查多个端口(适用于多个 API 服务)
|
||||
|
||||
# 检查端口 2020 (Platform API)
|
||||
if ! nc -z localhost 2020 2>/dev/null; then
|
||||
echo "Port 2020 is not responding"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查端口 2021 (WxMP API)
|
||||
if ! nc -z localhost 2021 2>/dev/null; then
|
||||
echo "Port 2021 is not responding"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 或使用 HTTP 端点
|
||||
# if ! wget --spider --quiet --timeout=5 http://localhost:2020/metrics 2>/dev/null; then
|
||||
# exit 1
|
||||
# fi
|
||||
|
||||
exit 0
|
||||
```
|
||||
|
||||
## 高级配置
|
||||
|
||||
### 环境变量配置
|
||||
|
||||
```dockerfile
|
||||
# 在 Dockerfile 中设置默认环境变量
|
||||
ENV MODE=production
|
||||
ENV LOG_LEVEL=info
|
||||
ENV GIN_MODE=release
|
||||
|
||||
# 运行时可覆盖
|
||||
# docker run -e MODE=test -e LOG_LEVEL=debug your-image
|
||||
```
|
||||
|
||||
### 配置文件挂载
|
||||
|
||||
```dockerfile
|
||||
# 创建配置目录
|
||||
RUN mkdir -p /app/configs
|
||||
|
||||
# 运行时挂载配置文件
|
||||
# docker run -v ./configs:/app/configs your-image
|
||||
```
|
||||
|
||||
### 非 root 用户运行
|
||||
|
||||
```dockerfile
|
||||
# 创建非特权用户
|
||||
RUN addgroup -g 1000 appuser && \
|
||||
adduser -D -u 1000 -G appuser appuser
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 复制文件
|
||||
COPY --from=builder --chown=appuser:appuser /build/app .
|
||||
|
||||
# 切换用户
|
||||
USER appuser
|
||||
|
||||
CMD ["./app"]
|
||||
```
|
||||
|
||||
### 多阶段构建优化
|
||||
|
||||
```dockerfile
|
||||
# ============================================
|
||||
# 依赖下载阶段(缓存 go.mod)
|
||||
# ============================================
|
||||
FROM golang:1.25-alpine AS deps
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# ============================================
|
||||
# 构建阶段
|
||||
# ============================================
|
||||
FROM golang:1.25-alpine AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# 从依赖阶段复制缓存
|
||||
COPY --from=deps /go/pkg /go/pkg
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=amd64
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN go build -o app -ldflags '-s -w' .
|
||||
|
||||
# ============================================
|
||||
# 运行阶段
|
||||
# ============================================
|
||||
FROM alpine:3.21
|
||||
|
||||
# ... 省略后续步骤
|
||||
```
|
||||
|
||||
## 镜像优化技巧
|
||||
|
||||
### 1. 减小镜像体积
|
||||
|
||||
```dockerfile
|
||||
# 使用 Alpine 基础镜像
|
||||
FROM alpine:3.21
|
||||
|
||||
# 去除符号表和调试信息
|
||||
RUN go build -ldflags '-s -w' -o app
|
||||
|
||||
# 使用 upx 压缩(可选,启动时间会变长)
|
||||
RUN apk add --no-cache upx && \
|
||||
upx --best --lzma app && \
|
||||
apk del upx
|
||||
```
|
||||
|
||||
### 2. 利用构建缓存
|
||||
|
||||
```dockerfile
|
||||
# 先复制 go.mod 和 go.sum,利用依赖缓存
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# 再复制源码(源码变化频繁)
|
||||
COPY . .
|
||||
```
|
||||
|
||||
### 3. 合并 RUN 命令
|
||||
|
||||
```dockerfile
|
||||
# 合并多个 RUN 命令减少层数
|
||||
RUN apk add --no-cache tzdata wget netcat-openbsd && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
|
||||
addgroup -g 1000 appuser
|
||||
```
|
||||
|
||||
### 4. 使用 .dockerignore
|
||||
|
||||
```
|
||||
# .dockerignore
|
||||
.git/
|
||||
.gitignore
|
||||
*.md
|
||||
docs/
|
||||
tests/
|
||||
.github/
|
||||
.gitea/
|
||||
Dockerfile*
|
||||
docker-compose.yml
|
||||
*.log
|
||||
tmp/
|
||||
vendor/
|
||||
```
|
||||
|
||||
## 构建命令示例
|
||||
|
||||
### 本地构建
|
||||
|
||||
```bash
|
||||
# 基础构建
|
||||
docker build -t your-service:latest .
|
||||
|
||||
# 指定 Dockerfile
|
||||
docker build -f Dockerfile.ci -t your-service:latest .
|
||||
|
||||
# 传递构建参数
|
||||
docker build --build-arg GIT_TAG=v1.0.0 -t your-service:1.0.0 .
|
||||
|
||||
# 查看构建过程
|
||||
docker build --progress=plain -t your-service:latest .
|
||||
```
|
||||
|
||||
### CI/CD 构建
|
||||
|
||||
```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 \
|
||||
.
|
||||
```
|
||||
|
||||
## 运行容器示例
|
||||
|
||||
```bash
|
||||
# 基础运行
|
||||
docker run -d -p 8080:8080 your-service:latest
|
||||
|
||||
# 挂载配置文件
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
-v ./configs:/app/configs \
|
||||
-v ./logs:/app/logs \
|
||||
your-service:latest
|
||||
|
||||
# 设置环境变量
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
-e MODE=production \
|
||||
-e DATABASE_URL=postgres://... \
|
||||
your-service:latest
|
||||
|
||||
# 查看日志
|
||||
docker logs -f <container-id>
|
||||
|
||||
# 进入容器调试
|
||||
docker exec -it <container-id> /bin/sh
|
||||
```
|
||||
|
||||
## 安全建议
|
||||
|
||||
### 1. 使用特定版本标签
|
||||
|
||||
```dockerfile
|
||||
# 不推荐:使用 latest
|
||||
FROM alpine:latest
|
||||
|
||||
# 推荐:使用特定版本
|
||||
FROM alpine:3.21
|
||||
```
|
||||
|
||||
### 2. 定期更新依赖
|
||||
|
||||
```bash
|
||||
# 更新 Go 模块
|
||||
go get -u ./...
|
||||
go mod tidy
|
||||
|
||||
# 更新基础镜像
|
||||
docker pull alpine:3.21
|
||||
```
|
||||
|
||||
### 3. 扫描漏洞
|
||||
|
||||
```bash
|
||||
# 使用 Trivy 扫描
|
||||
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
aquasec/trivy image your-service:latest
|
||||
```
|
||||
|
||||
### 4. 最小权限原则
|
||||
|
||||
```dockerfile
|
||||
# 使用非 root 用户
|
||||
USER appuser
|
||||
|
||||
# 只读文件系统(如果适用)
|
||||
# docker run --read-only your-service
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 时区不正确
|
||||
|
||||
**原因**: 容器默认使用 UTC 时区
|
||||
|
||||
**解决方案**:
|
||||
```dockerfile
|
||||
RUN apk add --no-cache tzdata && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
```
|
||||
|
||||
### Q2: 网络连接超时
|
||||
|
||||
**原因**: DNS 解析问题或网络配置
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 运行时指定 DNS
|
||||
docker run --dns 8.8.8.8 your-service
|
||||
|
||||
# 或在 Dockerfile 中配置
|
||||
RUN echo 'nameserver 8.8.8.8' > /etc/resolv.conf
|
||||
```
|
||||
|
||||
### Q3: CGO 依赖问题
|
||||
|
||||
**错误信息**: `binary was compiled with 'CGO_ENABLED=1'`
|
||||
|
||||
**解决方案**:
|
||||
```dockerfile
|
||||
# 禁用 CGO
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
# 或安装 gcc
|
||||
RUN apk add --no-cache gcc musl-dev
|
||||
```
|
||||
|
||||
### Q4: 静态链接失败
|
||||
|
||||
**错误信息**: `dynamic executable`
|
||||
|
||||
**解决方案**:
|
||||
```dockerfile
|
||||
# 确保 CGO_ENABLED=0
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
# 或使用 musl 交叉编译
|
||||
RUN apk add --no-cache musl-dev
|
||||
RUN go build -ldflags '-linkmode external -extldflags "-static"' -o app
|
||||
```
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [Go 官方 Docker 指南](https://docs.docker.com/language/golang/)
|
||||
- [Alpine Linux 包搜索](https://pkgs.alpinelinux.org/packages)
|
||||
- [Docker 多阶段构建文档](https://docs.docker.com/build/building/multi-stage/)
|
||||
- [Go 编译器标志](https://pkg.go.dev/cmd/go)
|
||||
631
skill/gitea/dockerfile-templates/nodejs-frontend.md
Normal file
631
skill/gitea/dockerfile-templates/nodejs-frontend.md
Normal file
@@ -0,0 +1,631 @@
|
||||
# Node.js 前端 Dockerfile 模板
|
||||
|
||||
Node.js 前端项目的 Docker 容器化模板,使用 Nginx 提供静态文件服务。
|
||||
|
||||
## 模板类型
|
||||
|
||||
### 1. CI 构建镜像(Dockerfile.ci)
|
||||
|
||||
**适用场景**:在 CI/CD 中使用,静态文件已在外部构建完成。
|
||||
|
||||
**优点**:
|
||||
- 镜像体积最小(~20MB)
|
||||
- 构建速度快
|
||||
- 适合生产环境
|
||||
|
||||
```dockerfile
|
||||
# CI 构建专用 Dockerfile
|
||||
# 将不常变化的层放在前面,最大化利用缓存
|
||||
# 使用固定版本避免 latest 导致的缓存失效和不确定性
|
||||
|
||||
FROM nginx:1.28.0-alpine
|
||||
|
||||
# 基础设置层 - 很少变化,可以长期缓存
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk add --no-cache tzdata && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
# Nginx 配置文件 - 配置 SPA 路由处理
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# 应用静态文件 - 每次构建都变化,放在最后
|
||||
COPY dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
**使用说明**:
|
||||
1. 创建 `nginx.conf` 配置文件
|
||||
2. 在 CI workflow 中先构建前端(生成 dist 目录),再构建镜像
|
||||
3. 根据实际需求修改 Nginx 配置
|
||||
|
||||
### 2. 完整构建镜像(Dockerfile)
|
||||
|
||||
**适用场景**:本地开发、无 CI 环境、独立构建。
|
||||
|
||||
**优点**:
|
||||
- 自包含构建流程
|
||||
- 可在任何环境构建
|
||||
- 利用 Docker 缓存加速
|
||||
|
||||
```dockerfile
|
||||
# ============================================
|
||||
# 构建阶段
|
||||
# ============================================
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
# 安装构建依赖
|
||||
RUN apk add --no-cache git
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# 设置 npm 镜像源(国内加速)
|
||||
RUN npm config set registry https://registry.npmmirror.com
|
||||
|
||||
# 安装 pnpm
|
||||
RUN npm install -g pnpm@latest-10
|
||||
|
||||
# 先复制依赖文件,利用 Docker 层缓存
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# 复制源码
|
||||
COPY . .
|
||||
|
||||
# 构建应用
|
||||
# 根据项目使用的构建工具修改命令
|
||||
RUN pnpm run build
|
||||
|
||||
# ============================================
|
||||
# 运行阶段
|
||||
# ============================================
|
||||
FROM nginx:1.28.0-alpine
|
||||
|
||||
# 安装运行时依赖
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk add --no-cache tzdata && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
# 复制 Nginx 配置
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# 从构建阶段复制静态文件
|
||||
COPY --from=builder /build/dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
**使用说明**:
|
||||
1. 根据项目使用 npm、yarn 或 pnpm 修改安装命令
|
||||
2. 根据构建工具(Vite、Webpack、Next.js 等)修改构建命令和输出目录
|
||||
3. 调整 Nginx 配置
|
||||
|
||||
### 3. 多环境构建版(Dockerfile.multienv)
|
||||
|
||||
**适用场景**:需要根据不同环境(dev/test/prod)构建不同配置。
|
||||
|
||||
```dockerfile
|
||||
# ============================================
|
||||
# 构建阶段
|
||||
# ============================================
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
ARG BUILD_ENV=production
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
RUN npm config set registry https://registry.npmmirror.com && \
|
||||
npm install -g pnpm@latest-10
|
||||
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
|
||||
# 根据 BUILD_ENV 设置不同的环境变量
|
||||
ENV NODE_ENV=${BUILD_ENV}
|
||||
ENV VITE_APP_ENV=${BUILD_ENV}
|
||||
|
||||
RUN pnpm run build
|
||||
|
||||
# ============================================
|
||||
# 运行阶段
|
||||
# ============================================
|
||||
FROM nginx:1.28.0-alpine
|
||||
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk add --no-cache tzdata && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=builder /build/dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
**构建命令**:
|
||||
```bash
|
||||
# 生产环境
|
||||
docker build --build-arg BUILD_ENV=production -t app:prod .
|
||||
|
||||
# 测试环境
|
||||
docker build --build-arg BUILD_ENV=test -t app:test .
|
||||
|
||||
# 开发环境
|
||||
docker build --build-arg BUILD_ENV=development -t app:dev .
|
||||
```
|
||||
|
||||
## Nginx 配置模板
|
||||
|
||||
### nginx.conf(基础 SPA 配置)
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# 启用 gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/x-javascript application/xml+rss
|
||||
application/json application/javascript;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# SPA 路由处理:所有请求都返回 index.html
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 健康检查端点
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### nginx.conf(带 API 代理)
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
client_max_body_size 30M;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# 启用 gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/x-javascript application/xml+rss
|
||||
application/json application/javascript;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# SPA 路由处理
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# API 代理(根据实际后端服务修改)
|
||||
location /api/ {
|
||||
proxy_pass http://backend-service:8080/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host:$server_port;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# 健康检查端点
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### nginx.conf(完整生产配置)
|
||||
|
||||
```nginx
|
||||
# SPA 应用 Nginx 配置
|
||||
# 所有路由都返回 index.html,由前端路由处理
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
client_max_body_size 30M;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# 启用 gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/x-javascript application/xml+rss
|
||||
application/json application/javascript;
|
||||
|
||||
# 静态资源缓存(带版本号的文件可以长期缓存)
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# HTML 文件不缓存(确保用户总是获取最新版本)
|
||||
location ~* \.html$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
# SPA 路由处理:所有请求都返回 index.html
|
||||
location / {
|
||||
# 用于配合 browserHistory 使用
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# API 代理:平台 API
|
||||
location /platform/api/ {
|
||||
proxy_pass http://backend-service:2020/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host:$server_port;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# API 代理:微信小程序 API
|
||||
location /wxmp/api/ {
|
||||
proxy_pass http://backend-service:2021/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host:$server_port;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# 第三方服务代理(如高德地图)
|
||||
location /_AMapService/ {
|
||||
set $args "$args&jscode=YOUR_AMAP_KEY";
|
||||
proxy_pass https://restapi.amap.com/;
|
||||
}
|
||||
|
||||
# 错误页面
|
||||
error_page 404 /404.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
# 健康检查端点
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 高级配置
|
||||
|
||||
### 支持 HTTPS
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name example.com;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# ... 其他配置
|
||||
}
|
||||
```
|
||||
|
||||
### 防盗链
|
||||
|
||||
```nginx
|
||||
location ~* \.(jpg|jpeg|png|gif|svg)$ {
|
||||
valid_referers none blocked example.com *.example.com;
|
||||
if ($invalid_referer) {
|
||||
return 403;
|
||||
}
|
||||
expires 1y;
|
||||
}
|
||||
```
|
||||
|
||||
### 限流
|
||||
|
||||
```nginx
|
||||
# 在 http 块中定义限流区域
|
||||
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
|
||||
|
||||
# 在 server 块中应用
|
||||
location / {
|
||||
limit_req zone=one burst=20 nodelay;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
```
|
||||
|
||||
### 安全头
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
# 防止点击劫持
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
|
||||
# 防止 MIME 类型嗅探
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
|
||||
# 启用 XSS 保护
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# CSP 策略
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;
|
||||
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
```
|
||||
|
||||
## 镜像优化技巧
|
||||
|
||||
### 1. 使用多阶段构建
|
||||
|
||||
```dockerfile
|
||||
# 分离构建和运行环境,只保留必要文件
|
||||
FROM node:22-alpine AS builder
|
||||
# ... 构建步骤
|
||||
|
||||
FROM nginx:1.28.0-alpine
|
||||
# 只复制构建产物
|
||||
COPY --from=builder /build/dist /usr/share/nginx/html
|
||||
```
|
||||
|
||||
### 2. 利用构建缓存
|
||||
|
||||
```dockerfile
|
||||
# 先复制依赖文件
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install
|
||||
|
||||
# 再复制源码(源码变化频繁)
|
||||
COPY . .
|
||||
```
|
||||
|
||||
### 3. 使用 .dockerignore
|
||||
|
||||
```
|
||||
# .dockerignore
|
||||
node_modules/
|
||||
.git/
|
||||
.gitignore
|
||||
*.md
|
||||
docs/
|
||||
tests/
|
||||
.github/
|
||||
.gitea/
|
||||
Dockerfile*
|
||||
docker-compose.yml
|
||||
.env*
|
||||
dist/
|
||||
build/
|
||||
coverage/
|
||||
.vscode/
|
||||
.idea/
|
||||
```
|
||||
|
||||
### 4. 优化 Nginx 配置
|
||||
|
||||
```nginx
|
||||
# 启用 sendfile
|
||||
sendfile on;
|
||||
|
||||
# 启用 tcp_nopush
|
||||
tcp_nopush on;
|
||||
|
||||
# 启用 tcp_nodelay
|
||||
tcp_nodelay on;
|
||||
|
||||
# 设置 keepalive 超时
|
||||
keepalive_timeout 65;
|
||||
|
||||
# 禁用访问日志(生产环境可选)
|
||||
access_log off;
|
||||
```
|
||||
|
||||
## 构建命令示例
|
||||
|
||||
### 本地构建
|
||||
|
||||
```bash
|
||||
# 基础构建
|
||||
docker build -t frontend:latest .
|
||||
|
||||
# 指定 Dockerfile
|
||||
docker build -f Dockerfile.ci -t frontend:latest .
|
||||
|
||||
# 传递构建参数
|
||||
docker build --build-arg BUILD_ENV=production -t frontend:1.0.0 .
|
||||
```
|
||||
|
||||
### CI/CD 构建
|
||||
|
||||
```bash
|
||||
# 使用 BuildKit 缓存
|
||||
export DOCKER_BUILDKIT=1
|
||||
|
||||
# 使用注册表缓存
|
||||
docker build \
|
||||
--cache-from=type=registry,ref=frontend:buildcache \
|
||||
--cache-to=type=registry,ref=frontend:buildcache,mode=max \
|
||||
-t frontend:latest \
|
||||
.
|
||||
```
|
||||
|
||||
## 运行容器示例
|
||||
|
||||
```bash
|
||||
# 基础运行
|
||||
docker run -d -p 80:80 frontend:latest
|
||||
|
||||
# 挂载自定义 Nginx 配置
|
||||
docker run -d \
|
||||
-p 80:80 \
|
||||
-v ./nginx.conf:/etc/nginx/conf.d/default.conf \
|
||||
frontend:latest
|
||||
|
||||
# 设置环境变量(如果 Nginx 配置需要)
|
||||
docker run -d \
|
||||
-p 80:80 \
|
||||
-e BACKEND_HOST=api.example.com \
|
||||
frontend:latest
|
||||
|
||||
# 查看日志
|
||||
docker logs -f <container-id>
|
||||
|
||||
# 进入容器调试
|
||||
docker exec -it <container-id> /bin/sh
|
||||
```
|
||||
|
||||
## Docker Compose 示例
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
frontend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
depends_on:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
backend:
|
||||
image: backend-service:latest
|
||||
ports:
|
||||
- "8080:8080"
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: SPA 路由 404 错误
|
||||
|
||||
**原因**: Nginx 找不到对应的文件
|
||||
|
||||
**解决方案**:
|
||||
```nginx
|
||||
# 配置 try_files,所有路由返回 index.html
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
```
|
||||
|
||||
### Q2: API 代理跨域问题
|
||||
|
||||
**原因**: CORS 配置不正确
|
||||
|
||||
**解决方案**:
|
||||
```nginx
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8080/;
|
||||
|
||||
# 添加 CORS 头
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Q3: 静态资源缓存问题
|
||||
|
||||
**原因**: 浏览器缓存了旧版本
|
||||
|
||||
**解决方案**:
|
||||
```nginx
|
||||
# HTML 文件不缓存
|
||||
location ~* \.html$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
# JS/CSS 使用版本号或哈希,可以长期缓存
|
||||
location ~* \.(js|css)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
```
|
||||
|
||||
### Q4: 容器启动后立即退出
|
||||
|
||||
**原因**: Nginx 配置文件语法错误
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 测试配置文件
|
||||
docker run --rm -v ./nginx.conf:/etc/nginx/conf.d/default.conf \
|
||||
nginx:1.28.0-alpine nginx -t
|
||||
|
||||
# 查看容器日志
|
||||
docker logs <container-id>
|
||||
```
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [Node.js 官方 Docker 指南](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/)
|
||||
- [Nginx 官方文档](https://nginx.org/en/docs/)
|
||||
- [Docker 多阶段构建文档](https://docs.docker.com/build/building/multi-stage/)
|
||||
- [前端构建工具文档](https://vitejs.dev/guide/)
|
||||
571
skill/gitea/dockerfile-templates/rust-service.md
Normal file
571
skill/gitea/dockerfile-templates/rust-service.md
Normal file
@@ -0,0 +1,571 @@
|
||||
# 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)
|
||||
443
skill/gitea/rust-quick-reference.md
Normal file
443
skill/gitea/rust-quick-reference.md
Normal file
@@ -0,0 +1,443 @@
|
||||
# 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)
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user